diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..d1c458c04 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,33 @@ +--- +name: Pull request +about: Push a change to this project +--- + +### Motivate of the pull request +- [ ] To address an existing issue. If so, please provide a link to the issue. +- [ ] Breaking new feature. If so, please decribe details in the description part. + +### Describe the technical details +- What is currently done? (Provide issue link if applicable) +- What does this pull request change? + +### Which part of the code base require a change +**In general, modification on existing submodules are not acceptable. You should push changes to upstream.** +- [ ] VPR +- [ ] OpenFPGA libraries +- [ ] FPGA-Verilog +- [ ] FPGA-Bitstream +- [ ] FPGA-SDC +- [ ] FPGA-SPICE +- [ ] Flow scripts +- [ ] Architecture library +- [ ] Cell library + +### Checklist of the pull request +- [ ] Require code changes. +- [ ] Require new tests to be added +- [ ] Require an update on documentation + +### Impact of the pull request +- [ ] Require a change on Quality of Results (QoR) +- [ ] Break back-compatibility. If so, please list who may be influenced. diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 000000000..d1c458c04 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,33 @@ +--- +name: Pull request +about: Push a change to this project +--- + +### Motivate of the pull request +- [ ] To address an existing issue. If so, please provide a link to the issue. +- [ ] Breaking new feature. If so, please decribe details in the description part. + +### Describe the technical details +- What is currently done? (Provide issue link if applicable) +- What does this pull request change? + +### Which part of the code base require a change +**In general, modification on existing submodules are not acceptable. You should push changes to upstream.** +- [ ] VPR +- [ ] OpenFPGA libraries +- [ ] FPGA-Verilog +- [ ] FPGA-Bitstream +- [ ] FPGA-SDC +- [ ] FPGA-SPICE +- [ ] Flow scripts +- [ ] Architecture library +- [ ] Cell library + +### Checklist of the pull request +- [ ] Require code changes. +- [ ] Require new tests to be added +- [ ] Require an update on documentation + +### Impact of the pull request +- [ ] Require a change on Quality of Results (QoR) +- [ ] Break back-compatibility. If so, please list who may be influenced. diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..f2a30f198 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,103 @@ +# See https://github.com/actions/labeler#common-examples for defining patterns. +# The globs use "minimatch" syntax found at https://github.com/isaacs/minimatch +# +# WARNING: Due to this file being yaml, any string starting with `*` must be +# wrapped in quotes. + +# Third-party tools +ABC: + - abc/* + - abc/**/* +ACE2: + - ace2/* + - ace2/**/* +VPR: + - vpr/* + - vpr/**/* + - libs/**/* + +# General areas +documentation: + - docs/* + - docs/**/* + - "*README*" + - "*.md" + - tutorial + - "*.rst" + - ".readthedocs.yml" +github: + - .github/* + - .github/**/* +docker: + - Dockerfile + - "*docker*" +build: + - Makefile + - "*.make" + - CMakeLists.txt + - cmake +libopenfpga: + - "libopenfpga/**" +libopenfpga-bitstream: + - "libopenfpga/libfpgabitstream/**" +libopenfpga-arch-parser: + - "libopenfpga/libarchopenfpga/**" +libopenfpga-fabric-key: + - "libopenfpga/libfabrickey/**" +libopenfpga-shell: + - "libopenfpga/libopenfpgashell/**" +libopenfpga-utils: + - "libopenfpga/libopenfpgautil/**" +openfpga-tools: + - "openfpga/**" +openfpga-verilog: + - "openfpga/*/fpga_verilog/**" +openfpga-sdc: + - "openfpga/*/fpga_sdc/**" +openfpga-bitstream: + - "openfpga/*/fpga_bitstream/**" +openfpga-spice: + - "openfpga/*/fpga_spice/**" +flow-scripts: + - "openfpga_flow/scripts/**" + - "openfpga_flow/openfpga_shell_scripts/**" + - "openfpga_flow/openfpga_simulation_settings/**" + - "openfpga_flow/misc/**" +architecture-description: + - "openfpga_flow/vpr_arch/**" + - "openfpga_flow/openfpga_arch/**" + - "openfpga_flow/fabric_keys/**" +bitstream: + - "openfpga_flow/fabric_keys/**" +cell-library: + - "openfpga_flow/openfpga_cell_library/**" + - "openfpga_flow/tech/**" +benchmarks: + - "openfpga_flow/benchmarks/**" +tests: + - "openfpga_flow/tasks/**" + +# Tag pull requests with the languages used to make it easy to see what is +# being used. +lang-hdl: + - "*.v" + - "*.sv" +lang-cpp: + - "*.c*" + - "*.h" +lang-perl: + - "*.pl" + - "*perl*" +lang-python: + - "*.py" +lang-shell: + - "*.sh" +lang-netlist: + - "*.blif" + - "*.eblif" + - "*.edif" + - "*.vqm" +lang-make: + - "*.make" + - Makefile + - CMakeLists.txt \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2a698695e..d9d057562 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -122,6 +122,8 @@ jobs: steps: - name: Checkout OpenFPGA repo uses: actions/checkout@v2 + with: + submodules: true - name: Install dependency run: source ./.github/workflows/install_dependency.sh diff --git a/.github/workflows/install_dependency.sh b/.github/workflows/install_dependency.sh index c4f70c29f..b20184fea 100644 --- a/.github/workflows/install_dependency.sh +++ b/.github/workflows/install_dependency.sh @@ -28,6 +28,8 @@ sudo apt-get install perl sudo apt-get install python sudo apt-get install python3-setuptools sudo apt-get install python-lxml +sudo apt-get install tcllib +sudo apt-get install tcl8.6-dev sudo apt-get install texinfo sudo apt-get install time sudo apt-get install valgrind diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000..20a5e480d --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,12 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@main + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: ".github/labeler.yml" diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..1fb1d4212 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "yosys"] + path = yosys + url = https://github.com/QuickLogic-Corp/yosys.git + branch = quicklogic-rebased diff --git a/CMakeLists.txt b/CMakeLists.txt index de41f3ca2..49b2fa1fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,12 +185,60 @@ endif() #add_subdirectory(iverilog) add_subdirectory(libs) add_subdirectory(libopenfpga) -add_subdirectory(yosys) +#add_subdirectory(yosys) add_subdirectory(abc) add_subdirectory(ace2) add_subdirectory(vpr) add_subdirectory(openfpga) +# yosys compilation starts + +# Compilation options for yosys +include(CMakeParseArguments) + +##project(yosys) + +# Options to enable/disable dependencies +option(YOSYS_ENABLE_TCL, "Enable TCL parser integrated in yosys" ON) +option(YOSYS_ENABLE_ABC, "Enable ABC library integrated in yosys" ON) +option(YOSYS_ENABLE_PLUGINS, "Enable plug-in in yosys" ON) +option(YOSYS_ENABLE_READLINE, "Enable readline library in yosys" ON) +option(YOSYS_ENABLE_VERIFIC, "Enable verification library in yosys" OFF) +option(YOSYS_ENABLE_COVER, "Enable coverage test in yosys" ON) +option(YOSYS_ENABLE_LIBYOSYS, "Enable static library compiled yosys" OFF) +option(YOSYS_ENABLE_GPROF, "Enable profiling in compiled yosys" OFF) +option(YOSYS_ENABLE_NDEBUG, "Enable non-debugging feature in compiled yosys" OFF) + +# +## Search and link dependent packages +## We need readline to compile +if (YOSYS_ENABLE_READLINE) + find_package(Readline REQUIRED) +endif() + +# +######################### +## # +## Compiler Flags Setup # +## # +######################### +# +## Compiler flag configuration checks +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) +# + +# run makefile provided, we pass-on the options to the local make file +add_custom_target( + yosys ALL + COMMAND $(MAKE) config-gcc + COMMAND $(MAKE) + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/yosys + COMMENT "Compile Yosys with given Makefile" +) + +# yosys compilation ends + # run make to extract compiler options, linker options and list of source files #add_custom_target( # yosys diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..d8b91a791 --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +# Makefile + +ifeq ($(origin CMAKE_COMMAND),undefined) +CMAKE_COMMAND := cmake +else +CMAKE_COMMAND := ${CMAKE_COMMAND} +endif + +.PHONY: all checkout compile + +all: checkout + mkdir -p build && cd build && $(CMAKE_COMMAND) ${CMAKE_FLAGS} .. + cd build && $(MAKE) + +checkout: + git submodule init + git submodule update --init --recursive + +compile: + mkdir -p build && cd build && $(CMAKE_COMMAND) ${CMAKE_FLAGS} .. + cd build && $(MAKE) + +clean: + rm -rf build + +build/Makefile: + make checkout + +.PHONY: Makefile + +%: build/Makefile + cd build && $(MAKE) $@ diff --git a/README.md b/README.md index b8803f098..93c7e5fe2 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,7 @@ It also includes detailed information about docker image. ```bash # Clone the repository and go inside it git clone https://github.com/LNIS-Projects/OpenFPGA.git && cd OpenFPGA -mkdir build && cd build # Create a folder named build in the OpenPFGA repository -cmake .. # Create a Makefile in this folder using cmake -make # Compile the tool and its dependencies +make all ``` --- diff --git a/docs/requirements.txt b/docs/requirements.txt index 46beeb9a4..2236fda06 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -6,7 +6,7 @@ #recommonmark #Handle references in bibtex format -sphinxcontrib-bibtex +sphinxcontrib-bibtex<2.0.0 #Work-around bug "AttributeError: 'Values' object has no attribute 'character_level_inline_markup'" with docutils 0.13.1 #See: diff --git a/docs/source/tutorials/compile.rst b/docs/source/tutorials/compile.rst index fc9a25b13..04d92365d 100644 --- a/docs/source/tutorials/compile.rst +++ b/docs/source/tutorials/compile.rst @@ -12,10 +12,7 @@ In general, please follow the steps to compile git clone https://github.com/LNIS-Projects/OpenFPGA.git cd OpenFPGA - mkdir build - cd build - cmake .. - make + make all .. note:: OpenFPGA requires gcc/g++ version >5 diff --git a/yosys b/yosys new file mode 160000 index 000000000..9ac3484a1 --- /dev/null +++ b/yosys @@ -0,0 +1 @@ +Subproject commit 9ac3484a18657ff734bb9a77cbb9827c19558308 diff --git a/yosys/.clang-format b/yosys/.clang-format deleted file mode 100644 index 28d13da25..000000000 --- a/yosys/.clang-format +++ /dev/null @@ -1,13 +0,0 @@ -# Default Linux style -BasedOnStyle: LLVM -IndentWidth: 8 -UseTab: Always -BreakBeforeBraces: Linux -AllowShortIfStatementsOnASingleLine: false -IndentCaseLabels: false - -# From CodingReadme -TabWidth: 8 -ContinuationIndentWidth: 2 -ColumnLimit: 150 -# BreakBeforeBraces: Linux diff --git a/yosys/.dockerignore b/yosys/.dockerignore deleted file mode 100644 index 9910e9954..000000000 --- a/yosys/.dockerignore +++ /dev/null @@ -1,13 +0,0 @@ -.editorconfig -.gitignore -.gitmodules -.github -.git -Dockerfile -README.md -manual -CodingReadme -CodeOfConduct -.travis -.travis.yml - diff --git a/yosys/.editorconfig b/yosys/.editorconfig deleted file mode 100644 index 4d6f5ef7a..000000000 --- a/yosys/.editorconfig +++ /dev/null @@ -1,7 +0,0 @@ -root = true - -[*] -indent_style = tab -indent_size = tab -trim_trailing_whitespace = true -insert_final_newline = true diff --git a/yosys/.github/issue_template.md b/yosys/.github/issue_template.md deleted file mode 100644 index 5a0723c3e..000000000 --- a/yosys/.github/issue_template.md +++ /dev/null @@ -1,24 +0,0 @@ -## Steps to reproduce the issue - -*Provide instructions for reproducing the issue. Make sure to include -all necessary source files. (You can simply drag&drop a .zip file into -the issue editor.)* - -Also, make sure that the issue is actually reproducable in current git -master of Yosys. - -See https://stackoverflow.com/help/mcve for some information on how to -create a Minimal, Complete, and Verifiable example (MCVE). - -Please do not waste our time with issues that lack sufficient information -to reproduce the issue easily. We will simply close those issues. - -Contact https://www.symbioticeda.com/ if you need commercial support for Yosys. - -## Expected behavior - -*Please describe the behavior you would have expected from the tool.* - -## Actual behavior - -*Please describe how the behavior you see differs from the expected behavior.* diff --git a/yosys/.gitignore b/yosys/.gitignore deleted file mode 100644 index 76f53cd06..000000000 --- a/yosys/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -*.o -*.d -.*.swp -*.gch -*.gcda -*.gcno -__pycache__ -/.cproject -/.project -/.settings -/qtcreator.files -/qtcreator.includes -/qtcreator.config -/qtcreator.creator -/qtcreator.creator.user -/coverage.info -/coverage_html -/Makefile.conf -/abc -/viz.js -/yosys -/yosys.exe -/yosys.js -/yosys-abc -/yosys-abc.exe -/yosys-config -/yosys-smtbmc -/yosys-smtbmc.exe -/yosys-smtbmc-script.py -/yosys-filterlib -/yosys-filterlib.exe -/kernel/*.pyh -/kernel/python_wrappers.cc -/kernel/version_*.cc -/share -/yosys-win32-mxebin-* -/yosys-win32-vcxsrc-* -/yosysjs-* -/libyosys.so -/tests/unit/bintest/ -/tests/unit/objtest/ -/tests/ystests diff --git a/yosys/.travis.yml b/yosys/.travis.yml deleted file mode 100644 index c253b2ff7..000000000 --- a/yosys/.travis.yml +++ /dev/null @@ -1,140 +0,0 @@ -sudo: false -language: cpp - -cache: - ccache: true - directories: - - ~/.local-bin - - -env: - global: - - MAKEFLAGS="-j 2" - -matrix: - include: - # Latest gcc-4.8, earliest version supported by Travis - - os: linux - addons: - apt: - packages: - - g++-4.8 - - gperf - - build-essential - - bison - - flex - - libreadline-dev - - gawk - - tcl-dev - - libffi-dev - - git - - graphviz - - xdot - - pkg-config - - python - - python3 - - libboost-system-dev - - libboost-python-dev - - libboost-filesystem-dev - env: - - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8" - - # Latest gcc supported on Travis Linux - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-9 - - gperf - - build-essential - - bison - - flex - - libreadline-dev - - gawk - - tcl-dev - - libffi-dev - - git - - graphviz - - xdot - - pkg-config - - python - - python3 - - libboost-system-dev - - libboost-python-dev - - libboost-filesystem-dev - env: - - MATRIX_EVAL="CONFIG=gcc && CC=gcc-9 && CXX=g++-9" - - # Clang which ships on Trusty Linux - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.8 - packages: - - clang-3.8 - - gperf - - build-essential - - bison - - flex - - libreadline-dev - - gawk - - tcl-dev - - libffi-dev - - git - - graphviz - - xdot - - pkg-config - - python - - python3 - - libboost-system-dev - - libboost-python-dev - - libboost-filesystem-dev - env: - - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8" - - # Latest clang supported by Travis Linux - - os: linux - addons: - apt: - sources: - - llvm-toolchain-xenial-8 - packages: - - clang-8 - - gperf - - build-essential - - bison - - flex - - libreadline-dev - - gawk - - tcl-dev - - libffi-dev - - git - - graphviz - - xdot - - pkg-config - - python - - python3 - - libboost-system-dev - - libboost-python-dev - - libboost-filesystem-dev - env: - - MATRIX_EVAL="CONFIG=clang && CC=clang-8 && CXX=clang++-8" - -# # Latest clang on Mac OS X -# - os: osx -# osx_image: xcode9.4 -# env: -# - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++" - -before_install: - - ./.travis/setup.sh - -script: - - ./.travis/build-and-test.sh - -after_success: - - ./.travis/deploy-after-success.sh diff --git a/yosys/.travis/build-and-test.sh b/yosys/.travis/build-and-test.sh deleted file mode 100755 index b8c35041d..000000000 --- a/yosys/.travis/build-and-test.sh +++ /dev/null @@ -1,51 +0,0 @@ -#! /bin/bash - -set -e - -source .travis/common.sh - -########################################################################## - -echo -echo 'Configuring...' && echo -en 'travis_fold:start:script.configure\\r' -echo - -if [ "$CONFIG" = "gcc" ]; then - echo "Configuring for gcc." - make config-gcc -elif [ "$CONFIG" = "clang" ]; then - echo "Configuring for clang." - make config-clang -fi - -echo -echo -en 'travis_fold:end:script.configure\\r' -echo - -########################################################################## - -echo -echo 'Building...' && echo -en 'travis_fold:start:script.build\\r' -echo - -make - -echo -echo -en 'travis_fold:end:script.build\\r' -echo - -########################################################################## - -./yosys tests/simple/fiedler-cooley.v - -echo -echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r' -echo - -make test - -echo -echo -en 'travis_fold:end:script.test\\r' -echo - -########################################################################## diff --git a/yosys/.travis/common.sh b/yosys/.travis/common.sh deleted file mode 100644 index 8eecc4c09..000000000 --- a/yosys/.travis/common.sh +++ /dev/null @@ -1,15 +0,0 @@ -#! /bin/bash - -# Setup the CC / CXX from the matrix config -eval "${MATRIX_EVAL}" - -# Look for location binaries first -export PATH="$HOME/.local-bin/bin:$PATH" - -# OS X specific common setup -if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - export PATH="/usr/local/opt/ccache/libexec:$PATH" -fi - -# Parallel builds! -MAKEFLAGS="-j 2" diff --git a/yosys/.travis/deploy-after-success.sh b/yosys/.travis/deploy-after-success.sh deleted file mode 100755 index d64e95244..000000000 --- a/yosys/.travis/deploy-after-success.sh +++ /dev/null @@ -1,6 +0,0 @@ -#! /bin/bash - -set -x -set -e - -# FIXME: Upload the build results somewhere... diff --git a/yosys/.travis/setup.sh b/yosys/.travis/setup.sh deleted file mode 100755 index 02879b974..000000000 --- a/yosys/.travis/setup.sh +++ /dev/null @@ -1,63 +0,0 @@ -#! /bin/bash - -set -e - -source .travis/common.sh - -########################################################################## - -# Output status information. -( - set +e - set -x - git status - git branch -v - git log -n 5 --graph - git log --format=oneline -n 20 --graph -) -echo -echo -en 'travis_fold:end:before_install.git\\r' -echo - -########################################################################## - -# Mac OS X specific setup. -if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - ( - echo - echo 'Setting up brew...' && echo -en 'travis_fold:start:before_install.brew\\r' - echo - brew update - brew tap Homebrew/bundle - brew bundle - brew install ccache - echo - echo -en 'travis_fold:end:before_install.brew\\r' - echo - ) -fi - -########################################################################## - -# Install iverilog -( - if [ ! -e ~/.local-bin/bin/iverilog ]; then - echo - echo 'Building iverilog...' && echo -en 'travis_fold:start:before_install.iverilog\\r' - echo - mkdir -p ~/.local-src - mkdir -p ~/.local-bin - cd ~/.local-src - git clone git://github.com/steveicarus/iverilog.git - cd iverilog - autoconf - CC=gcc CXX=g++ ./configure --prefix=$HOME/.local-bin - make - make install - echo - echo -en 'travis_fold:end:before_install.iverilog\\r' - echo - fi -) - -########################################################################## diff --git a/yosys/Brewfile b/yosys/Brewfile deleted file mode 100644 index 4ffe50e86..000000000 --- a/yosys/Brewfile +++ /dev/null @@ -1,9 +0,0 @@ -brew "bison" -brew "flex" -brew "gawk" -brew "libffi" -brew "git" -brew "graphviz" -brew "pkg-config" -brew "python3" -brew "tcl-tk" diff --git a/yosys/CHANGELOG b/yosys/CHANGELOG deleted file mode 100644 index afbcffa26..000000000 --- a/yosys/CHANGELOG +++ /dev/null @@ -1,729 +0,0 @@ - -List of major changes and improvements between releases -======================================================= - - -Yosys 0.8 .. Yosys 0.9 --------------------------- - - * Various - - Many bugfixes and small improvements - - Added support for SystemVerilog interfaces and modports - - Added "write_edif -attrprop" - - Added "opt_lut" pass - - Added "gate2lut.v" techmap rule - - Added "rename -src" - - Added "equiv_opt" pass - - Added "flowmap" LUT mapping pass - - Added "rename -wire" to rename cells based on the wires they drive - - Added "bugpoint" for creating minimised testcases - - Added "write_edif -gndvccy" - - "write_verilog" to escape Verilog keywords - - Fixed sign handling of real constants - - "write_verilog" to write initial statement for initial flop state - - Added pmgen pattern matcher generator - - Fixed opt_rmdff handling of $_DFFSR_???_ and $_DLATCHSR_???_ - - Added "setundef -params" to replace undefined cell parameters - - Renamed "yosys -D" to "yosys -U", added "yosys -D" to set Verilog defines - - Fixed handling of defparam when default_nettype is none - - Fixed "wreduce" flipflop handling - - Fixed FIRRTL to Verilog process instance subfield assignment - - Added "write_verilog -siminit" - - Several fixes and improvements for mem2reg memories - - Fixed handling of task output ports in clocked always blocks - - Improved handling of and-with-1 and or-with-0 in "opt_expr" - - Added "read_aiger" frontend - - Added "mutate" pass - - Added "hdlname" attribute - - Added "rename -output" - - Added "read_ilang -lib" - - Improved "proc" full_case detection and handling - - Added "whitebox" and "lib_whitebox" attributes - - Added "read_verilog -nowb", "flatten -wb" and "wbflip" - - Added Python bindings and support for Python plug-ins - - Added "pmux2shiftx" - - Added log_debug framework for reduced default verbosity - - Improved "opt_expr" and "opt_clean" handling of (partially) undriven and/or unused wires - - Added "peepopt" peephole optimisation pass using pmgen - - Added approximate support for SystemVerilog "var" keyword - - Added parsing of "specify" blocks into $specrule and $specify[23] - - Added support for attributes on parameters and localparams - - Added support for parsing attributes on port connections - - Added "wreduce -keepdc" - - Added support for optimising $dffe and $_DFFE_* cells in "opt_rmdff" - - Added Verilog wand/wor wire type support - - Added support for elaboration system tasks - - Added "muxcover -mux{4,8,16}=" - - Added "muxcover -dmux=" - - Added "muxcover -nopartial" - - Added "muxpack" pass - - Added "pmux2shiftx -norange" - - Added support for "~" in filename parsing - - Added "read_verilog -pwires" feature to turn parameters into wires - - Fixed sign extension of unsized constants with 'bx and 'bz MSB - - Fixed genvar to be a signed type - - Added support for attributes on case rules - - Added "upto" and "offset" to JSON frontend and backend - - Several liberty file parser improvements - - Fixed handling of more complex BRAM patterns - - Add "write_aiger -I -O -B" - - * Formal Verification - - Added $changed support to read_verilog - - Added "read_verilog -noassert -noassume -assert-assumes" - - Added btor ops for $mul, $div, $mod and $concat - - Added yosys-smtbmc support for btor witnesses - - Added "supercover" pass - - Fixed $global_clock handling vs autowire - - Added $dffsr support to "async2sync" - - Added "fmcombine" pass - - Added memory init support in "write_btor" - - Added "cutpoint" pass - - Changed "ne" to "neq" in btor2 output - - Added support for SVA "final" keyword - - Added "fmcombine -initeq -anyeq" - - Added timescale and generated-by header to yosys-smtbmc vcd output - - Improved BTOR2 handling of undriven wires - - * Verific support - - Enabled Verific flags vhdl_support_variable_slice and veri_elaborate_top_level_modules_having_interface_ports - - Improved support for asymmetric memories - - Added "verific -chparam" - - Fixed "verific -extnets" for more complex situations - - Added "read -verific" and "read -noverific" - - Added "hierarchy -chparam" - - * New back-ends - - Added initial Anlogic support - - Added initial SmartFusion2 and IGLOO2 support - - * ECP5 support - - Added "synth_ecp5 -nowidelut" - - Added BRAM inference support to "synth_ecp5" - - Added support for transforming Diamond IO and flipflop primitives - - * iCE40 support - - Added "ice40_unlut" pass - - Added "synth_ice40 -relut" - - Added "synth_ice40 -noabc" - - Added "synth_ice40 -dffe_min_ce_use" - - Added DSP inference support using pmgen - - Added support for initialising BRAM primitives from a file - - Added iCE40 Ultra RGB LED driver cells - - * Xilinx support - - Use "write_edif -pvector bra" for Xilinx EDIF files - - Fixes for VPR place and route support with "synth_xilinx" - - Added more cell simulation models - - Added "synth_xilinx -family" - - Added "stat -tech xilinx" to estimate logic cell usage - - Added "synth_xilinx -nocarry" - - Added "synth_xilinx -nowidelut" - - "synth_xilinx" to now infer hard shift registers (-nosrl to disable) - - Added support for mapping RAM32X1D - -Yosys 0.7 .. Yosys 0.8 ----------------------- - - * Various - - Many bugfixes and small improvements - - Strip debug symbols from installed binary - - Replace -ignore_redef with -[no]overwrite in front-ends - - Added write_verilog hex dump support, add -nohex option - - Added "write_verilog -decimal" - - Added "scc -set_attr" - - Added "verilog_defines" command - - Remember defines from one read_verilog to next - - Added support for hierarchical defparam - - Added FIRRTL back-end - - Improved ABC default scripts - - Added "design -reset-vlog" - - Added "yosys -W regex", "yosys -w regex", and "yosys -e regex" - - Added Verilog $rtoi and $itor support - - Added "check -initdrv" - - Added "read_blif -wideports" - - Added support for SystemVerilog "++" and "--" operators - - Added support for SystemVerilog unique, unique0, and priority case - - Added "write_edif" options for edif "flavors" - - Added support for resetall compiler directive - - Added simple C beck-end (bitwise combinatorical only atm) - - Added $_ANDNOT_ and $_ORNOT_ cell types - - Added cell library aliases to "abc -g" - - Added "setundef -anyseq" - - Added "chtype" command - - Added "design -import" - - Added "write_table" command - - Added "read_json" command - - Added "sim" command - - Added "extract_fa" and "extract_reduce" commands - - Added "extract_counter" command - - Added "opt_demorgan" command - - Added support for $size and $bits SystemVerilog functions - - Added "blackbox" command - - Added "ltp" command - - Added support for editline as replacement for readline - - Added warnings for driver-driver conflicts between FFs (and other cells) and constants - - Added "yosys -E" for creating Makefile dependencies files - - Added "synth -noshare" - - Added "memory_nordff" - - Added "setundef -undef -expose -anyconst" - - Added "expose -input" - - Added specify/specparam parser support (simply ignore them) - - Added "write_blif -inames -iattr" - - Added "hierarchy -simcheck" - - Added an option to statically link abc into yosys - - Added protobuf back-end - - Added BLIF parsing support for .conn and .cname - - Added read_verilog error checking for reg/wire/logic misuse - - Added "make coverage" and ENABLE_GCOV build option - - * Changes in Yosys APIs - - Added ConstEval defaultval feature - - Added {get,set}_src_attribute() methods on RTLIL::AttrObject - - Added SigSpec::is_fully_ones() and Const::is_fully_ones() - - Added log_file_warning() and log_file_error() functions - - * Formal Verification - - Added "write_aiger" - - Added "yosys-smtbmc --aig" - - Added "always " to .smtc format - - Added $cover cell type and support for cover properties - - Added $fair/$live cell type and support for liveness properties - - Added smtbmc support for memory vcd dumping - - Added "chformal" command - - Added "write_smt2 -stbv" and "write_smt2 -stdt" - - Fix equiv_simple, old behavior now available with "equiv_simple -short" - - Change to Yices2 as default SMT solver (it is GPL now) - - Added "yosys-smtbmc --presat" (now default in SymbiYosys) - - Added "yosys-smtbmc --smtc-init --smtc-top --noinit" - - Added a brand new "write_btor" command for BTOR2 - - Added clk2fflogic memory support and other improvements - - Added "async memory write" support to write_smt2 - - Simulate clock toggling in yosys-smtbmc VCD output - - Added $allseq/$allconst cells for EA-solving - - Make -nordff the default in "prep" - - Added (* gclk *) attribute - - Added "async2sync" pass for single-clock designs with async resets - - * Verific support - - Many improvements in Verific front-end - - Added proper handling of concurent SVA properties - - Map "const" and "rand const" to $anyseq/$anyconst - - Added "verific -import -flatten" and "verific -import -extnets" - - Added "verific -vlog-incdir -vlog-define -vlog-libdir" - - Remove PSL support (because PSL has been removed in upstream Verific) - - Improve integration with "hierarchy" command design elaboration - - Added YOSYS_NOVERIFIC for running non-verific test cases with verific bin - - Added simpilied "read" command that automatically uses verific if available - - Added "verific -set- .." - - Added "verific -work " - - * New back-ends - - Added initial Coolrunner-II support - - Added initial eASIC support - - Added initial ECP5 support - - * GreenPAK Support - - Added support for GP_DLATCH, GP_SPI, GP_DCMx, GP_COUNTx, etc. - - * iCE40 Support - - Add "synth_ice40 -vpr" - - Add "synth_ice40 -nodffe" - - Add "synth_ice40 -json" - - Add Support for UltraPlus cells - - * MAX10 and Cyclone IV Support - - Added initial version of metacommand "synth_intel". - - Improved write_verilog command to produce VQM netlist for Quartus Prime. - - Added support for MAX10 FPGA family synthesis. - - Added support for Cyclone IV family synthesis. - - Added example of implementation for DE2i-150 board. - - Added example of implementation for MAX10 development kit. - - Added LFSR example from Asic World. - - Added "dffinit -highlow" for mapping to Intel primitives - - -Yosys 0.6 .. Yosys 0.7 ----------------------- - - * Various - - Added "yosys -D" feature - - Added support for installed plugins in $(DATDIR)/plugins/ - - Renamed opt_const to opt_expr - - Renamed opt_share to opt_merge - - Added "prep -flatten" and "synth -flatten" - - Added "prep -auto-top" and "synth -auto-top" - - Using "mfs" and "lutpack" in ABC lut mapping - - Support for abstract modules in chparam - - Cleanup abstract modules at end of "hierarchy -top" - - Added tristate buffer support to iopadmap - - Added opt_expr support for div/mod by power-of-two - - Added "select -assert-min -assert-max " - - Added "attrmvcp" pass - - Added "attrmap" command - - Added "tee +INT -INT" - - Added "zinit" pass - - Added "setparam -type" - - Added "shregmap" pass - - Added "setundef -init" - - Added "nlutmap -assert" - - Added $sop cell type and "abc -sop -I -P " - - Added "dc2" to default ABC scripts - - Added "deminout" - - Added "insbuf" command - - Added "prep -nomem" - - Added "opt_rmdff -keepdc" - - Added "prep -nokeepdc" - - Added initial version of "synth_gowin" - - Added "fsm_expand -full" - - Added support for fsm_encoding="user" - - Many improvements in GreenPAK4 support - - Added black box modules for all Xilinx 7-series lib cells - - Added synth_ice40 support for latches via logic loops - - Fixed ice40_opt lut unmapping, added "ice40_opt -unlut" - - * Build System - - Added ABCEXTERNAL and ABCURL make variables - - Added BINDIR, LIBDIR, and DATDIR make variables - - Added PKG_CONFIG make variable - - Added SEED make variable (for "make test") - - Added YOSYS_VER_STR make variable - - Updated min GCC requirement to GCC 4.8 - - Updated required Bison version to Bison 3.x - - * Internal APIs - - Added ast.h to exported headers - - Added ScriptPass helper class for script-like passes - - Added CellEdgesDatabase API - - * Front-ends and Back-ends - - Added filename glob support to all front-ends - - Added avail (black-box) module params to ilang format - - Added $display %m support - - Added support for $stop Verilog system task - - Added support for SystemVerilog packages - - Fixed procedural assignments to non-unique lvalues, e.g. {y,y} = {a,b} - - Added support for "active high" and "active low" latches in read_blif and write_blif - - Use init value "2" for all uninitialized FFs in BLIF back-end - - Added "read_blif -sop" - - Added "write_blif -noalias" - - Added various write_blif options for VTR support - - write_json: also write module attributes. - - Added "write_verilog -nodec -nostr -defparam" - - Added "read_verilog -norestrict -assume-asserts" - - Added support for bus interfaces to "read_liberty -lib" - - Added liberty parser support for types within cell decls - - Added "write_verilog -renameprefix -v" - - Added "write_edif -nogndvcc" - - * Formal Verification - - Support for hierarchical designs in smt2 back-end - - Yosys-smtbmc: Support for hierarchical VCD dumping - - Added $initstate cell type and vlog function - - Added $anyconst and $anyseq cell types and vlog functions - - Added printing of code loc of failed asserts to yosys-smtbmc - - Added memory_memx pass, "memory -memx", and "prep -memx" - - Added "proc_mux -ifx" - - Added "yosys-smtbmc -g" - - Deprecated "write_smt2 -regs" (by default on now) - - Made "write_smt2 -bv -mem" default, added "write_smt2 -nobv -nomem" - - Added support for memories to smtio.py - - Added "yosys-smtbmc --dump-vlogtb" - - Added "yosys-smtbmc --smtc --dump-smtc" - - Added "yosys-smtbmc --dump-all" - - Added assertpmux command - - Added "yosys-smtbmc --unroll" - - Added $past, $stable, $rose, $fell SVA functions - - Added "yosys-smtbmc --noinfo and --dummy" - - Added "yosys-smtbmc --noincr" - - Added "yosys-smtbmc --cex " - - Added $ff and $_FF_ cell types - - Added $global_clock verilog syntax support for creating $ff cells - - Added clk2fflogic - - -Yosys 0.5 .. Yosys 0.6 ----------------------- - - * Various - - Added Contributor Covenant Code of Conduct - - Various improvements in dict<> and pool<> - - Added hashlib::mfp and refactored SigMap - - Improved support for reals as module parameters - - Various improvements in SMT2 back-end - - Added "keep_hierarchy" attribute - - Verilog front-end: define `BLACKBOX in -lib mode - - Added API for converting internal cells to AIGs - - Added ENABLE_LIBYOSYS Makefile option - - Removed "techmap -share_map" (use "-map +/filename" instead) - - Switched all Python scripts to Python 3 - - Added support for $display()/$write() and $finish() to Verilog front-end - - Added "yosys-smtbmc" formal verification flow - - Added options for clang sanitizers to Makefile - - * New commands and options - - Added "scc -expect -nofeedback" - - Added "proc_dlatch" - - Added "check" - - Added "select %xe %cie %coe %M %C %R" - - Added "sat -dump_json" (WaveJSON format) - - Added "sat -tempinduct-baseonly -tempinduct-inductonly" - - Added "sat -stepsize" and "sat -tempinduct-step" - - Added "sat -show-regs -show-public -show-all" - - Added "write_json" (Native Yosys JSON format) - - Added "write_blif -attr" - - Added "dffinit" - - Added "chparam" - - Added "muxcover" - - Added "pmuxtree" - - Added memory_bram "make_outreg" feature - - Added "splice -wires" - - Added "dff2dffe -direct-match" - - Added simplemap $lut support - - Added "read_blif" - - Added "opt_share -share_all" - - Added "aigmap" - - Added "write_smt2 -mem -regs -wires" - - Added "memory -nordff" - - Added "write_smv" - - Added "synth -nordff -noalumacc" - - Added "rename -top new_name" - - Added "opt_const -clkinv" - - Added "synth -nofsm" - - Added "miter -assert" - - Added "read_verilog -noautowire" - - Added "read_verilog -nodpi" - - Added "tribuf" - - Added "lut2mux" - - Added "nlutmap" - - Added "qwp" - - Added "test_cell -noeval" - - Added "edgetypes" - - Added "equiv_struct" - - Added "equiv_purge" - - Added "equiv_mark" - - Added "equiv_add -try -cell" - - Added "singleton" - - Added "abc -g -luts" - - Added "torder" - - Added "write_blif -cname" - - Added "submod -copy" - - Added "dffsr2dff" - - Added "stat -liberty" - - * Synthesis metacommands - - Various improvements in synth_xilinx - - Added synth_ice40 and synth_greenpak4 - - Added "prep" metacommand for "synthesis lite" - - * Cell library changes - - Added cell types to "help" system - - Added $meminit cell type - - Added $assume cell type - - Added $_MUX4_, $_MUX8_, and $_MUX16_ cells - - Added $tribuf and $_TBUF_ cell types - - Added read-enable to memory model - - * YosysJS - - Various improvements in emscripten build - - Added alternative webworker-based JS API - - Added a few example applications - - -Yosys 0.4 .. Yosys 0.5 ----------------------- - - * API changes - - Added log_warning() - - Added eval_select_args() and eval_select_op() - - Added cell->known(), cell->input(portname), cell->output(portname) - - Skip blackbox modules in design->selected_modules() - - Replaced std::map<> and std::set<> with dict<> and pool<> - - New SigSpec::extend() is what used to be SigSpec::extend_u0() - - Added YS_OVERRIDE, YS_FINAL, YS_ATTRIBUTE, YS_NORETURN - - * Cell library changes - - Added flip-flops with enable ($dffe etc.) - - Added $equiv cells for equivalence checking framework - - * Various - - Updated ABC to hg rev 61ad5f908c03 - - Added clock domain partitioning to ABC pass - - Improved plugin building (see "yosys-config --build") - - Added ENABLE_NDEBUG Makefile flag for high-performance builds - - Added "yosys -d", "yosys -L" and other driver improvements - - Added support for multi-bit (array) cell ports to "write_edif" - - Now printing most output to stdout, not stderr - - Added "onehot" attribute (set by "fsm_map") - - Various performance improvements - - Vastly improved Xilinx flow - - Added "make unsintall" - - * Equivalence checking - - Added equivalence checking commands: - equiv_make equiv_simple equiv_status - equiv_induct equiv_miter - equiv_add equiv_remove - - * Block RAM support: - - Added "memory_bram" command - - Added BRAM support to Xilinx flow - - * Other New Commands and Options - - Added "dff2dffe" - - Added "fsm -encfile" - - Added "dfflibmap -prepare" - - Added "write_blid -unbuf -undef -blackbox" - - Added "write_smt2" for writing SMT-LIBv2 files - - Added "test_cell -w -muxdiv" - - Added "select -read" - - -Yosys 0.3.0 .. Yosys 0.4 ------------------------- - - * Platform Support - - Added support for mxe-based cross-builds for win32 - - Added sourcecode-export as VisualStudio project - - Added experimental EMCC (JavaScript) support - - * Verilog Frontend - - Added -sv option for SystemVerilog (and automatic *.sv file support) - - Added support for real-valued constants and constant expressions - - Added support for non-standard "via_celltype" attribute on task/func - - Added support for non-standard "module mod_name(...);" syntax - - Added support for non-standard """ macro bodies - - Added support for array with more than one dimension - - Added support for $readmemh and $readmemb - - Added support for DPI functions - - * Changes in internal cell library - - Added $shift and $shiftx cell types - - Added $alu, $lcu, $fa and $macc cell types - - Removed $bu0 and $safe_pmux cell types - - $mem/$memwr WR_EN input is now a per-data-bit enable signal - - Added $_NAND_ $_NOR_ $_XNOR_ $_AOI3_ $_OAI3_ $_AOI4_ $_OAI4_ - - Renamed ports of $lut cells (from I->O to A->Y) - - Renamed $_INV_ to $_NOT_ - - * Changes for simple synthesis flows - - There is now a "synth" command with a recommended default script - - Many improvements in synthesis of arithmetic functions to gates - - Multipliers and adders with many operands are using carry-save adder trees - - Remaining adders are now implemented using Brent-Kung carry look-ahead adders - - Various new high-level optimizations on RTL netlist - - Various improvements in FSM optimization - - Updated ABC to hg 5b5af75f1dda (from 2014-11-07) - - * Changes in internal APIs and RTLIL - - Added log_id() and log_cell() helper functions - - Added function-like cell creation helpers - - Added GetSize() function (like .size() but with int) - - Major refactoring of RTLIL::Module and related classes - - Major refactoring of RTLIL::SigSpec and related classes - - Now RTLIL::IdString is essentially an int - - Added macros for code coverage counters - - Added some Makefile magic for pretty make logs - - Added "kernel/yosys.h" with all the core definitions - - Changed a lot of code from FILE* to c++ streams - - Added RTLIL::Monitor API and "trace" command - - Added "Yosys" C++ namespace - - * Changes relevant to SAT solving - - Added ezSAT::keep_cnf() and ezSAT::non_incremental() - - Added native ezSAT support for vector shift ops - - Updated MiniSAT to git 37dc6c67e2 (from 2013-09-25) - - * New commands (or large improvements to commands) - - Added "synth" command with default script - - Added "share" (finally some real resource sharing) - - Added "memory_share" (reduce number of ports on memories) - - Added "wreduce" and "alumacc" commands - - Added "opt -keepdc -fine -full -fast" - - Added some "test_*" commands - - * Various other changes - - Added %D and %c select operators - - Added support for labels in yosys scripts - - Added support for here-documents in yosys scripts - - Support "+/" prefix for files from proc_share_dir - - Added "autoidx" statement to ilang language - - Switched from "yosys-svgviewer" to "xdot" - - Renamed "stdcells.v" to "techmap.v" - - Various bug fixes and small improvements - - Improved welcome and bye messages - - -Yosys 0.2.0 .. Yosys 0.3.0 --------------------------- - - * Driver program and overall behavior: - - Added "design -push" and "design -pop" - - Added "tee" command for redirecting log output - - * Changes in the internal cell library: - - Added $dlatchsr and $_DLATCHSR_???_ cell types - - * Improvements in Verilog frontend: - - Improved support for const functions (case, always, repeat) - - The generate..endgenerate keywords are now optional - - Added support for arrays of module instances - - Added support for "`default_nettype" directive - - Added support for "`line" directive - - * Other front- and back-ends: - - Various changes to "write_blif" options - - Various improvements in EDIF backend - - Added "vhdl2verilog" pseudo-front-end - - Added "verific" pseudo-front-end - - * Improvements in technology mapping: - - Added support for recursive techmap - - Added CONSTMSK and CONSTVAL features to techmap - - Added _TECHMAP_CONNMAP_*_ feature to techmap - - Added _TECHMAP_REPLACE_ feature to techmap - - Added "connwrappers" command for wrap-extract-unwrap method - - Added "extract -map %" feature - - Added "extract -ignore_param ..." and "extract -ignore_parameters" - - Added "techmap -max_iter" option - - * Improvements to "eval" and "sat" framework: - - Now include a copy of Minisat (with build fixes applied) - - Switched to Minisat::SimpSolver as SAT back-end - - Added "sat -dump_vcd" feature - - Added "sat -dump_cnf" feature - - Added "sat -initsteps " feature - - Added "freduce -stop " feature - - Added "freduce -dump " feature - - * Integration with ABC: - - Updated ABC rev to 7600ffb9340c - - * Improvements in the internal APIs: - - Added RTLIL::Module::add... helper methods - - Various build fixes for OSX (Darwin) and OpenBSD - - -Yosys 0.1.0 .. Yosys 0.2.0 --------------------------- - - * Changes to the driver program: - - Added "yosys -h" and "yosys -H" - - Added support for backslash line continuation in scripts - - Added support for #-comments in same line as command - - Added "echo" and "log" commands - - * Improvements in Verilog frontend: - - Added support for local registers in named blocks - - Added support for "case" in "generate" blocks - - Added support for $clog2 system function - - Added support for basic SystemVerilog assert statements - - Added preprocessor support for macro arguments - - Added preprocessor support for `elsif statement - - Added "verilog_defaults" command - - Added read_verilog -icells option - - Added support for constant sizes from parameters - - Added "read_verilog -setattr" - - Added support for function returning 'integer' - - Added limited support for function calls in parameter values - - Added "read_verilog -defer" to suppress evaluation of modules with default parameters - - * Other front- and back-ends: - - Added BTOR backend - - Added Liberty frontend - - * Improvements in technology mapping: - - The "dfflibmap" command now strongly prefers solutions with - no inverters in clock paths - - The "dfflibmap" command now prefers cells with smaller area - - Added support for multiple -map options to techmap - - Added "dfflibmap" support for //-comments in liberty files - - Added "memory_unpack" command to revert "memory_collect" - - Added standard techmap rule "techmap -share_map pmux2mux.v" - - Added "iopadmap -bits" - - Added "setundef" command - - Added "hilomap" command - - * Changes in the internal cell library: - - Major rewrite of simlib.v for better compatibility with other tools - - Added PRIORITY parameter to $memwr cells - - Added TRANSPARENT parameter to $memrd cells - - Added RD_TRANSPARENT parameter to $mem cells - - Added $bu0 cell (always 0-extend, even undef MSB) - - Added $assert cell type - - Added $slice and $concat cell types - - * Integration with ABC: - - Updated ABC to hg rev 2058c8ccea68 - - Tighter integration of ABC build with Yosys build. The make - targets 'make abc' and 'make install-abc' are now obsolete. - - Added support for passing FFs from one clock domain through ABC - - Now always use BLIF as exchange format with ABC - - Added support for "abc -script +" - - Improved standard ABC recipe - - Added support for "keep" attribute to abc command - - Added "abc -dff / -clk / -keepff" options - - * Improvements to "eval" and "sat" framework: - - Added support for "0" and "~0" in right-hand side -set expressions - - Added "eval -set-undef" and "eval -table" - - Added "sat -set-init" and "sat -set-init-*" for sequential problems - - Added undef support to SAT solver, incl. various new "sat" options - - Added correct support for === and !== for "eval" and "sat" - - Added "sat -tempinduct" (default -seq is now non-induction sequential) - - Added "sat -prove-asserts" - - Complete rewrite of the 'freduce' command - - Added "miter" command - - Added "sat -show-inputs" and "sat -show-outputs" - - Added "sat -ignore_unknown_cells" (now produce an error by default) - - Added "sat -falsify" - - Now "sat -verify" and "sat -falsify" can also be used without "-prove" - - Added "expose" command - - Added support for @ to sat and eval signal expressions - - * Changes in the 'make test' framework and auxiliary test tools: - - Added autotest.sh -p and -f options - - Replaced autotest.sh ISIM support with XSIM support - - Added test cases for SAT framework - - * Added "abbreviated IDs": - - Now $$foo can be abbreviated as $foo. - - Usually this last part is a unique id (from RTLIL::autoidx) - - This abbreviated IDs are now also used in "show" output - - * Other changes to selection framework: - - Now */ is optional in */: expressions - - Added "select -assert-none" and "select -assert-any" - - Added support for matching modules by attribute (A:) - - Added "select -none" - - Added support for r: pattern for matching cell parameters - - Added support for !=, <, <=, >=, > for attribute and parameter matching - - Added support for %s for selecting sub-modules - - Added support for %m for expanding selections to whole modules - - Added support for i:*, o:* and x:* pattern for selecting module ports - - Added support for s: pattern for matching wire width - - Added support for %a operation to select wire aliases - - * Various other changes to commands and options: - - The "ls" command now supports wildcards - - Added "show -pause" and "show -format dot" - - Added "show -color" support for cells - - Added "show -label" and "show -notitle" - - Added "dump -m" and "dump -n" - - Added "history" command - - Added "rename -hide" - - Added "connect" command - - Added "splitnets -driver" - - Added "opt_const -mux_undef" - - Added "opt_const -mux_bool" - - Added "opt_const -undriven" - - Added "opt -mux_undef -mux_bool -undriven -purge" - - Added "hierarchy -libdir" - - Added "hierarchy -purge_lib" (by default now do not remove lib cells) - - Added "delete" command - - Added "dump -append" - - Added "setattr" and "setparam" commands - - Added "design -stash/-copy-from/-copy-to" - - Added "copy" command - - Added "splice" command - diff --git a/yosys/CMakeLists.txt b/yosys/CMakeLists.txt deleted file mode 100644 index 9ec574964..000000000 --- a/yosys/CMakeLists.txt +++ /dev/null @@ -1,103 +0,0 @@ -cmake_minimum_required(VERSION 3.3.0) - -include(CMakeParseArguments) - -project(yosys) - -# Version number -set(YOSYS_VERSION_MAJOR 0.7) -set(YOSYS_VERSION_MINOR 0) -set(YOSYS_VERSION_PATCH 0) - -# Options to enable/disable dependencies -option(YOSYS_ENABLE_TCL, "Enable TCL parser integrated in yosys" ON) -option(YOSYS_ENABLE_ABC, "Enable ABC library integrated in yosys" ON) -option(YOSYS_ENABLE_PLUGINS, "Enable plug-in in yosys" ON) -option(YOSYS_ENABLE_READLINE, "Enable readline library in yosys" ON) -option(YOSYS_ENABLE_VERIFIC, "Enable verification library in yosys" OFF) -option(YOSYS_ENABLE_COVER, "Enable coverage test in yosys" ON) -option(YOSYS_ENABLE_LIBYOSYS, "Enable static library compiled yosys" OFF) -option(YOSYS_ENABLE_GPROF, "Enable profiling in compiled yosys" OFF) -option(YOSYS_ENABLE_NDEBUG, "Enable non-debugging feature in compiled yosys" OFF) - -# -## Search and link dependent packages -## We need readline to compile -if (YOSYS_ENABLE_READLINE) - find_package(Readline REQUIRED) -endif() -# -######################### -## # -## Compiler Flags Setup # -## # -######################### -# -## Compiler flag configuration checks -include(CheckCCompilerFlag) -include(CheckCXXCompilerFlag) -# -## Required Compiler Standard -#set(CMAKE_CXX_STANDARD 11) # need at least c+11 standard -#set(CMAKE_CXX_STANDARD_REQUIRED ON) -# -## Set warning flags -#set(WARN_FLAGS_TO_CHECK "") # checklist of warning flags -#set(WARN_FLAGS "") # actual warning flags to be added during compilation -## Add warning flags depending on options -#if (YOSYS_ENABLE_NDEBUG) -# set(WARN_FLAGS_TO_CHECK, ${WARN_FLAGS_TO_CHECK}, "-O3") -#endif() -# -# -##Collect the source files -#file(GLOB_RECURSE EXEC_YOSYS kernel/yosys.cc) -#file(GLOB_RECURSE LIB_SOURCES kernel/*.cc) -#file(GLOB_RECURSE LIB_HEADERS kernel/*.h) -#files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) -# -## Use c++ compiler for c source files -#set_source_files_properties(${LIB_SOURCES} PROPERTIES LANGUAGE CXX) -#set_source_files_properties(${EXEC_SOURCES} PROPERTIES LANGUAGE CXX) -#set_source_files_properties(${EXEC_SOURCES_SHELL} PROPERTIES LANGUAGE CXX) -# -##Build the library -#add_library(libyosys STATIC -# ${LIB_HEADERS} -# ${LIB_SOURCES}) -# -## add header files to be included -#target_include_directories(libyosys PUBLIC ${LIB_INCLUDE_DIRS}) -#set_target_properties(libyosys PROPERTIES PREFIX "") #Avoid extra 'lib' prefix#Create the executable -# -##Specify link-time dependancies -#target_link_libraries(libyosys -# readline) -# -## Build targets -## 1. yosys -#add_executable(yosys ${EXEC_SOURCES}) -#target_link_libraries(vpr -# libyosys) -# 2. yosys-config - -# run makefile provided, we pass-on the options to the local make file -add_custom_target( - yosys ALL - COMMAND - $(MAKE) - #CC=${CMAKE_C_COMPILER} - #CXX=${CMAKE_CXX_COMPILER} - #LD=${CMAKE_CXX_COMPILER} - #ENABLE_TCL=${YOSYS_ENABLE_TCL} - #ENABLE_ABC=${YOSYS_ENABLE_ABC} - #ENABLE_PLUGINS=${YOSYS_ENABLE_PLUGINS} - #ENABLE_READLINE=${YOSYS_ENABLE_READLINE} - #ENABLE_VERIFIC=${YOSYS_ENABLE_VERIFIC} - #ENABLE_COVER=${YOSYS_ENABLE_COVER} - #ENABLE_LIBYOSYS=${YOSYS_ENABLE_LIBYOSYS} - #ENABLE_GPROF=${YOSYS_ENABLE_GPROF} - #ENABLE_NDEBUG=${YOSYS_ENABLE_NDEBUG} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Compile Yosys with given Makefile" -) diff --git a/yosys/COPYING b/yosys/COPYING deleted file mode 100644 index 0839088c3..000000000 --- a/yosys/COPYING +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (C) 2012 - 2019 Clifford Wolf - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/yosys/CodeOfConduct b/yosys/CodeOfConduct deleted file mode 100644 index 4f779977b..000000000 --- a/yosys/CodeOfConduct +++ /dev/null @@ -1,73 +0,0 @@ -Contributor Covenant Code of Conduct - -Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at clifford@clifford.at (and/or -cliffordvienna@gmail.com if you think your mail to the other address got -stuck in the spam filter). All complaints will be reviewed and investigated and -will result in a response that is deemed necessary and appropriate to the -circumstances. The project team is obligated to maintain confidentiality with -regard to the reporter of an incident. Further details of specific enforcement -policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -Attribution - -This Code of Conduct is adapted from the Contributor Covenant, version 1.4, -available at http://contributor-covenant.org/version/1/4/ diff --git a/yosys/CodingReadme b/yosys/CodingReadme deleted file mode 100644 index b64e79178..000000000 --- a/yosys/CodingReadme +++ /dev/null @@ -1,509 +0,0 @@ - -This file contains some very brief documentation on things like programming APIs. -Also consult the Yosys manual and the section about programming in the presentation. -(Both can be downloaded as PDF from the yosys webpage.) - - ---snip-- only the lines below this mark are included in the yosys manual --snip-- -Getting Started -=============== - - -Outline of a Yosys command --------------------------- - -Here is a the C++ code for a "hello_world" Yosys command (hello.cc): - - #include "kernel/yosys.h" - - USING_YOSYS_NAMESPACE - PRIVATE_NAMESPACE_BEGIN - - struct HelloWorldPass : public Pass { - HelloWorldPass() : Pass("hello_world") { } - void execute(vector, Design*) override { - log("Hello World!\n"); - } - } HelloWorldPass; - - PRIVATE_NAMESPACE_END - -This can be built into a Yosys module using the following command: - - yosys-config --exec --cxx --cxxflags --ldflags -o hello.so -shared hello.cc --ldlibs - -Or short: - - yosys-config --build hello.so hello.cc - -And then executed using the following command: - - yosys -m hello.so -p hello_world - - -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. Yosys Container Classes - -Yosys uses dict and pool as main container classes. dict is -essentially a replacement for std::unordered_map and pool is a -replacement for std::unordered_set. The main characteristics are: - - - dict and pool are about 2x faster than the std containers - - - references to elements in a dict or pool are invalidated by - insert and remove operations (similar to std::vector 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 and pool will have the same order of iteration across - all compilers, standard libraries and architectures. - -In addition to dict and pool there is also an idict that -creates a bijective map from K to the integers. For example: - - idict 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 implements a merge-find set data structure (aka. disjoint-set or -union-find) over the type K ("mfp" = merge-find-promote). - - 2. Standard STL data types - -In Yosys we use std::vector and std::string whenever applicable. When -dict and pool are not suitable then std::map and std::set -are used instead. - -The types std::vector and std::string are also available as vector -and string in the Yosys namespace. - - 3. RTLIL objects - -The current design (essentially a collection of modules, each defined by a -netlist) is stored in memory using RTLIL object (declared in kernel/rtlil.h, -automatically included by kernel/yosys.h). You should glance over at least -the declarations for the following types in kernel/rtlil.h: - - RTLIL::IdString - This is a handle for an identifier (e.g. cell or wire name). - It feels a lot like a std::string, but is only a single int - in size. (The actual string is stored in a global lookup - table.) - - RTLIL::SigBit - A single signal bit. I.e. either a constant state (0, 1, - x, z) or a single bit from a wire. - - RTLIL::SigSpec - Essentially a vector of SigBits. - - RTLIL::Wire - RTLIL::Cell - The building blocks of the netlist in a module. - - RTLIL::Module - RTLIL::Design - The module is a container with connected cells and wires - in it. The design is a container with modules in it. - -All this types are also available without the RTLIL:: prefix in the Yosys -namespace. - - 4. SigMap and other Helper Classes - -There are a couple of additional helper classes that are in wide use -in Yosys. Most importantly there is SigMap (declared in kernel/sigtools.h). - -When a design has many wires in it that are connected to each other, then a -single signal bit can have multiple valid names. The SigMap object can be used -to map SigSpecs or SigBits to unique SigSpecs and SigBits that consistently -only use one wire from such a group of connected wires. For example: - - SigBit a = module->addWire(NEW_ID); - SigBit b = module->addWire(NEW_ID); - module->connect(a, b); - - log("%d\n", a == b); // will print 0 - - SigMap sigmap(module); - log("%d\n", sigmap(a) == sigmap(b)); // will print 1 - - -Using the RTLIL Netlist Format ------------------------------- - -In the RTLIL netlist format the cell ports contain SigSpecs that point to the -Wires. There are no references in the other direction. This has two direct -consequences: - -(1) It is very easy to go from cells to wires but hard to go in the other way. - -(2) There is no danger in removing cells from the netlists, but removing wires -can break the netlist format when there are still references to the wire -somewhere in the netlist. - -The solution to (1) is easy: Create custom indexes that allow you to make fast -lookups for the wire-to-cell direction. You can either use existing generic -index structures to do that (such as the ModIndex class) or write your own -index. For many application it is simplest to construct a custom index. For -example: - - SigMap sigmap(module); - dict sigbit_to_driver_index; - - for (auto cell : module->cells()) - for (auto &conn : cell->connections()) - if (cell->output(conn.first)) - for (auto bit : sigmap(conn.second)) - sigbit_to_driver_index[bit] = cell; - -Regarding (2): There is a general theme in Yosys that you don't remove wires -from the design. You can rename them, unconnect them, but you do not actually remove -the Wire object from the module. Instead you let the "clean" command take care -of the dangling wires. On the other hand it is safe to remove cells (as long as -you make sure this does not invalidate a custom index you are using in your code). - - -Example Code ------------- - -The following yosys commands are a good starting point if you are looking for examples -of how to use the Yosys API: - - manual/CHAPTER_Prog/stubnets.cc - manual/PRESENTATION_Prog/my_cmd.cc - - -Notes on the existing codebase ------------------------------- - -For historical reasons not all parts of Yosys adhere to the current coding -style. When adding code to existing parts of the system, adhere to this guide -for the new code instead of trying to mimic the style of the surrounding code. - - - -Coding Style -============ - - -Formatting of code ------------------- - -- Yosys code is using tabs for indentation. Tabs are 8 characters. - -- A continuation of a statement in the following line is indented by - two additional tabs. - -- Lines are as long as you want them to be. A good rule of thumb is - to break lines at about column 150. - -- Opening braces can be put on the same or next line as the statement - opening the block (if, switch, for, while, do). Put the opening brace - on its own line for larger blocks, especially blocks that contains - blank lines. - -- Otherwise stick to the Linux Kernel Coding Style: - https://www.kernel.org/doc/Documentation/CodingStyle - - -C++ Language -------------- - -Yosys is written in C++11. At the moment only constructs supported by -gcc 4.8 are allowed in Yosys code. This will change in future releases. - -In general Yosys uses "int" instead of "size_t". To avoid compiler -warnings for implicit type casts, always use "GetSize(foobar)" instead -of "foobar.size()". (GetSize() is defined in kernel/yosys.h) - -Use range-based for loops whenever applicable. - - ---snap-- only the lines above this mark are included in the yosys manual --snap-- - - -Creating the Visual Studio Template Project -=========================================== - -1. Create an empty Visual C++ Win32 Console App project - - Microsoft Visual Studio Express 2013 for Windows Desktop - Open New Project Wizard (File -> New Project..) - - Project Name: YosysVS - Solution Name: YosysVS - [X] Create directory for solution - [ ] Add to source control - - [X] Console applications - [X] Empty Project - [ ] SDL checks - -2. Open YosysVS Project Properties - - Select Configuration: All Configurations - - C/C++ -> General -> Additional Include Directories - Add: ..\yosys - - C/C++ -> Preprocessor -> Preprocessor Definitions - Add: _YOSYS_;_CRT_SECURE_NO_WARNINGS - -3. Resulting file system tree: - - YosysVS/ - YosysVS/YosysVS - YosysVS/YosysVS/YosysVS.vcxproj - YosysVS/YosysVS/YosysVS.vcxproj.filters - YosysVS/YosysVS.sdf - YosysVS/YosysVS.sln - YosysVS/YosysVS.v12.suo - -4. Zip YosysVS as YosysVS-Tpl-v1.zip - - - -Checklist for adding internal cell types -======================================== - -Things to do right away: - - - Add to kernel/celltypes.h (incl. eval() handling for non-mem cells) - - Add to InternalCellChecker::check() in kernel/rtlil.cc - - Add to techlibs/common/simlib.v - - Add to techlibs/common/techmap.v - -Things to do after finalizing the cell interface: - - - Add support to kernel/satgen.h for the new cell type - - Add to manual/CHAPTER_CellLib.tex (or just add a fixme to the bottom) - - Maybe add support to the Verilog backend for dumping such cells as expression - - - -Checklist for creating Yosys releases -===================================== - -Update the CHANGELOG file: - - cd ~yosys - gitk & - vi CHANGELOG - - -Update and check documentation: - - cd ~yosys - make update-manual - make manual - - sanity check the figures in the appnotes and presentation - - if there are any odd things -> investigate - - make cosmetic changes to the .tex files if necessary - - cd ~yosys - vi README CodingReadme - - is the information provided in those file still up to date - - -Then with default config setting: - - cd ~yosys - make vgtest - - cd ~yosys - ./yosys -p 'proc; show' tests/simple/fiedler-cooley.v - ./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v - ./yosys -p 'synth; show' tests/simple/fiedler-cooley.v - ./yosys -p 'synth_xilinx -top up3down5; show' tests/simple/fiedler-cooley.v - - cd ~yosys/examples/cmos - bash testbench.sh - - cd ~yosys/examples/basys3 - bash run.sh - - -Test building plugins with various of the standard passes: - - yosys-config --build test.so equiv_simple.cc - - also check the code examples in CodingReadme - - -And if a version of the verific library is currently available: - - cd ~yosys - cat frontends/verific/build_amd64.txt - - follow instructions - - cd frontends/verific - ../../yosys test_navre.ys - - -Finally run all tests with "make config-{clang,gcc,gcc-4.8}": - - cd ~yosys - make clean - make test - make ystests - make vloghtb - make install - - cd ~yosys-bigsim - make clean - make full - - cd ~vloghammer - make purge gen_issues gen_samples - make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" REPORT_FULL=1 world - chromium-browser report.html - - -Release: - - - set YOSYS_VER to x.y.z in Makefile - - update version string in CHANGELOG - git commit -am "Yosys x.y.z" - - - push tag to github - - post changelog on github - - post short release note on reddit - - -Updating the website: - - cd ~yosys - make manual - make install - - - update pdf files on the website - - cd ~yosys-web - make update_cmd - make update_show - git commit -am update - make push - - - -Cross-Building for Windows with MXE -=================================== - -Check http://mxe.cc/#requirements and install all missing requirements. - -As root (or other user with write access to /usr/local/src): - - cd /usr/local/src - git clone https://github.com/mxe/mxe.git - cd mxe - - make -j$(nproc) MXE_PLUGIN_DIRS="plugins/tcl.tk" \ - MXE_TARGETS="i686-w64-mingw32.static" \ - gcc tcl readline - -Then as regular user in some directory where you build stuff: - - git clone https://github.com/cliffordwolf/yosys.git yosys-win32 - cd yosys-win32 - make config-mxe - make -j$(nproc) mxebin - - - -How to add unit test -==================== - -Unit test brings some advantages, briefly, we can list some of them (reference -[1](https://en.wikipedia.org/wiki/Unit_testing)): - -* Tests reduce bugs in new features; -* Tests reduce bugs in existing features; -* Tests are good documentation; -* Tests reduce the cost of change; -* Tests allow refactoring; - -With those advantages in mind, it was required to choose a framework which fits -well with C/C++ code. Hence, it was chosen (google test) -[https://github.com/google/googletest], because it is largely used and it is -relatively easy learn. - -Install and configure google test (manually) --------------------------------------------- - -In this section, you will see a brief description of how to install google -test. However, it is strongly recommended that you take a look to the official -repository (https://github.com/google/googletest) and refers to that if you -have any problem to install it. Follow the steps below: - -* Install: cmake and pthread -* Clone google test project from: https://github.com/google/googletest and - enter in the project directory -* Inside project directory, type: - -``` -cmake -DBUILD_SHARED_LIBS=ON . -make -``` - -* After compilation, copy all "*.so" inside directory "googlemock" and - "googlemock/gtest" to "/usr/lib/" -* Done! Now you can compile your tests. - -If you have any problem, go to the official repository to find help. - -Ps.: Some distros already have googletest packed. If your distro supports it, -you can use it instead of compile. - -Create new unit test --------------------- - -If you want to add new unit tests for Yosys, just follow the steps below: - -* Go to directory "yosys/test/unit/" -* In this directory you can find something similar Yosys's directory structure. - To create your unit test file you have to follow this pattern: - fileNameToImplementUnitTest + Test.cc. E.g.: if you want to implement the - unit test for kernel/celledges.cc, you will need to create a file like this: - tests/unit/kernel/celledgesTest.cc; -* Implement your unit test - -Run unit test -------------- - -To compile and run all unit tests, just go to yosys root directory and type: -``` -make unit-test -``` - -If you want to remove all unit test files, type: -``` -make clean-unit-test -``` diff --git a/yosys/Dockerfile b/yosys/Dockerfile deleted file mode 100644 index 3c7188d82..000000000 --- a/yosys/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM ubuntu:18.04 as builder -LABEL author="Abdelrahman Hosny " -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y build-essential \ - clang \ - bison \ - flex \ - libreadline-dev \ - gawk \ - tcl-dev \ - libffi-dev \ - git \ - pkg-config \ - python3 && \ - rm -rf /var/lib/apt/lists -COPY . / -RUN make && \ - make install - -FROM ubuntu:18.04 -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y libreadline-dev tcl-dev - -COPY --from=builder /yosys /build/yosys -COPY --from=builder /yosys-abc /build/yosys-abc -COPY --from=builder /yosys-config /build/yosys-config -COPY --from=builder /yosys-filterlib /build/yosys-filterlib -COPY --from=builder /yosys-smtbmc /build/yosys-smtbmc - -ENV PATH /build:$PATH -RUN useradd -m yosys -USER yosys -ENTRYPOINT ["yosys"] diff --git a/yosys/Makefile b/yosys/Makefile deleted file mode 100644 index 3c1f51e7e..000000000 --- a/yosys/Makefile +++ /dev/null @@ -1,903 +0,0 @@ - -# CONFIG := clang -CONFIG := gcc -# CONFIG := gcc-4.8 -# CONFIG := afl-gcc -# CONFIG := emcc -# CONFIG := mxe -# CONFIG := msys2 -# CONFIG := msys2-64 - -# features (the more the better) -ENABLE_TCL := 0 -ENABLE_ABC := 1 -ENABLE_GLOB := 1 -ENABLE_PLUGINS := 1 -ENABLE_READLINE := 1 -ENABLE_EDITLINE := 0 -ENABLE_VERIFIC := 0 -ENABLE_COVER := 1 -ENABLE_LIBYOSYS := 0 -ENABLE_PROTOBUF := 0 - -# python wrappers -ENABLE_PYOSYS := 0 - -# other configuration flags -ENABLE_GCOV := 0 -ENABLE_GPROF := 0 -ENABLE_DEBUG := 0 -ENABLE_NDEBUG := 0 -LINK_CURSES := 0 -LINK_TERMCAP := 0 -LINK_ABC := 0 -# Needed for environments that don't have proper thread support (i.e. emscripten) -DISABLE_ABC_THREADS := 0 - -# clang sanitizers -SANITIZER = -# SANITIZER = address -# SANITIZER = memory -# SANITIZER = undefined -# SANITIZER = cfi - - -OS := $(shell uname -s) -PREFIX ?= /usr/local -INSTALL_SUDO := - -ifneq ($(wildcard Makefile.conf),) -include Makefile.conf -endif - -BINDIR := $(PREFIX)/bin -LIBDIR := $(PREFIX)/lib -DATDIR := $(PREFIX)/share/yosys - -EXE = -OBJS = -GENFILES = -EXTRA_OBJS = -EXTRA_TARGETS = -TARGETS = yosys$(EXE) yosys-config - -PRETTY = 1 -SMALL = 0 - -# Unit test -UNITESTPATH := tests/unit - -all: top-all - -YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) -VPATH := $(YOSYS_SRC) - -CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include -LDFLAGS := $(LDFLAGS) -L$(LIBDIR) -LDLIBS := $(LDLIBS) -lstdc++ -lm -PLUGIN_LDFLAGS := - -PKG_CONFIG ?= pkg-config -SED ?= sed -BISON ?= bison -STRIP ?= strip -AWK ?= awk - -ifeq ($(OS), Darwin) -PLUGIN_LDFLAGS += -undefined dynamic_lookup - -# homebrew search paths -ifneq ($(shell which brew),) -BREW_PREFIX := $(shell brew --prefix)/opt -$(info $$BREW_PREFIX is [${BREW_PREFIX}]) -ifeq ($(ENABLE_PYOSYS),1) -CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost -LDFLAGS += -L$(BREW_PREFIX)/boost/lib -endif -CXXFLAGS += -I$(BREW_PREFIX)/readline/include -LDFLAGS += -L$(BREW_PREFIX)/readline/lib -PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) -PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH) -export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) - -# macports search paths -else ifneq ($(shell which port),) -PORT_PREFIX := $(patsubst %/bin/port,%,$(shell which port)) -CXXFLAGS += -I$(PORT_PREFIX)/include -LDFLAGS += -L$(PORT_PREFIX)/lib -PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH) -export PATH := $(PORT_PREFIX)/bin:$(PATH) -endif - -else -LDFLAGS += -rdynamic -LDLIBS += -lrt -endif - -YOSYS_VER := 0.9 -GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN) -OBJS = kernel/version_$(GIT_REV).o - -# set 'ABCREV = default' to use abc/ as it is -# -# Note: If you do ABC development, make sure that 'abc' in this directory -# is just a symlink to your actual ABC working directory, as 'make mrproper' -# will remove the 'abc' directory and you do not want to accidentally -# delete your work on ABC.. -ABCREV = 3709744 -ABCPULL = 1 -ABCURL ?= https://github.com/berkeley-abc/abc -ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 - -# set ABCEXTERNAL = to use an external ABC instance -# Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set. -ABCEXTERNAL ?= - -define newline - - -endef - -ifneq ($(wildcard Makefile.conf),) -$(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$,;' < Makefile.conf | tr -d '\n' | sed 's,\$$--\$$$$,,'))) -include Makefile.conf -endif - -ifeq ($(ENABLE_PYOSYS),1) -PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" -PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) -PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") -PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.) -PYTHON_PREFIX := $(shell $(PYTHON_EXECUTABLE)-config --prefix) -PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages - -# Reload Makefile.conf to override python specific variables if defined -ifneq ($(wildcard Makefile.conf),) -include Makefile.conf -endif - -endif - -ifeq ($(CONFIG),clang) -CXX = clang -LD = clang++ -CXXFLAGS += -std=c++11 -Os -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" - -ifneq ($(SANITIZER),) -$(info [Clang Sanitizer] $(SANITIZER)) -CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER) -LDFLAGS += -g -fsanitize=$(SANITIZER) -ifeq ($(SANITIZER),address) -ENABLE_COVER := 0 -endif -ifeq ($(SANITIZER),memory) -CXXFLAGS += -fPIE -fsanitize-memory-track-origins -LDFLAGS += -fPIE -fsanitize-memory-track-origins -endif -ifeq ($(SANITIZER),cfi) -CXXFLAGS += -flto -LDFLAGS += -flto -endif -endif - -else ifeq ($(CONFIG),gcc) -CXX = gcc -LD = gcc -CXXFLAGS += -std=c++11 -Os -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" - -else ifeq ($(CONFIG),gcc-static) -LD = $(CXX) -LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -static -LDLIBS := $(filter-out -lrt,$(LDLIBS)) -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -CXXFLAGS += -std=c++11 -Os -ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(LD)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \ - ARCHFLAGS="-DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING=1 -Wno-unused-but-set-variable $(ARCHFLAGS)" ABC_USE_NO_READLINE=1 -ifeq ($(DISABLE_ABC_THREADS),1) -ABCMKARGS += "ABC_USE_NO_PTHREADS=1" -endif - -else ifeq ($(CONFIG),gcc-4.8) -CXX = gcc-4.8 -LD = gcc-4.8 -CXXFLAGS += -std=c++11 -Os -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" - -else ifeq ($(CONFIG),afl-gcc) -CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc -LD = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc -CXXFLAGS += -std=c++11 -Os -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" - -else ifeq ($(CONFIG),cygwin) -CXX = gcc -LD = gcc -CXXFLAGS += -std=gnu++11 -Os -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" - -else ifeq ($(CONFIG),emcc) -CXX = emcc -LD = emcc -CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8" -EMCCFLAGS := -Os -Wno-warn-absolute-paths -EMCCFLAGS += --memory-init-file 0 --embed-file share -s NO_EXIT_RUNTIME=1 -EMCCFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg']" -EMCCFLAGS += -s TOTAL_MEMORY=128*1024*1024 -# https://github.com/kripken/emscripten/blob/master/src/settings.js -CXXFLAGS += $(EMCCFLAGS) -LDFLAGS += $(EMCCFLAGS) -LDLIBS = -EXE = .js - -TARGETS := $(filter-out yosys-config,$(TARGETS)) -EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip - -ifeq ($(ENABLE_ABC),1) -LINK_ABC := 1 -DISABLE_ABC_THREADS := 1 -endif - -viz.js: - wget -O viz.js.part https://github.com/mdaines/viz.js/releases/download/0.0.3/viz.js - mv viz.js.part viz.js - -yosysjs-$(YOSYS_VER).zip: yosys.js viz.js misc/yosysjs/* - rm -rf yosysjs-$(YOSYS_VER) yosysjs-$(YOSYS_VER).zip - mkdir -p yosysjs-$(YOSYS_VER) - cp viz.js misc/yosysjs/* yosys.js yosysjs-$(YOSYS_VER)/ - zip -r yosysjs-$(YOSYS_VER).zip yosysjs-$(YOSYS_VER) - -yosys.html: misc/yosys.html - $(P) cp misc/yosys.html yosys.html - -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++ -LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++ -CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s -LDLIBS := $(filter-out -lrt,$(LDLIBS)) -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" LDFLAGS="-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) -CXX = i686-w64-mingw32-g++ -LD = i686-w64-mingw32-g++ -CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s -LDLIBS := $(filter-out -lrt,$(LDLIBS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" -EXE = .exe - -else ifeq ($(CONFIG),msys2-64) -CXX = x86_64-w64-mingw32-g++ -LD = x86_64-w64-mingw32-g++ -CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s -LDLIBS := $(filter-out -lrt,$(LDLIBS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" -EXE = .exe - -else ifneq ($(CONFIG),none) -$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2, msys2-64) -endif - -ifeq ($(ENABLE_LIBYOSYS),1) -TARGETS += libyosys.so -endif - -ifeq ($(ENABLE_PYOSYS),1) - -#Detect name of boost_python library. Some distros usbe boost_python-py, other boost_python, some only use the major version number, some a concatenation of major and minor version numbers -ifeq ($(OS), Darwin) -BOOST_PYTHON_LIB ?= $(shell \ - if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \ - if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ - if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \ - if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(shell $(PYTHON_EXECUTABLE)-config --ldflags) -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ - echo ""; fi; fi; fi; fi;) -else -BOOST_PYTHON_LIB ?= $(shell \ - if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \ - if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ - if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \ - if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \ - echo ""; fi; fi; fi; fi;) -endif - -ifeq ($(BOOST_PYTHON_LIB),) -$(error BOOST_PYTHON_LIB could not be detected. Please define manualy) -endif - -ifeq ($(OS), Darwin) -ifeq ($(PYTHON_MAJOR_VERSION),3) -LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem -CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON -else -LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem -CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON -endif -else -ifeq ($(PYTHON_MAJOR_VERSION),3) -LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem -CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON -else -LDLIBS += $(shell $(PYTHON_EXECUTABLE)-config --libs) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem -CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON -endif -endif - -ifeq ($(ENABLE_PYOSYS),1) -PY_WRAPPER_FILE = kernel/python_wrappers -OBJS += $(PY_WRAPPER_FILE).o -PY_GEN_SCRIPT= py_wrap_generator -PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()") -endif -endif - -ifeq ($(ENABLE_READLINE),1) -CXXFLAGS += -DYOSYS_ENABLE_READLINE -ifeq ($(OS), FreeBSD) -CXXFLAGS += -I/usr/local/include -endif -LDLIBS += -lreadline -ifeq ($(LINK_CURSES),1) -LDLIBS += -lcurses -ABCMKARGS += "ABC_READLINE_LIBRARIES=-lcurses -lreadline" -endif -ifeq ($(LINK_TERMCAP),1) -LDLIBS += -ltermcap -ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap" -endif -ifeq ($(CONFIG),mxe) -LDLIBS += -ltermcap -endif -else -ifeq ($(ENABLE_EDITLINE),1) -CXXFLAGS += -DYOSYS_ENABLE_EDITLINE -LDLIBS += -ledit -ltinfo -lbsd -else -ABCMKARGS += "ABC_USE_NO_READLINE=1" -endif -endif - -ifeq ($(DISABLE_ABC_THREADS),1) -ABCMKARGS += "ABC_USE_NO_PTHREADS=1" -endif - -ifeq ($(ENABLE_PLUGINS),1) -CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS -LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ifneq ($(OS), FreeBSD) -LDLIBS += -ldl -endif -endif - -ifeq ($(ENABLE_GLOB),1) -CXXFLAGS += -DYOSYS_ENABLE_GLOB -endif - -ifeq ($(ENABLE_TCL),1) -TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") -ifeq ($(OS), FreeBSD) -TCL_INCLUDE ?= /usr/local/include/$(TCL_VERSION) -else -TCL_INCLUDE ?= /usr/include/$(TCL_VERSION) -endif - -ifeq ($(CONFIG),mxe) -CXXFLAGS += -DYOSYS_ENABLE_TCL -LDLIBS += -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 -ifeq ($(OS), FreeBSD) -# FreeBSD uses tcl8.6, but lib is named "libtcl86" -LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION) | tr -d '.') -else -LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION)) -endif -endif -endif - -ifeq ($(ENABLE_GCOV),1) -CXXFLAGS += --coverage -LDFLAGS += --coverage -endif - -ifeq ($(ENABLE_GPROF),1) -CXXFLAGS += -pg -LDFLAGS += -pg -endif - -ifeq ($(ENABLE_NDEBUG),1) -CXXFLAGS := -O3 -DNDEBUG $(filter-out -Os -ggdb,$(CXXFLAGS)) -endif - -ifeq ($(ENABLE_DEBUG),1) -ifeq ($(CONFIG),clang) -CXXFLAGS := -O0 -DDEBUG $(filter-out -Os,$(CXXFLAGS)) -else -CXXFLAGS := -Og -DDEBUG $(filter-out -Os,$(CXXFLAGS)) -endif -endif - -ifeq ($(ENABLE_ABC),1) -CXXFLAGS += -DYOSYS_ENABLE_ABC -ifeq ($(LINK_ABC),1) -CXXFLAGS += -DYOSYS_LINK_ABC -ifeq ($(DISABLE_ABC_THREADS),0) -LDLIBS += -lpthread -endif -else -ifeq ($(ABCEXTERNAL),) -TARGETS += yosys-abc$(EXE) -endif -endif -endif - -ifeq ($(ENABLE_VERIFIC),1) -VERIFIC_DIR ?= /usr/local/src/verific_lib -VERIFIC_COMPONENTS ?= verilog vhdl database util containers hier_tree -CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC -ifeq ($(OS), Darwin) -LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-mac.a,$(VERIFIC_COMPONENTS)) -lz -else -LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -lz -endif -endif - -ifeq ($(ENABLE_PROTOBUF),1) -LDLIBS += $(shell pkg-config --cflags --libs protobuf) -endif - -ifeq ($(ENABLE_COVER),1) -CXXFLAGS += -DYOSYS_ENABLE_COVER -endif - -define add_share_file -EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) -$(subst //,/,$(1)/$(notdir $(2))): $(2) - $$(P) mkdir -p $(1) - $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(notdir $(2))) -endef - -define add_gen_share_file -EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) -$(subst //,/,$(1)/$(notdir $(2))): $(2) - $$(P) mkdir -p $(1) - $$(Q) cp $(2) $(subst //,/,$(1)/$(notdir $(2))) -endef - -define add_include_file -$(eval $(call add_share_file,$(dir share/include/$(1)),$(1))) -endef - -ifeq ($(PRETTY), 1) -P_STATUS = 0 -P_OFFSET = 0 -P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }')) -P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%] -P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@"; -Q = @ -S = -s -else -P_SHOW = -> -P = -Q = -S = -endif - -$(eval $(call add_include_file,kernel/yosys.h)) -$(eval $(call add_include_file,kernel/hashlib.h)) -$(eval $(call add_include_file,kernel/log.h)) -$(eval $(call add_include_file,kernel/rtlil.h)) -$(eval $(call add_include_file,kernel/register.h)) -$(eval $(call add_include_file,kernel/celltypes.h)) -$(eval $(call add_include_file,kernel/celledges.h)) -$(eval $(call add_include_file,kernel/consteval.h)) -$(eval $(call add_include_file,kernel/sigtools.h)) -$(eval $(call add_include_file,kernel/modtools.h)) -$(eval $(call add_include_file,kernel/macc.h)) -$(eval $(call add_include_file,kernel/utils.h)) -$(eval $(call add_include_file,kernel/satgen.h)) -$(eval $(call add_include_file,libs/ezsat/ezsat.h)) -$(eval $(call add_include_file,libs/ezsat/ezminisat.h)) -$(eval $(call add_include_file,libs/sha1/sha1.h)) -$(eval $(call add_include_file,passes/fsm/fsmdata.h)) -$(eval $(call add_include_file,frontends/ast/ast.h)) -$(eval $(call add_include_file,backends/ilang/ilang_backend.h)) - -OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o -OBJS += kernel/cellaigs.o kernel/celledges.o - -kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' -kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' - -OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o -OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o - -OBJS += libs/sha1/sha1.o - -ifneq ($(SMALL),1) - -OBJS += libs/subcircuit/subcircuit.o - -OBJS += libs/ezsat/ezsat.o -OBJS += libs/ezsat/ezminisat.o - -OBJS += libs/minisat/Options.o -OBJS += libs/minisat/SimpSolver.o -OBJS += libs/minisat/Solver.o -OBJS += libs/minisat/System.o - -include $(YOSYS_SRC)/frontends/*/Makefile.inc -include $(YOSYS_SRC)/passes/*/Makefile.inc -include $(YOSYS_SRC)/backends/*/Makefile.inc -include $(YOSYS_SRC)/techlibs/*/Makefile.inc - -else - -include frontends/verilog/Makefile.inc -include frontends/ilang/Makefile.inc -include frontends/ast/Makefile.inc -include frontends/blif/Makefile.inc - -OBJS += passes/hierarchy/hierarchy.o -OBJS += passes/cmds/select.o -OBJS += passes/cmds/show.o -OBJS += passes/cmds/stat.o -OBJS += passes/cmds/cover.o -OBJS += passes/cmds/design.o -OBJS += passes/cmds/plugin.o - -include passes/proc/Makefile.inc -include passes/opt/Makefile.inc -include passes/techmap/Makefile.inc - -include backends/verilog/Makefile.inc -include backends/ilang/Makefile.inc - -include techlibs/common/Makefile.inc - -endif - -ifeq ($(LINK_ABC),1) -OBJS += yosys-libabc.a -endif - -top-all: $(TARGETS) $(EXTRA_TARGETS) - @echo "" - @echo " Build successful." - @echo "" - -ifeq ($(CONFIG),emcc) -yosys.js: $(filter-out yosysjs-$(YOSYS_VER).zip,$(EXTRA_TARGETS)) -endif - -yosys$(EXE): $(OBJS) - $(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS) - -libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) -ifeq ($(OS), Darwin) - $(P) $(LD) -o libyosys.so -shared -Wl,-install_name,libyosys.so $(LDFLAGS) $^ $(LDLIBS) -else - $(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS) -endif - -%.o: %.cc - $(Q) mkdir -p $(dir $@) - $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< - -%.pyh: %.h - $(Q) mkdir -p $(dir $@) - $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P - - -ifeq ($(ENABLE_PYOSYS),1) -$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES) - $(Q) mkdir -p $(dir $@) - $(P) python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")" -endif - -%.o: %.cpp - $(Q) mkdir -p $(dir $@) - $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< - -YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) $(shell \ - $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS))) - -kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile - $(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc - $(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; }" > kernel/version_$(GIT_REV).cc - -ifeq ($(ENABLE_VERIFIC),1) -CXXFLAGS_NOVERIFIC = $(foreach v,$(CXXFLAGS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v))) -LDLIBS_NOVERIFIC = $(foreach v,$(LDLIBS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v))) -else -CXXFLAGS_NOVERIFIC = $(CXXFLAGS) -LDLIBS_NOVERIFIC = $(LDLIBS) -endif - -yosys-config: misc/yosys-config.in - $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC)))#;' \ - -e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LDFLAGS@#$(strip $(LDFLAGS) $(PLUGIN_LDFLAGS))#;' -e 's#@LDLIBS@#$(strip $(LDLIBS_NOVERIFIC))#;' \ - -e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > yosys-config - $(Q) chmod +x yosys-config - -abc/abc-$(ABCREV)$(EXE) abc/libabc-$(ABCREV).a: - $(P) -ifneq ($(ABCREV),default) - $(Q) if test -d abc/.hg; then \ - echo 'REEBE: NOP qverpgbel vf n ut jbexvat pbcl! Erzbir nop/ naq er-eha "znxr".' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \ - fi - $(Q) if ( cd abc 2> /dev/null && ! git diff-index --quiet HEAD; ); then \ - echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \ - fi - $(Q) if test "`cd abc 2> /dev/null && git rev-parse --short HEAD`" != "$(ABCREV)"; then \ - test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ - echo "Pulling ABC from $(ABCURL):"; set -x; \ - test -d abc || git clone $(ABCURL) abc; \ - cd abc && $(MAKE) DEP= clean && git fetch origin master && git checkout $(ABCREV); \ - fi -endif - $(Q) rm -f abc/abc-[0-9a-f]* - $(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc-$(ABCREV)",PROG="abc-$(ABCREV)$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc-$(ABCREV).a) - -ifeq ($(ABCREV),default) -.PHONY: abc/abc-$(ABCREV)$(EXE) -.PHONY: abc/libabc-$(ABCREV).a -endif - -yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE) - $(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE) - -yosys-libabc.a: abc/libabc-$(ABCREV).a - $(P) cp abc/libabc-$(ABCREV).a yosys-libabc.a - -ifneq ($(SEED),) -SEEDOPT="-S $(SEED)" -else -SEEDOPT="" -endif - -ifneq ($(ABCEXTERNAL),) -ABCOPT="-A $(ABCEXTERNAL)" -else -ABCOPT="" -endif - -test: $(TARGETS) $(EXTRA_TARGETS) - +cd tests/simple && 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/fsm && bash run-test.sh $(SEEDOPT) - +cd tests/techmap && bash run-test.sh - +cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT) - +cd tests/bram && bash run-test.sh $(SEEDOPT) - +cd tests/various && bash run-test.sh - +cd tests/sat && bash run-test.sh - +cd tests/svinterfaces && bash run-test.sh $(SEEDOPT) - +cd tests/opt && bash run-test.sh - +cd tests/aiger && bash run-test.sh $(ABCOPT) - +cd tests/arch && bash run-test.sh - @echo "" - @echo " Passed \"make test\"." - @echo "" - -VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all - -vgtest: $(TARGETS) $(EXTRA_TARGETS) - $(VALGRIND) ./yosys -p 'setattr -mod -unset top; synth' $$( ls tests/simple/*.v | grep -v repwhile.v ) - @echo "" - @echo " Passed \"make vgtest\"." - @echo "" - -vloghtb: $(TARGETS) $(EXTRA_TARGETS) - +cd tests/vloghtb && bash run-test.sh - @echo "" - @echo " Passed \"make vloghtb\"." - @echo "" - -ystests: $(TARGETS) $(EXTRA_TARGETS) - rm -rf tests/ystests - git clone -b yosys-0.9-rc https://github.com/YosysHQ/yosys-tests.git tests/ystests - +$(MAKE) PATH="$$PWD:$$PATH" -C tests/ystests - @echo "" - @echo " Finished \"make ystests\"." - @echo "" - -# Unit test -unit-test: libyosys.so - @$(MAKE) -C $(UNITESTPATH) CXX="$(CXX)" CPPFLAGS="$(CPPFLAGS)" \ - CXXFLAGS="$(CXXFLAGS)" LDLIBS="$(LDLIBS)" ROOTPATH="$(CURDIR)" - -clean-unit-test: - @$(MAKE) -C $(UNITESTPATH) clean - -install: $(TARGETS) $(EXTRA_TARGETS) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) - $(INSTALL_SUDO) cp $(TARGETS) $(DESTDIR)$(BINDIR) -ifneq ($(filter yosys,$(TARGETS)),) - $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/yosys -endif -ifneq ($(filter yosys-abc,$(TARGETS)),) - $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/yosys-abc -endif -ifneq ($(filter yosys-filterlib,$(TARGETS)),) - $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/yosys-filterlib -endif - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) - $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. -ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) - $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/ - $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so -ifeq ($(ENABLE_PYOSYS),1) - $(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys - $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/ - $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/ -endif -endif - -uninstall: - $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR)/,$(notdir $(TARGETS))) - $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) -ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so -ifeq ($(ENABLE_PYOSYS),1) - $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/libyosys.so - $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/__init__.py - $(INSTALL_SUDO) rmdir $(PYTHON_DESTDIR)/pyosys -endif -endif - -update-manual: $(TARGETS) $(EXTRA_TARGETS) - cd manual && ../yosys -p 'help -write-tex-command-reference-manual' - -manual: $(TARGETS) $(EXTRA_TARGETS) - cd manual && bash appnotes.sh - cd manual && bash presentation.sh - cd manual && bash manual.sh - -clean: - rm -rf share - rm -rf kernel/*.pyh - if test -d manual; then cd manual && sh clean.sh; fi - rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc - rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a - rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d - rm -rf tests/asicworld/*.out tests/asicworld/*.log - rm -rf tests/hana/*.out tests/hana/*.log - rm -rf tests/simple/*.out tests/simple/*.log - rm -rf tests/memories/*.out tests/memories/*.log tests/memories/*.dmp - rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log - rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp - rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_* - rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff - rm -f tests/tools/cmp_tbdata - -clean-abc: - $(MAKE) -C abc DEP= clean - rm -f yosys-abc$(EXE) yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a - -mrproper: clean - git clean -xdf - -coverage: - ./yosys -qp 'help; help -all' - rm -rf coverage.info coverage_html - lcov --capture -d . --no-external -o coverage.info - genhtml coverage.info --output-directory coverage_html - -qtcreator: - { for file in $(basename $(OBJS)); do \ - for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \ - done; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \); } > qtcreator.files - { echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes - touch qtcreator.config qtcreator.creator - -vcxsrc: $(GENFILES) $(EXTRA_TARGETS) - rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip} - set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \ - echo "Analyse: $$f" >&2; cpp -std=c++11 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt - bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV) - echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc - zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc - 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 yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/ -ifeq ($(ENABLE_ABC),1) - cp -r 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 http://www.clifford.at/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 - -config-clang: clean - echo 'CONFIG := clang' > Makefile.conf - -config-gcc: clean - echo 'CONFIG := gcc' > Makefile.conf - -config-gcc-static: clean - echo 'CONFIG := gcc-static' > Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - echo 'ENABLE_READLINE := 0' >> Makefile.conf - echo 'ENABLE_TCL := 0' >> Makefile.conf - -config-gcc-4.8: clean - echo 'CONFIG := gcc-4.8' > Makefile.conf - -config-afl-gcc: clean - echo 'CONFIG := afl-gcc' > Makefile.conf - -config-emcc: clean - echo 'CONFIG := emcc' > Makefile.conf - echo 'ENABLE_TCL := 0' >> Makefile.conf - echo 'ENABLE_ABC := 0' >> Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - echo 'ENABLE_READLINE := 0' >> Makefile.conf - -config-mxe: clean - echo 'CONFIG := mxe' > Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - -config-msys2: clean - echo 'CONFIG := msys2' > Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - -config-msys2-64: clean - echo 'CONFIG := msys2-64' > Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - -config-cygwin: clean - echo 'CONFIG := cygwin' > Makefile.conf - -config-gcov: clean - echo 'CONFIG := gcc' > Makefile.conf - echo 'ENABLE_GCOV := 1' >> Makefile.conf - echo 'ENABLE_DEBUG := 1' >> Makefile.conf - -config-gprof: clean - echo 'CONFIG := gcc' > Makefile.conf - echo 'ENABLE_GPROF := 1' >> Makefile.conf - -config-sudo: - echo "INSTALL_SUDO := sudo" >> Makefile.conf - -echo-yosys-ver: - @echo "$(YOSYS_VER)" - -echo-git-rev: - @echo "$(GIT_REV)" - --include libs/*/*.d --include frontends/*/*.d --include passes/*/*.d --include backends/*/*.d --include kernel/*.d --include techlibs/*/*.d - -.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator coverage vcxsrc mxebin -.PHONY: config-clean config-clang config-gcc config-gcc-static config-gcc-4.8 config-afl-gcc config-gprof config-sudo - diff --git a/yosys/README.md b/yosys/README.md deleted file mode 100644 index 5132332a5..000000000 --- a/yosys/README.md +++ /dev/null @@ -1,538 +0,0 @@ -``` -yosys -- Yosys Open SYnthesis Suite - -Copyright (C) 2012 - 2019 Clifford Wolf - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -``` - - -yosys – Yosys Open SYnthesis Suite -=================================== - -This is a framework for RTL synthesis tools. It currently has -extensive Verilog-2005 support and provides a basic set of -synthesis algorithms for various application domains. - -Yosys can be adapted to perform any synthesis job by combining -the existing passes (algorithms) using synthesis scripts and -adding additional passes as needed by extending the yosys C++ -code base. - -Yosys is free software licensed under the ISC license (a GPL -compatible license that is similar in terms to the MIT license -or the 2-clause BSD license). - - -Web Site and Other Resources -============================ - -More information and documentation can be found on the Yosys web site: -- http://www.clifford.at/yosys/ - -The "Documentation" page on the web site contains links to more resources, -including a manual that even describes some of the Yosys internals: -- http://www.clifford.at/yosys/documentation.html - -The file `CodingReadme` in this directory contains additional information -for people interested in using the Yosys C++ APIs. - -Users interested in formal verification might want to use the formal verification -front-end for Yosys, SymbiYosys: -- https://symbiyosys.readthedocs.io/en/latest/ -- https://github.com/YosysHQ/SymbiYosys - - -Setup -====== - -You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is -recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make. -TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile). -Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. - -For example on Ubuntu Linux 16.04 LTS the following commands will install all -prerequisites for building yosys: - - $ sudo apt-get install build-essential clang bison flex \ - libreadline-dev gawk tcl-dev libffi-dev git \ - graphviz xdot pkg-config python3 libboost-system-dev \ - libboost-python-dev libboost-filesystem-dev - -Similarily, on Mac OS X Homebrew can be used to install dependencies: - - $ brew tap Homebrew/bundle && brew bundle - -or MacPorts: - - $ sudo port install bison flex readline gawk libffi \ - git graphviz pkgconfig python36 boost tcl - -On FreeBSD use the following command to install all prerequisites: - - # pkg install bison flex readline gawk libffi\ - git graphviz pkgconfig python3 python36 tcl-wrapper boost-libs - -On FreeBSD system use gmake instead of make. To run tests use: - % MAKE=gmake CC=cc gmake test - -For Cygwin use the following command to install all prerequisites, or select these additional packages: - - setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build - -There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well -as a source distribution for Visual Studio. Visit the Yosys download page for -more information: http://www.clifford.at/yosys/download.html - -To configure the build system to use a specific compiler, use one of - - $ make config-clang - $ make config-gcc - -For other compilers and build configurations it might be -necessary to make some changes to the config section of the -Makefile. - - $ vi Makefile # ..or.. - $ vi Makefile.conf - -To build Yosys simply type 'make' in this directory. - - $ make - $ sudo make install - -Note that this also downloads, builds and installs ABC (using yosys-abc -as executable name). - -Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via: - - $ make test - -Getting Started -=============== - -Yosys can be used with the interactive command shell, with -synthesis scripts or with command line arguments. Let's perform -a simple synthesis job using the interactive command shell: - - $ ./yosys - yosys> - -the command ``help`` can be used to print a list of all available -commands and ``help `` to print details on the specified command: - - yosys> help help - -reading the design using the Verilog frontend: - - yosys> read_verilog tests/simple/fiedler-cooley.v - -writing the design to the console in Yosys's internal format: - - yosys> write_ilang - -elaborate design hierarchy: - - yosys> hierarchy - -convert processes (``always`` blocks) to netlist elements and perform -some simple optimizations: - - yosys> proc; opt - -display design netlist using ``xdot``: - - yosys> show - -the same thing using ``gv`` as postscript viewer: - - yosys> show -format ps -viewer gv - -translating netlist to gate logic and perform some simple optimizations: - - yosys> techmap; opt - -write design netlist to a new Verilog file: - - yosys> write_verilog synth.v - -a similar synthesis can be performed using yosys command line options only: - - $ ./yosys -o synth.v -p hierarchy -p proc -p opt \ - -p techmap -p opt tests/simple/fiedler-cooley.v - -or using a simple synthesis script: - - $ cat synth.ys - read_verilog tests/simple/fiedler-cooley.v - hierarchy; proc; opt; techmap; opt - write_verilog synth.v - - $ ./yosys synth.ys - -It is also possible to only have the synthesis commands but not the read/write -commands in the synthesis script: - - $ cat synth.ys - hierarchy; proc; opt; techmap; opt - - $ ./yosys -o synth.v tests/simple/fiedler-cooley.v synth.ys - -The following very basic synthesis script should work well with all designs: - - # check design hierarchy - hierarchy - - # translate processes (always blocks) - proc; opt - - # detect and optimize FSM encodings - fsm; opt - - # implement memories (arrays) - memory; opt - - # convert to gate logic - techmap; opt - -If ABC is enabled in the Yosys build configuration and a cell library is given -in the liberty file ``mycells.lib``, the following synthesis script will -synthesize for the given cell library: - - # the high-level stuff - hierarchy; proc; fsm; opt; memory; opt - - # mapping to internal cell library - techmap; opt - - # mapping flip-flops to mycells.lib - dfflibmap -liberty mycells.lib - - # mapping logic to mycells.lib - abc -liberty mycells.lib - - # cleanup - clean - -If you do not have a liberty file but want to test this synthesis script, -you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources. - -Liberty file downloads for and information about free and open ASIC standard -cell libraries can be found here: - -- http://www.vlsitechnology.org/html/libraries.html -- http://www.vlsitechnology.org/synopsys/vsclib013.lib - -The command ``synth`` provides a good default synthesis script (see -``help synth``). If possible a synthesis script should borrow from ``synth``. -For example: - - # the high-level stuff - hierarchy - synth -run coarse - - # mapping to internal cells - techmap; opt -fast - dfflibmap -liberty mycells.lib - abc -liberty mycells.lib - clean - -Yosys is under construction. A more detailed documentation will follow. - - -Unsupported Verilog-2005 Features -================================= - -The following Verilog-2005 features are not supported by -Yosys and there are currently no plans to add support -for them: - -- Non-synthesizable language features as defined in - IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002 - -- The ``tri``, ``triand`` and ``trior`` net types - -- The ``config`` and ``disable`` keywords and library map files - - -Verilog Attributes and non-standard features -============================================ - -- The ``full_case`` attribute on case statements is supported - (also the non-standard ``// synopsys full_case`` directive) - -- The ``parallel_case`` attribute on case statements is supported - (also the non-standard ``// synopsys parallel_case`` directive) - -- The ``// synopsys translate_off`` and ``// synopsys translate_on`` - directives are also supported (but the use of ``` `ifdef .. `endif ``` - is strongly recommended instead). - -- The ``nomem2reg`` attribute on modules or arrays prohibits the - automatic early conversion of arrays to separate registers. This - is potentially dangerous. Usually the front-end has good reasons - for converting an array to a list of registers. Prohibiting this - step will likely result in incorrect synthesis results. - -- The ``mem2reg`` attribute on modules or arrays forces the early - conversion of arrays to separate registers. - -- The ``nomeminit`` attribute on modules or arrays prohibits the - creation of initialized memories. This effectively puts ``mem2reg`` - on all memories that are written to in an ``initial`` block and - are not ROMs. - -- The ``nolatches`` attribute on modules or always-blocks - prohibits the generation of logic-loops for latches. Instead - all not explicitly assigned values default to x-bits. This does - not affect clocked storage elements such as flip-flops. - -- The ``nosync`` attribute on registers prohibits the generation of a - storage element. The register itself will always have all bits set - to 'x' (undefined). The variable may only be used as blocking assigned - temporary variable within an always block. This is mostly used internally - by Yosys to synthesize Verilog functions and access arrays. - -- The ``onehot`` attribute on wires mark them as one-hot state register. This - is used for example for memory port sharing and set by the fsm_map pass. - -- The ``blackbox`` attribute on modules is used to mark empty stub modules - that have the same ports as the real thing but do not contain information - on the internal configuration. This modules are only used by the synthesis - passes to identify input and output ports of cells. The Verilog backend - also does not output blackbox modules on default. ``read_verilog``, unless - called with ``-noblackbox`` will automatically set the blackbox attribute - on any empty module it reads. - -- The ``noblackbox`` attribute set on an empty module prevents ``read_verilog`` - from automatically setting the blackbox attribute on the module. - -- The ``whitebox`` attribute on modules triggers the same behavior as - ``blackbox``, but is for whitebox modules, i.e. library modules that - contain a behavioral model of the cell type. - -- The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog`` - is run in `-lib` mode. Otherwise it's automatically removed. - -- The ``dynports`` attribute is used by the Verilog front-end to mark modules - that have ports with a width that depends on a parameter. - -- The ``hdlname`` attribute is used by some passes to document the original - (HDL) name of a module when renaming a module. - -- The ``keep`` attribute on cells and wires is used to mark objects that should - never be removed by the optimizer. This is used for example for cells that - have hidden connections that are not part of the netlist, such as IO pads. - Setting the ``keep`` attribute on a module has the same effect as setting it - on all instances of the module. - -- The ``keep_hierarchy`` attribute on cells and modules keeps the ``flatten`` - command from flattening the indicated cells and modules. - -- The ``init`` attribute on wires is set by the frontend when a register is - initialized "FPGA-style" with ``reg foo = val``. It can be used during - synthesis to add the necessary reset logic. - -- The ``top`` attribute on a module marks this module as the top of the - design hierarchy. The ``hierarchy`` command sets this attribute when called - with ``-top``. Other commands, such as ``flatten`` and various backends - use this attribute to determine the top module. - -- The ``src`` attribute is set on cells and wires created by to the string - ``:`` by the HDL front-end and is then carried - through the synthesis. When entities are combined, a new |-separated - string is created that contains all the string from the original entities. - -- The ``defaultvalue`` attribute is used to store default values for - module inputs. The attribute is attached to the input wire by the HDL - front-end when the input is declared with a default value. - -- The ``parameter`` and ``localparam`` attributes are used to mark wires - that represent module parameters or localparams (when the HDL front-end - is run in -pwires mode). - -- In addition to the ``(* ... *)`` attribute syntax, Yosys supports - the non-standard ``{* ... *}`` attribute syntax to set default attributes - for everything that comes after the ``{* ... *}`` statement. (Reset - by adding an empty ``{* *}`` statement.) - -- In module parameter and port declarations, and cell port and parameter - lists, a trailing comma is ignored. This simplifies writing Verilog code - generators a bit in some cases. - -- Modules can be declared with ``module mod_name(...);`` (with three dots - instead of a list of module ports). With this syntax it is sufficient - to simply declare a module port as 'input' or 'output' in the module - body. - -- When defining a macro with `define, all text between triple double quotes - is interpreted as macro body, even if it contains unescaped newlines. The - triple double quotes are removed from the macro body. For example: - - `define MY_MACRO(a, b) """ - assign a = 23; - assign b = 42; - """ - -- The attribute ``via_celltype`` can be used to implement a Verilog task or - function by instantiating the specified cell type. The value is the name - of the cell type to use. For functions the name of the output port can - be specified by appending it to the cell type separated by a whitespace. - The body of the task or function is unused in this case and can be used - to specify a behavioral model of the cell type for simulation. For example: - - module my_add3(A, B, C, Y); - parameter WIDTH = 8; - input [WIDTH-1:0] A, B, C; - output [WIDTH-1:0] Y; - ... - endmodule - - module top; - ... - (* via_celltype = "my_add3 Y" *) - (* via_celltype_defparam_WIDTH = 32 *) - function [31:0] add3; - input [31:0] A, B, C; - begin - add3 = A + B + C; - end - endfunction - ... - endmodule - -- A limited subset of DPI-C functions is supported. The plugin mechanism - (see ``help plugin``) can be used to load .so files with implementations - of DPI-C routines. As a non-standard extension it is possible to specify - a plugin alias using the ``:`` syntax. For example: - - module dpitest; - import "DPI-C" function foo:round = real my_round (real); - parameter real r = my_round(12.345); - endmodule - - $ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v' - -- Sized constants (the syntax ``'s?[bodh]``) support constant - expressions as ````. If the expression is not a simple identifier, it - must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010`` - -- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in - initial blocks in an unconditional context (only if/case statements on - expressions over parameters and constant values are allowed). The intended - use for this is synthesis-time DRC. - -- There is limited support for converting specify .. endspecify statements to - special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in - blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this - functionality. (By default specify .. endspecify blocks are ignored.) - - -Non-standard or SystemVerilog features for formal verification -============================================================== - -- Support for ``assert``, ``assume``, ``restrict``, and ``cover`` is enabled - when ``read_verilog`` is called with ``-formal``. - -- The system task ``$initstate`` evaluates to 1 in the initial state and - to 0 otherwise. - -- The system function ``$anyconst`` evaluates to any constant value. This is - equivalent to declaring a reg as ``rand const``, but also works outside - of checkers. (Yosys also supports ``rand const`` outside checkers.) - -- The system function ``$anyseq`` evaluates to any value, possibly a different - value in each cycle. This is equivalent to declaring a reg as ``rand``, - but also works outside of checkers. (Yosys also supports ``rand`` - variables outside checkers.) - -- The system functions ``$allconst`` and ``$allseq`` can be used to construct - formal exist-forall problems. Assumptions only hold if the trace satisfies - the assumption for all ``$allconst/$allseq`` values. For assertions and cover - statements it is sufficient if just one ``$allconst/$allseq`` value triggers - the property (similar to ``$anyconst/$anyseq``). - -- Wires/registers declared using the ``anyconst/anyseq/allconst/allseq`` attribute - (for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven - by a ``$anyconst/$anyseq/$allconst/$allseq`` function. - -- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are - supported in any clocked block. - -- The syntax ``@($global_clock)`` can be used to create FFs that have no - explicit clock input (``$ff`` cells). The same can be achieved by using - ``@(posedge )`` or ``@(negedge )`` when ```` - is marked with the ``(* gclk *)`` Verilog attribute. - - -Supported features from SystemVerilog -===================================== - -When ``read_verilog`` is called with ``-sv``, it accepts some language features -from SystemVerilog: - -- The ``assert`` statement from SystemVerilog is supported in its most basic - form. In module context: ``assert property ();`` and within an - always block: ``assert();``. It is transformed to an ``$assert`` cell. - -- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are - also supported. The same limitations as with the ``assert`` statement apply. - -- The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic`` - and ``bit`` are supported. - -- Declaring free variables with ``rand`` and ``rand const`` is supported. - -- Checkers without a port list that do not need to be instantiated (but instead - behave like a named block) are supported. - -- SystemVerilog packages are supported. Once a SystemVerilog file is read - into a design with ``read_verilog``, all its packages are available to - SystemVerilog files being read into the same design afterwards. - -- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether - ports are inputs or outputs are supported. - - -Building the documentation -========================== - -Note that there is no need to build the manual if you just want to read it. -Simply download the PDF from http://www.clifford.at/yosys/documentation.html -instead. - -On Ubuntu, texlive needs these packages to be able to build the manual: - - sudo apt-get install texlive-binaries - sudo apt-get install texlive-science # install algorithm2e.sty - sudo apt-get install texlive-bibtex-extra # gets multibib.sty - sudo apt-get install texlive-fonts-extra # gets skull.sty and dsfont.sty - sudo apt-get install texlive-publishers # IEEEtran.cls - -Also the non-free font luximono should be installed, there is unfortunately -no Ubuntu package for this so it should be installed separately using -`getnonfreefonts`: - - wget https://tug.org/fonts/getnonfreefonts/install-getnonfreefonts - sudo texlua install-getnonfreefonts # will install to /usr/local by default, can be changed by editing BINDIR at MANDIR at the top of the script - getnonfreefonts luximono # installs to /home/user/texmf - -Then execute, from the root of the repository: - - make manual - -Notes: - -- To run `make manual` you need to have installed Yosys with `make install`, - otherwise it will fail on finding `kernel/yosys.h` while building - `PRESENTATION_Prog`. diff --git a/yosys/backends/aiger/Makefile.inc b/yosys/backends/aiger/Makefile.inc deleted file mode 100644 index 0fc37e95c..000000000 --- a/yosys/backends/aiger/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/aiger/aiger.o - diff --git a/yosys/backends/aiger/aiger.cc b/yosys/backends/aiger/aiger.cc deleted file mode 100644 index 6863b40fa..000000000 --- a/yosys/backends/aiger/aiger.cc +++ /dev/null @@ -1,790 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -void aiger_encode(std::ostream &f, int x) -{ - log_assert(x >= 0); - - while (x & ~0x7f) { - f.put((x & 0x7f) | 0x80); - x = x >> 7; - } - - f.put(x); -} - -struct AigerWriter -{ - Module *module; - bool zinit_mode; - SigMap sigmap; - - dict init_map; - pool input_bits, output_bits; - dict not_map, ff_map, alias_map; - dict> and_map; - vector> asserts, assumes; - vector> liveness, fairness; - pool initstate_bits; - - vector> aig_gates; - vector aig_latchin, aig_latchinit, aig_outputs; - int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0; - int aig_b = 0, aig_c = 0, aig_j = 0, aig_f = 0; - - dict aig_map; - dict ordered_outputs; - dict ordered_latches; - - dict init_inputs; - int initstate_ff = 0; - - int mkgate(int a0, int a1) - { - aig_m++, aig_a++; - aig_gates.push_back(a0 > a1 ? make_pair(a0, a1) : make_pair(a1, a0)); - return 2*aig_m; - } - - int bit2aig(SigBit bit) - { - if (aig_map.count(bit) == 0) - { - aig_map[bit] = -1; - - if (initstate_bits.count(bit)) { - log_assert(initstate_ff > 0); - aig_map[bit] = initstate_ff; - } else - if (not_map.count(bit)) { - int a = bit2aig(not_map.at(bit)) ^ 1; - aig_map[bit] = a; - } else - if (and_map.count(bit)) { - auto args = and_map.at(bit); - int a0 = bit2aig(args.first); - int a1 = bit2aig(args.second); - aig_map[bit] = mkgate(a0, a1); - } else - if (alias_map.count(bit)) { - int a = bit2aig(alias_map.at(bit)); - aig_map[bit] = a; - } - - if (bit == State::Sx || bit == State::Sz) - log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n"); - } - - log_assert(aig_map.at(bit) >= 0); - return aig_map.at(bit); - } - - AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module) - { - pool undriven_bits; - pool unused_bits; - - // promote public wires - for (auto wire : module->wires()) - if (wire->name[0] == '\\') - sigmap.add(wire); - - // promote input wires - for (auto wire : module->wires()) - if (wire->port_input) - sigmap.add(wire); - - // promote output wires - for (auto wire : module->wires()) - if (wire->port_output) - sigmap.add(wire); - - for (auto wire : module->wires()) - { - if (wire->attributes.count("\\init")) { - SigSpec initsig = sigmap(wire); - Const initval = wire->attributes.at("\\init"); - for (int i = 0; i < GetSize(wire) && i < GetSize(initval); i++) - if (initval[i] == State::S0 || initval[i] == State::S1) - init_map[initsig[i]] = initval[i] == State::S1; - } - - for (int i = 0; i < GetSize(wire); i++) - { - SigBit wirebit(wire, i); - SigBit bit = sigmap(wirebit); - - if (bit.wire == nullptr) { - if (wire->port_output) { - aig_map[wirebit] = (bit == State::S1) ? 1 : 0; - output_bits.insert(wirebit); - } - continue; - } - - undriven_bits.insert(bit); - unused_bits.insert(bit); - - if (wire->port_input) - input_bits.insert(bit); - - if (wire->port_output) { - if (bit != wirebit) - alias_map[wirebit] = bit; - output_bits.insert(wirebit); - } - } - } - - for (auto bit : input_bits) - undriven_bits.erase(bit); - - for (auto bit : output_bits) - unused_bits.erase(bit); - - for (auto cell : module->cells()) - { - if (cell->type == "$_NOT_") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - unused_bits.erase(A); - undriven_bits.erase(Y); - not_map[Y] = A; - continue; - } - - if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_")) - { - SigBit D = sigmap(cell->getPort("\\D").as_bit()); - SigBit Q = sigmap(cell->getPort("\\Q").as_bit()); - unused_bits.erase(D); - undriven_bits.erase(Q); - ff_map[Q] = D; - continue; - } - - if (cell->type == "$_AND_") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit B = sigmap(cell->getPort("\\B").as_bit()); - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - unused_bits.erase(A); - unused_bits.erase(B); - undriven_bits.erase(Y); - and_map[Y] = make_pair(A, B); - continue; - } - - if (cell->type == "$initstate") - { - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - undriven_bits.erase(Y); - initstate_bits.insert(Y); - continue; - } - - if (cell->type == "$assert") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit EN = sigmap(cell->getPort("\\EN").as_bit()); - unused_bits.erase(A); - unused_bits.erase(EN); - asserts.push_back(make_pair(A, EN)); - continue; - } - - if (cell->type == "$assume") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit EN = sigmap(cell->getPort("\\EN").as_bit()); - unused_bits.erase(A); - unused_bits.erase(EN); - assumes.push_back(make_pair(A, EN)); - continue; - } - - if (cell->type == "$live") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit EN = sigmap(cell->getPort("\\EN").as_bit()); - unused_bits.erase(A); - unused_bits.erase(EN); - liveness.push_back(make_pair(A, EN)); - continue; - } - - if (cell->type == "$fair") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit EN = sigmap(cell->getPort("\\EN").as_bit()); - unused_bits.erase(A); - unused_bits.erase(EN); - fairness.push_back(make_pair(A, EN)); - continue; - } - - if (cell->type == "$anyconst") - { - for (auto bit : sigmap(cell->getPort("\\Y"))) { - undriven_bits.erase(bit); - ff_map[bit] = bit; - } - continue; - } - - if (cell->type == "$anyseq") - { - for (auto bit : sigmap(cell->getPort("\\Y"))) { - undriven_bits.erase(bit); - input_bits.insert(bit); - } - continue; - } - - log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); - } - - for (auto bit : unused_bits) - undriven_bits.erase(bit); - - if (!undriven_bits.empty()) { - undriven_bits.sort(); - for (auto bit : undriven_bits) { - log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit)); - input_bits.insert(bit); - } - log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module)); - } - - init_map.sort(); - input_bits.sort(); - output_bits.sort(); - not_map.sort(); - ff_map.sort(); - and_map.sort(); - - aig_map[State::S0] = 0; - aig_map[State::S1] = 1; - - for (auto bit : input_bits) { - aig_m++, aig_i++; - aig_map[bit] = 2*aig_m; - } - - if (imode && input_bits.empty()) { - aig_m++, aig_i++; - } - - if (zinit_mode) - { - for (auto it : ff_map) { - if (init_map.count(it.first)) - continue; - aig_m++, aig_i++; - init_inputs[it.first] = 2*aig_m; - } - } - - int fair_live_inputs_cnt = GetSize(liveness); - int fair_live_inputs_m = aig_m; - - aig_m += fair_live_inputs_cnt; - aig_i += fair_live_inputs_cnt; - - for (auto it : ff_map) { - aig_m++, aig_l++; - aig_map[it.first] = 2*aig_m; - ordered_latches[it.first] = aig_l-1; - if (init_map.count(it.first) == 0) - aig_latchinit.push_back(2); - else - aig_latchinit.push_back(init_map.at(it.first) ? 1 : 0); - } - - if (!initstate_bits.empty() || !init_inputs.empty()) { - aig_m++, aig_l++; - initstate_ff = 2*aig_m+1; - aig_latchinit.push_back(0); - } - - int fair_live_latches_cnt = GetSize(fairness) + 2*GetSize(liveness); - int fair_live_latches_m = aig_m; - int fair_live_latches_l = aig_l; - - aig_m += fair_live_latches_cnt; - aig_l += fair_live_latches_cnt; - - for (int i = 0; i < fair_live_latches_cnt; i++) - aig_latchinit.push_back(0); - - if (zinit_mode) - { - for (auto it : ff_map) - { - int l = ordered_latches[it.first]; - - if (aig_latchinit.at(l) == 1) - aig_map[it.first] ^= 1; - - if (aig_latchinit.at(l) == 2) - { - int gated_ffout = mkgate(aig_map[it.first], initstate_ff^1); - int gated_initin = mkgate(init_inputs[it.first], initstate_ff); - aig_map[it.first] = mkgate(gated_ffout^1, gated_initin^1)^1; - } - } - } - - for (auto it : ff_map) { - int a = bit2aig(it.second); - int l = ordered_latches[it.first]; - if (zinit_mode && aig_latchinit.at(l) == 1) - aig_latchin.push_back(a ^ 1); - else - aig_latchin.push_back(a); - } - - if (!initstate_bits.empty() || !init_inputs.empty()) - aig_latchin.push_back(1); - - for (auto bit : output_bits) { - aig_o++; - ordered_outputs[bit] = aig_o-1; - aig_outputs.push_back(bit2aig(bit)); - } - - if (omode && output_bits.empty()) { - aig_o++; - aig_outputs.push_back(0); - } - - for (auto it : asserts) { - aig_b++; - int bit_a = bit2aig(it.first); - int bit_en = bit2aig(it.second); - aig_outputs.push_back(mkgate(bit_a^1, bit_en)); - } - - if (bmode && asserts.empty()) { - aig_b++; - aig_outputs.push_back(0); - } - - for (auto it : assumes) { - aig_c++; - int bit_a = bit2aig(it.first); - int bit_en = bit2aig(it.second); - aig_outputs.push_back(mkgate(bit_a^1, bit_en)^1); - } - - for (auto it : liveness) - { - int input_m = ++fair_live_inputs_m; - int latch_m1 = ++fair_live_latches_m; - int latch_m2 = ++fair_live_latches_m; - - log_assert(GetSize(aig_latchin) == fair_live_latches_l); - fair_live_latches_l += 2; - - int bit_a = bit2aig(it.first); - int bit_en = bit2aig(it.second); - int bit_s = 2*input_m; - int bit_q1 = 2*latch_m1; - int bit_q2 = 2*latch_m2; - - int bit_d1 = mkgate(mkgate(bit_s, bit_en)^1, bit_q1^1)^1; - int bit_d2 = mkgate(mkgate(bit_d1, bit_a)^1, bit_q2^1)^1; - - aig_j++; - aig_latchin.push_back(bit_d1); - aig_latchin.push_back(bit_d2); - aig_outputs.push_back(mkgate(bit_q1, bit_q2^1)); - } - - for (auto it : fairness) - { - int latch_m = ++fair_live_latches_m; - - log_assert(GetSize(aig_latchin) == fair_live_latches_l); - fair_live_latches_l += 1; - - int bit_a = bit2aig(it.first); - int bit_en = bit2aig(it.second); - int bit_q = 2*latch_m; - - aig_f++; - aig_latchin.push_back(mkgate(mkgate(bit_q^1, bit_en^1)^1, bit_a^1)); - aig_outputs.push_back(bit_q^1); - } - } - - void write_aiger(std::ostream &f, bool ascii_mode, bool miter_mode, bool symbols_mode) - { - int aig_obc = aig_o + aig_b + aig_c; - int aig_obcj = aig_obc + aig_j; - int aig_obcjf = aig_obcj + aig_f; - - log_assert(aig_m == aig_i + aig_l + aig_a); - log_assert(aig_l == GetSize(aig_latchin)); - log_assert(aig_l == GetSize(aig_latchinit)); - log_assert(aig_obcjf == GetSize(aig_outputs)); - - if (miter_mode) { - if (aig_b || aig_c || aig_j || aig_f) - log_error("Running AIGER back-end in -miter mode, but design contains $assert, $assume, $live and/or $fair cells!\n"); - f << stringf("%s %d %d %d 0 %d %d\n", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_a, aig_o); - } else { - f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a); - if (aig_b || aig_c || aig_j || aig_f) - f << stringf(" %d %d %d %d", aig_b, aig_c, aig_j, aig_f); - f << stringf("\n"); - } - - if (ascii_mode) - { - for (int i = 0; i < aig_i; i++) - f << stringf("%d\n", 2*i+2); - - for (int i = 0; i < aig_l; i++) { - if (zinit_mode || aig_latchinit.at(i) == 0) - f << stringf("%d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i)); - else if (aig_latchinit.at(i) == 1) - f << stringf("%d %d 1\n", 2*(aig_i+i)+2, aig_latchin.at(i)); - else if (aig_latchinit.at(i) == 2) - f << stringf("%d %d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i), 2*(aig_i+i)+2); - } - - for (int i = 0; i < aig_obc; i++) - f << stringf("%d\n", aig_outputs.at(i)); - - for (int i = aig_obc; i < aig_obcj; i++) - f << stringf("1\n"); - - for (int i = aig_obc; i < aig_obcj; i++) - f << stringf("%d\n", aig_outputs.at(i)); - - for (int i = aig_obcj; i < aig_obcjf; i++) - f << stringf("%d\n", aig_outputs.at(i)); - - for (int i = 0; i < aig_a; i++) - f << stringf("%d %d %d\n", 2*(aig_i+aig_l+i)+2, aig_gates.at(i).first, aig_gates.at(i).second); - } - else - { - for (int i = 0; i < aig_l; i++) { - if (zinit_mode || aig_latchinit.at(i) == 0) - f << stringf("%d\n", aig_latchin.at(i)); - else if (aig_latchinit.at(i) == 1) - f << stringf("%d 1\n", aig_latchin.at(i)); - else if (aig_latchinit.at(i) == 2) - f << stringf("%d %d\n", aig_latchin.at(i), 2*(aig_i+i)+2); - } - - for (int i = 0; i < aig_obc; i++) - f << stringf("%d\n", aig_outputs.at(i)); - - for (int i = aig_obc; i < aig_obcj; i++) - f << stringf("1\n"); - - for (int i = aig_obc; i < aig_obcj; i++) - f << stringf("%d\n", aig_outputs.at(i)); - - for (int i = aig_obcj; i < aig_obcjf; i++) - f << stringf("%d\n", aig_outputs.at(i)); - - for (int i = 0; i < aig_a; i++) { - int lhs = 2*(aig_i+aig_l+i)+2; - int rhs0 = aig_gates.at(i).first; - int rhs1 = aig_gates.at(i).second; - int delta0 = lhs - rhs0; - int delta1 = rhs0 - rhs1; - aiger_encode(f, delta0); - aiger_encode(f, delta1); - } - } - - if (symbols_mode) - { - dict> symbols; - - for (auto wire : module->wires()) - { - if (wire->name[0] == '$') - continue; - - SigSpec sig = sigmap(wire); - - for (int i = 0; i < GetSize(wire); i++) - { - if (sig[i].wire == nullptr) { - if (wire->port_output) - sig[i] = SigBit(wire, i); - else - continue; - } - - if (wire->port_input) { - int a = aig_map.at(sig[i]); - log_assert((a & 1) == 0); - if (GetSize(wire) != 1) - symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s[%d]", log_id(wire), i)); - else - symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s", log_id(wire))); - } - - if (wire->port_output) { - int o = ordered_outputs.at(SigSpec(wire, i)); - if (GetSize(wire) != 1) - symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", log_id(wire), i)); - else - symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", log_id(wire))); - } - - if (init_inputs.count(sig[i])) { - int a = init_inputs.at(sig[i]); - log_assert((a & 1) == 0); - if (GetSize(wire) != 1) - symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", log_id(wire), i)); - else - symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", log_id(wire))); - } - - if (ordered_latches.count(sig[i])) { - int l = ordered_latches.at(sig[i]); - const char *p = (zinit_mode && (aig_latchinit.at(l) == 1)) ? "!" : ""; - if (GetSize(wire) != 1) - symbols[stringf("l%d", l)].push_back(stringf("%s%s[%d]", p, log_id(wire), i)); - else - symbols[stringf("l%d", l)].push_back(stringf("%s%s", p, log_id(wire))); - } - } - } - - symbols.sort(); - - for (auto &sym : symbols) { - f << sym.first; - std::sort(sym.second.begin(), sym.second.end()); - for (auto &s : sym.second) - f << " " << s; - f << std::endl; - } - } - - f << stringf("c\nGenerated by %s\n", yosys_version_str); - } - - void write_map(std::ostream &f, bool verbose_map) - { - dict input_lines; - dict init_lines; - dict output_lines; - dict latch_lines; - dict wire_lines; - - for (auto wire : module->wires()) - { - if (!verbose_map && wire->name[0] == '$') - continue; - - SigSpec sig = sigmap(wire); - - for (int i = 0; i < GetSize(wire); i++) - { - if (aig_map.count(sig[i]) == 0 || sig[i].wire == nullptr) - continue; - - int a = aig_map.at(sig[i]); - - if (verbose_map) - wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire)); - - if (wire->port_input) { - log_assert((a & 1) == 0); - input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire)); - } - - if (wire->port_output) { - int o = ordered_outputs.at(sig[i]); - output_lines[o] += stringf("output %d %d %s\n", o, i, log_id(wire)); - } - - if (init_inputs.count(sig[i])) { - int a = init_inputs.at(sig[i]); - log_assert((a & 1) == 0); - init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, i, log_id(wire)); - } - - if (ordered_latches.count(sig[i])) { - int l = ordered_latches.at(sig[i]); - if (zinit_mode && (aig_latchinit.at(l) == 1)) - latch_lines[l] += stringf("invlatch %d %d %s\n", l, i, log_id(wire)); - else - latch_lines[l] += stringf("latch %d %d %s\n", l, i, log_id(wire)); - } - } - } - - input_lines.sort(); - for (auto &it : input_lines) - f << it.second; - - init_lines.sort(); - for (auto &it : init_lines) - f << it.second; - - output_lines.sort(); - for (auto &it : output_lines) - f << it.second; - - latch_lines.sort(); - for (auto &it : latch_lines) - f << it.second; - - wire_lines.sort(); - for (auto &it : wire_lines) - f << it.second; - } -}; - -struct AigerBackend : public Backend { - AigerBackend() : Backend("aiger", "write design to AIGER file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_aiger [options] [filename]\n"); - log("\n"); - log("Write the current design to an AIGER file. The design must be flattened and\n"); - log("must not contain any cell types except $_AND_, $_NOT_, simple FF types,\n"); - log("$assert and $assume cells, and $initstate cells.\n"); - log("\n"); - log("$assert and $assume cells are converted to AIGER bad state properties and\n"); - log("invariant constraints.\n"); - log("\n"); - log(" -ascii\n"); - log(" write ASCII version of AGIER format\n"); - log("\n"); - log(" -zinit\n"); - log(" convert FFs to zero-initialized FFs, adding additional inputs for\n"); - log(" uninitialized FFs.\n"); - log("\n"); - log(" -miter\n"); - log(" design outputs are AIGER bad state properties\n"); - log("\n"); - log(" -symbols\n"); - log(" include a symbol table in the generated AIGER file\n"); - log("\n"); - log(" -map \n"); - log(" write an extra file with port and latch symbols\n"); - log("\n"); - log(" -vmap \n"); - log(" like -map, but more verbose\n"); - log("\n"); - log(" -I, -O, -B\n"); - log(" If the design contains no input/output/assert then create one\n"); - log(" dummy input/output/bad_state pin to make the tools reading the\n"); - log(" AIGER file happy.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - bool ascii_mode = false; - bool zinit_mode = false; - bool miter_mode = false; - bool symbols_mode = false; - bool verbose_map = false; - bool imode = false; - bool omode = false; - bool bmode = false; - std::string map_filename; - - log_header(design, "Executing AIGER backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-ascii") { - ascii_mode = true; - continue; - } - if (args[argidx] == "-zinit") { - zinit_mode = true; - continue; - } - if (args[argidx] == "-miter") { - miter_mode = true; - continue; - } - if (args[argidx] == "-symbols") { - symbols_mode = true; - continue; - } - if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) { - map_filename = args[++argidx]; - continue; - } - if (map_filename.empty() && args[argidx] == "-vmap" && argidx+1 < args.size()) { - map_filename = args[++argidx]; - verbose_map = true; - continue; - } - if (args[argidx] == "-I") { - imode = true; - continue; - } - if (args[argidx] == "-O") { - omode = true; - continue; - } - if (args[argidx] == "-B") { - bmode = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - Module *top_module = design->top_module(); - - if (top_module == nullptr) - log_error("Can't find top module in current design!\n"); - - AigerWriter writer(top_module, zinit_mode, imode, omode, bmode); - writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); - - if (!map_filename.empty()) { - rewrite_filename(filename); - std::ofstream mapf; - mapf.open(map_filename.c_str(), std::ofstream::trunc); - if (mapf.fail()) - log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); - writer.write_map(mapf, verbose_map); - } - } -} AigerBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/blif/Makefile.inc b/yosys/backends/blif/Makefile.inc deleted file mode 100644 index 517dabaf2..000000000 --- a/yosys/backends/blif/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/blif/blif.o - diff --git a/yosys/backends/blif/blif.cc b/yosys/backends/blif/blif.cc deleted file mode 100644 index a1761b662..000000000 --- a/yosys/backends/blif/blif.cc +++ /dev/null @@ -1,682 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// [[CITE]] Berkeley Logic Interchange Format (BLIF) -// University of California. Berkeley. July 28, 1992 -// http://www.ece.cmu.edu/~ee760/760docs/blif.pdf - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct BlifDumperConfig -{ - bool icells_mode; - bool conn_mode; - bool impltf_mode; - bool gates_mode; - bool cname_mode; - bool iname_mode; - bool param_mode; - bool attr_mode; - bool iattr_mode; - bool blackbox_mode; - bool noalias_mode; - - std::string buf_type, buf_in, buf_out; - std::map> unbuf_types; - std::string true_type, true_out, false_type, false_out, undef_type, undef_out; - - BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), - cname_mode(false), iname_mode(false), param_mode(false), attr_mode(false), iattr_mode(false), - blackbox_mode(false), noalias_mode(false) { } -}; - -struct BlifDumper -{ - std::ostream &f; - RTLIL::Module *module; - RTLIL::Design *design; - BlifDumperConfig *config; - CellTypes ct; - - SigMap sigmap; - dict init_bits; - - BlifDumper(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig *config) : - f(f), module(module), design(design), config(config), ct(design), sigmap(module) - { - for (Wire *wire : module->wires()) - if (wire->attributes.count("\\init")) { - SigSpec initsig = sigmap(wire); - Const initval = wire->attributes.at("\\init"); - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - switch (initval[i]) { - case State::S0: - init_bits[initsig[i]] = 0; - break; - case State::S1: - init_bits[initsig[i]] = 1; - break; - default: - break; - } - } - } - - vector cstr_buf; - pool cstr_bits_seen; - - const char *cstr(RTLIL::IdString id) - { - std::string str = RTLIL::unescape_id(id); - for (size_t i = 0; i < str.size(); i++) - if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>') - str[i] = '?'; - cstr_buf.push_back(str); - return cstr_buf.back().c_str(); - } - - const char *cstr(RTLIL::SigBit sig) - { - cstr_bits_seen.insert(sig); - - if (sig.wire == NULL) { - if (sig == RTLIL::State::S0) return config->false_type == "-" || config->false_type == "+" ? config->false_out.c_str() : "$false"; - if (sig == RTLIL::State::S1) return config->true_type == "-" || config->true_type == "+" ? config->true_out.c_str() : "$true"; - return config->undef_type == "-" || config->undef_type == "+" ? config->undef_out.c_str() : "$undef"; - } - - std::string str = RTLIL::unescape_id(sig.wire->name); - for (size_t i = 0; i < str.size(); i++) - if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>') - str[i] = '?'; - - if (sig.wire->width != 1) - str += stringf("[%d]", sig.wire->upto ? sig.wire->start_offset+sig.wire->width-sig.offset-1 : sig.wire->start_offset+sig.offset); - - cstr_buf.push_back(str); - return cstr_buf.back().c_str(); - } - - const char *cstr_init(RTLIL::SigBit sig) - { - sigmap.apply(sig); - - if (init_bits.count(sig) == 0) - return " 2"; - - string str = stringf(" %d", init_bits.at(sig)); - - cstr_buf.push_back(str); - return cstr_buf.back().c_str(); - } - - const char *subckt_or_gate(std::string cell_type) - { - if (!config->gates_mode) - return "subckt"; - if (!design->modules_.count(RTLIL::escape_id(cell_type))) - return "gate"; - if (design->modules_.at(RTLIL::escape_id(cell_type))->get_blackbox_attribute()) - return "gate"; - return "subckt"; - } - - void dump_params(const char *command, dict ¶ms) - { - for (auto ¶m : params) { - f << stringf("%s %s ", command, RTLIL::id2cstr(param.first)); - if (param.second.flags & RTLIL::CONST_FLAG_STRING) { - std::string str = param.second.decode_string(); - f << stringf("\""); - for (char ch : str) - if (ch == '"' || ch == '\\') - f << stringf("\\%c", ch); - else if (ch < 32 || ch >= 127) - f << stringf("\\%03o", ch); - else - f << stringf("%c", ch); - f << stringf("\"\n"); - } else - f << stringf("%s\n", param.second.as_string().c_str()); - } - } - - void dump() - { - f << stringf("\n"); - f << stringf(".model %s\n", cstr(module->name)); - - std::map inputs, outputs; - - for (auto &wire_it : module->wires_) { - RTLIL::Wire *wire = wire_it.second; - if (wire->port_input) - inputs[wire->port_id] = wire; - if (wire->port_output) - outputs[wire->port_id] = wire; - } - - f << stringf(".inputs"); - for (auto &it : inputs) { - RTLIL::Wire *wire = it.second; - for (int i = 0; i < wire->width; i++) - f << stringf(" %s", cstr(RTLIL::SigSpec(wire, i))); - } - f << stringf("\n"); - - f << stringf(".outputs"); - for (auto &it : outputs) { - RTLIL::Wire *wire = it.second; - for (int i = 0; i < wire->width; i++) - f << stringf(" %s", cstr(RTLIL::SigSpec(wire, i))); - } - f << stringf("\n"); - - if (module->get_blackbox_attribute()) { - f << stringf(".blackbox\n"); - f << stringf(".end\n"); - return; - } - - if (!config->impltf_mode) { - if (!config->false_type.empty()) { - if (config->false_type == "+") - f << stringf(".names %s\n", config->false_out.c_str()); - else if (config->false_type != "-") - f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type), - config->false_type.c_str(), config->false_out.c_str()); - } else - f << stringf(".names $false\n"); - if (!config->true_type.empty()) { - if (config->true_type == "+") - f << stringf(".names %s\n1\n", config->true_out.c_str()); - else if (config->true_type != "-") - f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type), - config->true_type.c_str(), config->true_out.c_str()); - } else - f << stringf(".names $true\n1\n"); - if (!config->undef_type.empty()) { - if (config->undef_type == "+") - f << stringf(".names %s\n", config->undef_out.c_str()); - else if (config->undef_type != "-") - f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type), - config->undef_type.c_str(), config->undef_out.c_str()); - } else - f << stringf(".names $undef\n"); - } - - for (auto &cell_it : module->cells_) - { - RTLIL::Cell *cell = cell_it.second; - - if (config->unbuf_types.count(cell->type)) { - auto portnames = config->unbuf_types.at(cell->type); - f << stringf(".names %s %s\n1 1\n", - cstr(cell->getPort(portnames.first)), cstr(cell->getPort(portnames.second))); - continue; - } - - if (!config->icells_mode && cell->type == "$_NOT_") { - f << stringf(".names %s %s\n0 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_AND_") { - f << stringf(".names %s %s %s\n11 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_OR_") { - f << stringf(".names %s %s %s\n1- 1\n-1 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_XOR_") { - f << stringf(".names %s %s %s\n10 1\n01 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_NAND_") { - f << stringf(".names %s %s %s\n0- 1\n-0 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_NOR_") { - f << stringf(".names %s %s %s\n00 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_XNOR_") { - f << stringf(".names %s %s %s\n11 1\n00 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_ANDNOT_") { - f << stringf(".names %s %s %s\n10 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_ORNOT_") { - f << stringf(".names %s %s %s\n1- 1\n-0 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_AOI3_") { - f << stringf(".names %s %s %s %s\n-00 1\n0-0 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_OAI3_") { - f << stringf(".names %s %s %s %s\n00- 1\n--0 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_AOI4_") { - f << stringf(".names %s %s %s %s %s\n-0-0 1\n-00- 1\n0--0 1\n0-0- 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), - cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_OAI4_") { - f << stringf(".names %s %s %s %s %s\n00-- 1\n--00 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), - cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_MUX_") { - f << stringf(".names %s %s %s %s\n1-0 1\n-11 1\n", - cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), - cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_FF_") { - f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), - cstr_init(cell->getPort("\\Q"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_DFF_N_") { - f << stringf(".latch %s %s fe %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), - cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_DFF_P_") { - f << stringf(".latch %s %s re %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), - cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_DLATCH_N_") { - f << stringf(".latch %s %s al %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), - cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$_DLATCH_P_") { - f << stringf(".latch %s %s ah %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), - cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q"))); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$lut") { - f << stringf(".names"); - auto &inputs = cell->getPort("\\A"); - auto width = cell->parameters.at("\\WIDTH").as_int(); - log_assert(inputs.size() == width); - for (int i = width-1; i >= 0; i--) - f << stringf(" %s", cstr(inputs.extract(i, 1))); - auto &output = cell->getPort("\\Y"); - log_assert(output.size() == 1); - f << stringf(" %s", cstr(output)); - f << stringf("\n"); - RTLIL::SigSpec mask = cell->parameters.at("\\LUT"); - for (int i = 0; i < (1 << width); i++) - if (mask[i] == RTLIL::S1) { - for (int j = width-1; j >= 0; j--) { - f << ((i>>j)&1 ? '1' : '0'); - } - f << " 1\n"; - } - goto internal_cell; - } - - if (!config->icells_mode && cell->type == "$sop") { - f << stringf(".names"); - auto &inputs = cell->getPort("\\A"); - auto width = cell->parameters.at("\\WIDTH").as_int(); - auto depth = cell->parameters.at("\\DEPTH").as_int(); - vector table = cell->parameters.at("\\TABLE").bits; - while (GetSize(table) < 2*width*depth) - table.push_back(State::S0); - log_assert(inputs.size() == width); - for (int i = 0; i < width; i++) - f << stringf(" %s", cstr(inputs.extract(i, 1))); - auto &output = cell->getPort("\\Y"); - log_assert(output.size() == 1); - f << stringf(" %s", cstr(output)); - f << stringf("\n"); - for (int i = 0; i < depth; i++) { - for (int j = 0; j < width; j++) { - bool pat0 = table.at(2*width*i + 2*j + 0) == State::S1; - bool pat1 = table.at(2*width*i + 2*j + 1) == State::S1; - if (pat0 && !pat1) f << "0"; - else if (!pat0 && pat1) f << "1"; - else f << "-"; - } - f << " 1\n"; - } - goto internal_cell; - } - - f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type)); - for (auto &conn : cell->connections()) - { - if (conn.second.size() == 1) { - f << stringf(" %s=%s", cstr(conn.first), cstr(conn.second[0])); - continue; - } - - Module *m = design->module(cell->type); - Wire *w = m ? m->wire(conn.first) : nullptr; - - if (w == nullptr) { - for (int i = 0; i < GetSize(conn.second); i++) - f << stringf(" %s[%d]=%s", cstr(conn.first), i, cstr(conn.second[i])); - } else { - for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) { - SigBit sig(w, i); - f << stringf(" %s[%d]=%s", cstr(conn.first), sig.wire->upto ? - sig.wire->start_offset+sig.wire->width-sig.offset-1 : - sig.wire->start_offset+sig.offset, cstr(conn.second[i])); - } - } - } - f << stringf("\n"); - - if (config->cname_mode) - f << stringf(".cname %s\n", cstr(cell->name)); - if (config->attr_mode) - dump_params(".attr", cell->attributes); - if (config->param_mode) - dump_params(".param", cell->parameters); - - if (0) { - internal_cell: - if (config->iname_mode) - f << stringf(".cname %s\n", cstr(cell->name)); - if (config->iattr_mode) - dump_params(".attr", cell->attributes); - } - } - - for (auto &conn : module->connections()) - for (int i = 0; i < conn.first.size(); i++) - { - SigBit lhs_bit = conn.first[i]; - SigBit rhs_bit = conn.second[i]; - - if (config->noalias_mode && cstr_bits_seen.count(lhs_bit) == 0) - continue; - - if (config->conn_mode) - f << stringf(".conn %s %s\n", cstr(rhs_bit), cstr(lhs_bit)); - else if (!config->buf_type.empty()) - f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), - config->buf_in.c_str(), cstr(rhs_bit), config->buf_out.c_str(), cstr(lhs_bit)); - else - f << stringf(".names %s %s\n1 1\n", cstr(rhs_bit), cstr(lhs_bit)); - } - - f << stringf(".end\n"); - } - - static void dump(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig &config) - { - BlifDumper dumper(f, module, design, &config); - dumper.dump(); - } -}; - -struct BlifBackend : public Backend { - BlifBackend() : Backend("blif", "write design to BLIF file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_blif [options] [filename]\n"); - log("\n"); - log("Write the current design to an BLIF file.\n"); - log("\n"); - log(" -top top_module\n"); - log(" set the specified module as design top module\n"); - log("\n"); - log(" -buf \n"); - log(" use cells of type with the specified port names for buffers\n"); - log("\n"); - log(" -unbuf \n"); - log(" replace buffer cells with the specified name and port names with\n"); - log(" a .names statement that models a buffer\n"); - log("\n"); - log(" -true \n"); - log(" -false \n"); - log(" -undef \n"); - log(" use the specified cell types to drive nets that are constant 1, 0, or\n"); - log(" undefined. when '-' is used as , then specifies\n"); - log(" the wire name to be used for the constant signal and no cell driving\n"); - log(" that wire is generated. when '+' is used as , then \n"); - log(" specifies the wire name to be used for the constant signal and a .names\n"); - log(" statement is generated to drive the wire.\n"); - log("\n"); - log(" -noalias\n"); - log(" if a net name is aliasing another net name, then by default a net\n"); - log(" without fanout is created that is driven by the other net. This option\n"); - log(" suppresses the generation of this nets without fanout.\n"); - log("\n"); - log("The following options can be useful when the generated file is not going to be\n"); - log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n"); - log("file *.blif when any of this options is used.\n"); - log("\n"); - log(" -icells\n"); - log(" do not translate Yosys's internal gates to generic BLIF logic\n"); - log(" functions. Instead create .subckt or .gate lines for all cells.\n"); - log("\n"); - log(" -gates\n"); - log(" print .gate instead of .subckt lines for all cells that are not\n"); - log(" instantiations of other modules from this design.\n"); - log("\n"); - log(" -conn\n"); - log(" do not generate buffers for connected wires. instead use the\n"); - log(" non-standard .conn statement.\n"); - log("\n"); - log(" -attr\n"); - log(" use the non-standard .attr statement to write cell attributes\n"); - log("\n"); - log(" -param\n"); - log(" use the non-standard .param statement to write cell parameters\n"); - log("\n"); - log(" -cname\n"); - log(" use the non-standard .cname statement to write cell names\n"); - log("\n"); - log(" -iname, -iattr\n"); - log(" enable -cname and -attr functionality for .names statements\n"); - log(" (the .cname and .attr statements will be included in the BLIF\n"); - log(" output after the truth table for the .names statement)\n"); - log("\n"); - log(" -blackbox\n"); - log(" write blackbox cells with .blackbox statement.\n"); - log("\n"); - log(" -impltf\n"); - log(" do not write definitions for the $true, $false and $undef wires.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - std::string top_module_name; - std::string buf_type, buf_in, buf_out; - std::string true_type, true_out; - std::string false_type, false_out; - BlifDumperConfig config; - - log_header(design, "Executing BLIF backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_module_name = args[++argidx]; - continue; - } - if (args[argidx] == "-buf" && argidx+3 < args.size()) { - config.buf_type = args[++argidx]; - config.buf_in = args[++argidx]; - config.buf_out = args[++argidx]; - continue; - } - if (args[argidx] == "-unbuf" && argidx+3 < args.size()) { - RTLIL::IdString unbuf_type = RTLIL::escape_id(args[++argidx]); - RTLIL::IdString unbuf_in = RTLIL::escape_id(args[++argidx]); - RTLIL::IdString unbuf_out = RTLIL::escape_id(args[++argidx]); - config.unbuf_types[unbuf_type] = std::pair(unbuf_in, unbuf_out); - continue; - } - if (args[argidx] == "-true" && argidx+2 < args.size()) { - config.true_type = args[++argidx]; - config.true_out = args[++argidx]; - continue; - } - if (args[argidx] == "-false" && argidx+2 < args.size()) { - config.false_type = args[++argidx]; - config.false_out = args[++argidx]; - continue; - } - if (args[argidx] == "-undef" && argidx+2 < args.size()) { - config.undef_type = args[++argidx]; - config.undef_out = args[++argidx]; - continue; - } - if (args[argidx] == "-icells") { - config.icells_mode = true; - continue; - } - if (args[argidx] == "-gates") { - config.gates_mode = true; - continue; - } - if (args[argidx] == "-conn") { - config.conn_mode = true; - continue; - } - if (args[argidx] == "-cname") { - config.cname_mode = true; - continue; - } - if (args[argidx] == "-param") { - config.param_mode = true; - continue; - } - if (args[argidx] == "-attr") { - config.attr_mode = true; - continue; - } - if (args[argidx] == "-iname") { - config.iname_mode = true; - continue; - } - if (args[argidx] == "-iattr") { - config.iattr_mode = true; - continue; - } - if (args[argidx] == "-blackbox") { - config.blackbox_mode = true; - continue; - } - if (args[argidx] == "-impltf") { - config.impltf_mode = true; - continue; - } - if (args[argidx] == "-noalias") { - config.noalias_mode = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - if (top_module_name.empty()) - for (auto & mod_it:design->modules_) - if (mod_it.second->get_bool_attribute("\\top")) - top_module_name = mod_it.first.str(); - - *f << stringf("# Generated by %s\n", yosys_version_str); - - std::vector mod_list; - - design->sort(); - for (auto module_it : design->modules_) - { - RTLIL::Module *module = module_it.second; - if (module->get_blackbox_attribute() && !config.blackbox_mode) - continue; - - if (module->processes.size() != 0) - log_error("Found unmapped processes in module %s: unmapped processes are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name)); - if (module->memories.size() != 0) - log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name)); - - if (module->name == RTLIL::escape_id(top_module_name)) { - BlifDumper::dump(*f, module, design, config); - top_module_name.clear(); - continue; - } - - mod_list.push_back(module); - } - - if (!top_module_name.empty()) - log_error("Can't find top module `%s'!\n", top_module_name.c_str()); - - for (auto module : mod_list) - BlifDumper::dump(*f, module, design, config); - } -} BlifBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/btor/Makefile.inc b/yosys/backends/btor/Makefile.inc deleted file mode 100644 index af7ab14dc..000000000 --- a/yosys/backends/btor/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/btor/btor.o - diff --git a/yosys/backends/btor/btor.cc b/yosys/backends/btor/btor.cc deleted file mode 100644 index a507b120b..000000000 --- a/yosys/backends/btor/btor.cc +++ /dev/null @@ -1,1251 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// [[CITE]] Btor2 , BtorMC and Boolector 3.0 -// Aina Niemetz, Mathias Preiner, Clifford Wolf, Armin Biere -// Computer Aided Verification - 30th International Conference, CAV 2018 -// https://cs.stanford.edu/people/niemetz/publication/2018/niemetzpreinerwolfbiere-cav18/ - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct BtorWorker -{ - std::ostream &f; - SigMap sigmap; - RTLIL::Module *module; - bool verbose; - bool single_bad; - - int next_nid = 1; - int initstate_nid = -1; - - // => - dict sorts_bv; - - // (, ) => - dict, int> sorts_mem; - - // SigBit => (, ) - dict> bit_nid; - - // => - dict nid_width; - - // SigSpec => - dict sig_nid; - - // bit to driving cell - dict bit_cell; - - // nids for constants - dict consts; - - // ff inputs that need to be evaluated (, ) - vector> ff_todo; - - pool cell_recursion_guard; - vector bad_properties; - dict initbits; - pool statewires; - string indent; - - void btorf(const char *fmt, ...) - { - va_list ap; - va_start(ap, fmt); - f << indent << vstringf(fmt, ap); - va_end(ap); - } - - void btorf_push(const string &id) - { - if (verbose) { - f << indent << stringf(" ; begin %s\n", id.c_str()); - indent += " "; - } - } - - void btorf_pop(const string &id) - { - if (verbose) { - indent = indent.substr(4); - f << indent << stringf(" ; end %s\n", id.c_str()); - } - } - - int get_bv_sid(int width) - { - if (sorts_bv.count(width) == 0) { - int nid = next_nid++; - btorf("%d sort bitvec %d\n", nid, width); - sorts_bv[width] = nid; - } - return sorts_bv.at(width); - } - - int get_mem_sid(int abits, int dbits) - { - pair key(abits, dbits); - if (sorts_mem.count(key) == 0) { - int addr_sid = get_bv_sid(abits); - int data_sid = get_bv_sid(dbits); - int nid = next_nid++; - btorf("%d sort array %d %d\n", nid, addr_sid, data_sid); - sorts_mem[key] = nid; - } - return sorts_mem.at(key); - } - - void add_nid_sig(int nid, const SigSpec &sig) - { - if (verbose) - f << indent << stringf("; %d %s\n", nid, log_signal(sig)); - - for (int i = 0; i < GetSize(sig); i++) - bit_nid[sig[i]] = make_pair(nid, i); - - sig_nid[sig] = nid; - nid_width[nid] = GetSize(sig); - } - - void export_cell(Cell *cell) - { - if (cell_recursion_guard.count(cell)) { - string cell_list; - for (auto c : cell_recursion_guard) - cell_list += stringf("\n %s", log_id(c)); - log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list.c_str()); - } - - cell_recursion_guard.insert(cell); - btorf_push(log_id(cell)); - - if (cell->type.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx", - "$concat", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) - { - string btor_op; - if (cell->type == "$add") btor_op = "add"; - if (cell->type == "$sub") btor_op = "sub"; - if (cell->type == "$mul") btor_op = "mul"; - if (cell->type.in("$shl", "$sshl")) btor_op = "sll"; - if (cell->type == "$shr") btor_op = "srl"; - if (cell->type == "$sshr") btor_op = "sra"; - if (cell->type.in("$shift", "$shiftx")) btor_op = "shift"; - if (cell->type.in("$and", "$_AND_")) btor_op = "and"; - if (cell->type.in("$or", "$_OR_")) btor_op = "or"; - if (cell->type.in("$xor", "$_XOR_")) btor_op = "xor"; - if (cell->type == "$concat") btor_op = "concat"; - if (cell->type == "$_NAND_") btor_op = "nand"; - if (cell->type == "$_NOR_") btor_op = "nor"; - if (cell->type.in("$xnor", "$_XNOR_")) btor_op = "xnor"; - log_assert(!btor_op.empty()); - - int width = GetSize(cell->getPort("\\Y")); - width = std::max(width, GetSize(cell->getPort("\\A"))); - width = std::max(width, GetSize(cell->getPort("\\B"))); - - bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false; - bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false; - - if (btor_op == "shift" && !b_signed) - btor_op = "srl"; - - if (cell->type.in("$shl", "$sshl", "$shr", "$sshr")) - b_signed = false; - - if (cell->type == "$sshr" && !a_signed) - btor_op = "srl"; - - int sid = get_bv_sid(width); - int nid; - - if (btor_op == "shift") - { - int nid_a = get_sig_nid(cell->getPort("\\A"), width, false); - int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed); - - int nid_r = next_nid++; - btorf("%d srl %d %d %d\n", nid_r, sid, nid_a, nid_b); - - int nid_b_neg = next_nid++; - btorf("%d neg %d %d\n", nid_b_neg, sid, nid_b); - - int nid_l = next_nid++; - btorf("%d sll %d %d %d\n", nid_l, sid, nid_a, nid_b_neg); - - int sid_bit = get_bv_sid(1); - int nid_zero = get_sig_nid(Const(0, width)); - int nid_b_ltz = next_nid++; - btorf("%d slt %d %d %d\n", nid_b_ltz, sid_bit, nid_b, nid_zero); - - nid = next_nid++; - btorf("%d ite %d %d %d %d\n", nid, sid, nid_b_ltz, nid_l, nid_r); - } - else - { - int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed); - int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed); - - nid = next_nid++; - btorf("%d %s %d %d %d\n", nid, btor_op.c_str(), sid, nid_a, nid_b); - } - - SigSpec sig = sigmap(cell->getPort("\\Y")); - - if (GetSize(sig) < width) { - int sid = get_bv_sid(GetSize(sig)); - int nid2 = next_nid++; - btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1); - nid = nid2; - } - - add_nid_sig(nid, sig); - goto okay; - } - - if (cell->type.in("$div", "$mod")) - { - string btor_op; - if (cell->type == "$div") btor_op = "div"; - if (cell->type == "$mod") btor_op = "rem"; - log_assert(!btor_op.empty()); - - int width = GetSize(cell->getPort("\\Y")); - width = std::max(width, GetSize(cell->getPort("\\A"))); - width = std::max(width, GetSize(cell->getPort("\\B"))); - - bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false; - bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false; - - int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed); - int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed); - - int sid = get_bv_sid(width); - int nid = next_nid++; - btorf("%d %c%s %d %d %d\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b); - - SigSpec sig = sigmap(cell->getPort("\\Y")); - - if (GetSize(sig) < width) { - int sid = get_bv_sid(GetSize(sig)); - int nid2 = next_nid++; - btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1); - nid = nid2; - } - - add_nid_sig(nid, sig); - goto okay; - } - - if (cell->type.in("$_ANDNOT_", "$_ORNOT_")) - { - int sid = get_bv_sid(1); - int nid_a = get_sig_nid(cell->getPort("\\A")); - int nid_b = get_sig_nid(cell->getPort("\\B")); - - int nid1 = next_nid++; - int nid2 = next_nid++; - - if (cell->type == "$_ANDNOT_") { - btorf("%d not %d %d\n", nid1, sid, nid_b); - btorf("%d and %d %d %d\n", nid2, sid, nid_a, nid1); - } - - if (cell->type == "$_ORNOT_") { - btorf("%d not %d %d\n", nid1, sid, nid_b); - btorf("%d or %d %d %d\n", nid2, sid, nid_a, nid1); - } - - SigSpec sig = sigmap(cell->getPort("\\Y")); - add_nid_sig(nid2, sig); - goto okay; - } - - if (cell->type.in("$_OAI3_", "$_AOI3_")) - { - int sid = get_bv_sid(1); - int nid_a = get_sig_nid(cell->getPort("\\A")); - int nid_b = get_sig_nid(cell->getPort("\\B")); - int nid_c = get_sig_nid(cell->getPort("\\C")); - - int nid1 = next_nid++; - int nid2 = next_nid++; - int nid3 = next_nid++; - - if (cell->type == "$_OAI3_") { - btorf("%d or %d %d %d\n", nid1, sid, nid_a, nid_b); - btorf("%d and %d %d %d\n", nid2, sid, nid1, nid_c); - btorf("%d not %d %d\n", nid3, sid, nid2); - } - - if (cell->type == "$_AOI3_") { - btorf("%d and %d %d %d\n", nid1, sid, nid_a, nid_b); - btorf("%d or %d %d %d\n", nid2, sid, nid1, nid_c); - btorf("%d not %d %d\n", nid3, sid, nid2); - } - - SigSpec sig = sigmap(cell->getPort("\\Y")); - add_nid_sig(nid3, sig); - goto okay; - } - - if (cell->type.in("$_OAI4_", "$_AOI4_")) - { - int sid = get_bv_sid(1); - int nid_a = get_sig_nid(cell->getPort("\\A")); - int nid_b = get_sig_nid(cell->getPort("\\B")); - int nid_c = get_sig_nid(cell->getPort("\\C")); - int nid_d = get_sig_nid(cell->getPort("\\D")); - - int nid1 = next_nid++; - int nid2 = next_nid++; - int nid3 = next_nid++; - int nid4 = next_nid++; - - if (cell->type == "$_OAI4_") { - btorf("%d or %d %d %d\n", nid1, sid, nid_a, nid_b); - btorf("%d or %d %d %d\n", nid2, sid, nid_c, nid_d); - btorf("%d and %d %d %d\n", nid3, sid, nid1, nid2); - btorf("%d not %d %d\n", nid4, sid, nid3); - } - - if (cell->type == "$_AOI4_") { - btorf("%d and %d %d %d\n", nid1, sid, nid_a, nid_b); - btorf("%d and %d %d %d\n", nid2, sid, nid_c, nid_d); - btorf("%d or %d %d %d\n", nid3, sid, nid1, nid2); - btorf("%d not %d %d\n", nid4, sid, nid3); - } - - SigSpec sig = sigmap(cell->getPort("\\Y")); - add_nid_sig(nid4, sig); - goto okay; - } - - if (cell->type.in("$lt", "$le", "$eq", "$eqx", "$ne", "$nex", "$ge", "$gt")) - { - string btor_op; - if (cell->type == "$lt") btor_op = "lt"; - if (cell->type == "$le") btor_op = "lte"; - if (cell->type.in("$eq", "$eqx")) btor_op = "eq"; - if (cell->type.in("$ne", "$nex")) btor_op = "neq"; - if (cell->type == "$ge") btor_op = "gte"; - if (cell->type == "$gt") btor_op = "gt"; - log_assert(!btor_op.empty()); - - int width = 1; - width = std::max(width, GetSize(cell->getPort("\\A"))); - width = std::max(width, GetSize(cell->getPort("\\B"))); - - bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false; - bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false; - - int sid = get_bv_sid(1); - int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed); - int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed); - - int nid = next_nid++; - if (cell->type.in("$lt", "$le", "$ge", "$gt")) { - btorf("%d %c%s %d %d %d\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b); - } else { - btorf("%d %s %d %d %d\n", nid, btor_op.c_str(), sid, nid_a, nid_b); - } - - SigSpec sig = sigmap(cell->getPort("\\Y")); - - if (GetSize(sig) > 1) { - int sid = get_bv_sid(GetSize(sig)); - int nid2 = next_nid++; - btorf("%d uext %d %d %d\n", nid2, sid, nid, GetSize(sig) - 1); - nid = nid2; - } - - add_nid_sig(nid, sig); - goto okay; - } - - if (cell->type.in("$not", "$neg", "$_NOT_")) - { - string btor_op; - if (cell->type.in("$not", "$_NOT_")) btor_op = "not"; - if (cell->type == "$neg") btor_op = "neg"; - log_assert(!btor_op.empty()); - - int width = GetSize(cell->getPort("\\Y")); - width = std::max(width, GetSize(cell->getPort("\\A"))); - - bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false; - - int sid = get_bv_sid(width); - int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed); - - int nid = next_nid++; - btorf("%d %s %d %d\n", nid, btor_op.c_str(), sid, nid_a); - - SigSpec sig = sigmap(cell->getPort("\\Y")); - - if (GetSize(sig) < width) { - int sid = get_bv_sid(GetSize(sig)); - int nid2 = next_nid++; - btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1); - nid = nid2; - } - - add_nid_sig(nid, sig); - goto okay; - } - - if (cell->type.in("$logic_and", "$logic_or", "$logic_not")) - { - string btor_op; - if (cell->type == "$logic_and") btor_op = "and"; - if (cell->type == "$logic_or") btor_op = "or"; - if (cell->type == "$logic_not") btor_op = "not"; - log_assert(!btor_op.empty()); - - int sid = get_bv_sid(1); - int nid_a = get_sig_nid(cell->getPort("\\A")); - int nid_b = btor_op != "not" ? get_sig_nid(cell->getPort("\\B")) : 0; - - if (GetSize(cell->getPort("\\A")) > 1) { - int nid_red_a = next_nid++; - btorf("%d redor %d %d\n", nid_red_a, sid, nid_a); - nid_a = nid_red_a; - } - - if (btor_op != "not" && GetSize(cell->getPort("\\B")) > 1) { - int nid_red_b = next_nid++; - btorf("%d redor %d %d\n", nid_red_b, sid, nid_b); - nid_b = nid_red_b; - } - - int nid = next_nid++; - if (btor_op != "not") - btorf("%d %s %d %d %d\n", nid, btor_op.c_str(), sid, nid_a, nid_b); - else - btorf("%d %s %d %d\n", nid, btor_op.c_str(), sid, nid_a); - - SigSpec sig = sigmap(cell->getPort("\\Y")); - - if (GetSize(sig) > 1) { - int sid = get_bv_sid(GetSize(sig)); - int zeros_nid = get_sig_nid(Const(0, GetSize(sig)-1)); - int nid2 = next_nid++; - btorf("%d concat %d %d %d\n", nid2, sid, zeros_nid, nid); - nid = nid2; - } - - add_nid_sig(nid, sig); - goto okay; - } - - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor")) - { - string btor_op; - if (cell->type == "$reduce_and") btor_op = "redand"; - if (cell->type.in("$reduce_or", "$reduce_bool")) btor_op = "redor"; - if (cell->type.in("$reduce_xor", "$reduce_xnor")) btor_op = "redxor"; - log_assert(!btor_op.empty()); - - int sid = get_bv_sid(1); - int nid_a = get_sig_nid(cell->getPort("\\A")); - - int nid = next_nid++; - btorf("%d %s %d %d\n", nid, btor_op.c_str(), sid, nid_a); - - if (cell->type == "$reduce_xnor") { - int nid2 = next_nid++; - btorf("%d not %d %d %d\n", nid2, sid, nid); - nid = nid2; - } - - SigSpec sig = sigmap(cell->getPort("\\Y")); - - if (GetSize(sig) > 1) { - int sid = get_bv_sid(GetSize(sig)); - int zeros_nid = get_sig_nid(Const(0, GetSize(sig)-1)); - int nid2 = next_nid++; - btorf("%d concat %d %d %d\n", nid2, sid, zeros_nid, nid); - nid = nid2; - } - - add_nid_sig(nid, sig); - goto okay; - } - - if (cell->type.in("$mux", "$_MUX_")) - { - SigSpec sig_a = sigmap(cell->getPort("\\A")); - SigSpec sig_b = sigmap(cell->getPort("\\B")); - SigSpec sig_s = sigmap(cell->getPort("\\S")); - SigSpec sig_y = sigmap(cell->getPort("\\Y")); - - int nid_a = get_sig_nid(sig_a); - int nid_b = get_sig_nid(sig_b); - int nid_s = get_sig_nid(sig_s); - - int sid = get_bv_sid(GetSize(sig_y)); - int nid = next_nid++; - btorf("%d ite %d %d %d %d\n", nid, sid, nid_s, nid_b, nid_a); - - add_nid_sig(nid, sig_y); - goto okay; - } - - if (cell->type == "$pmux") - { - SigSpec sig_a = sigmap(cell->getPort("\\A")); - SigSpec sig_b = sigmap(cell->getPort("\\B")); - SigSpec sig_s = sigmap(cell->getPort("\\S")); - SigSpec sig_y = sigmap(cell->getPort("\\Y")); - - int width = GetSize(sig_a); - int sid = get_bv_sid(width); - int nid = get_sig_nid(sig_a); - - for (int i = 0; i < GetSize(sig_s); i++) { - int nid_b = get_sig_nid(sig_b.extract(i*width, width)); - int nid_s = get_sig_nid(sig_s.extract(i)); - int nid2 = next_nid++; - btorf("%d ite %d %d %d %d\n", nid2, sid, nid_s, nid_b, nid); - nid = nid2; - } - - add_nid_sig(nid, sig_y); - goto okay; - } - - if (cell->type.in("$dff", "$ff", "$_DFF_P_", "$_DFF_N", "$_FF_")) - { - SigSpec sig_d = sigmap(cell->getPort("\\D")); - SigSpec sig_q = sigmap(cell->getPort("\\Q")); - - IdString symbol; - - if (sig_q.is_wire()) { - Wire *w = sig_q.as_wire(); - if (w->port_id == 0) { - statewires.insert(w); - symbol = w->name; - } - } - - Const initval; - for (int i = 0; i < GetSize(sig_q); i++) - if (initbits.count(sig_q[i])) - initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0); - else - initval.bits.push_back(State::Sx); - - int nid_init_val = -1; - - if (!initval.is_fully_undef()) - nid_init_val = get_sig_nid(initval); - - int sid = get_bv_sid(GetSize(sig_q)); - int nid = next_nid++; - - if (symbol.empty()) - btorf("%d state %d\n", nid, sid); - else - btorf("%d state %d %s\n", nid, sid, log_id(symbol)); - - if (nid_init_val >= 0) { - int nid_init = next_nid++; - if (verbose) - btorf("; initval = %s\n", log_signal(initval)); - btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val); - } - - ff_todo.push_back(make_pair(nid, cell)); - add_nid_sig(nid, sig_q); - goto okay; - } - - if (cell->type.in("$anyconst", "$anyseq")) - { - SigSpec sig_y = sigmap(cell->getPort("\\Y")); - - int sid = get_bv_sid(GetSize(sig_y)); - int nid = next_nid++; - - btorf("%d state %d\n", nid, sid); - - if (cell->type == "$anyconst") { - int nid2 = next_nid++; - btorf("%d next %d %d %d\n", nid2, sid, nid, nid); - } - - add_nid_sig(nid, sig_y); - goto okay; - } - - if (cell->type == "$initstate") - { - SigSpec sig_y = sigmap(cell->getPort("\\Y")); - - if (initstate_nid < 0) - { - int sid = get_bv_sid(1); - int one_nid = get_sig_nid(Const(1, 1)); - int zero_nid = get_sig_nid(Const(0, 1)); - initstate_nid = next_nid++; - btorf("%d state %d\n", initstate_nid, sid); - btorf("%d init %d %d %d\n", next_nid++, sid, initstate_nid, one_nid); - btorf("%d next %d %d %d\n", next_nid++, sid, initstate_nid, zero_nid); - } - - add_nid_sig(initstate_nid, sig_y); - goto okay; - } - - if (cell->type == "$mem") - { - int abits = cell->getParam("\\ABITS").as_int(); - int width = cell->getParam("\\WIDTH").as_int(); - int nwords = cell->getParam("\\SIZE").as_int(); - int rdports = cell->getParam("\\RD_PORTS").as_int(); - int wrports = cell->getParam("\\WR_PORTS").as_int(); - - Const wr_clk_en = cell->getParam("\\WR_CLK_ENABLE"); - Const rd_clk_en = cell->getParam("\\RD_CLK_ENABLE"); - - bool asyncwr = wr_clk_en.is_fully_zero(); - - if (!asyncwr && !wr_clk_en.is_fully_ones()) - log_error("Memory %s.%s has mixed async/sync write ports.\n", - log_id(module), log_id(cell)); - - if (!rd_clk_en.is_fully_zero()) - log_error("Memory %s.%s has sync read ports.\n", - log_id(module), log_id(cell)); - - SigSpec sig_rd_addr = sigmap(cell->getPort("\\RD_ADDR")); - SigSpec sig_rd_data = sigmap(cell->getPort("\\RD_DATA")); - - SigSpec sig_wr_addr = sigmap(cell->getPort("\\WR_ADDR")); - SigSpec sig_wr_data = sigmap(cell->getPort("\\WR_DATA")); - SigSpec sig_wr_en = sigmap(cell->getPort("\\WR_EN")); - - int data_sid = get_bv_sid(width); - int bool_sid = get_bv_sid(1); - int sid = get_mem_sid(abits, width); - - Const initdata = cell->getParam("\\INIT"); - initdata.exts(nwords*width); - int nid_init_val = -1; - - if (!initdata.is_fully_undef()) - { - bool constword = true; - Const firstword = initdata.extract(0, width); - - for (int i = 1; i < nwords; i++) { - Const thisword = initdata.extract(i*width, width); - if (thisword != firstword) { - constword = false; - break; - } - } - - if (constword) - { - if (verbose) - btorf("; initval = %s\n", log_signal(firstword)); - nid_init_val = get_sig_nid(firstword); - } - else - { - int nid_init_val = next_nid++; - btorf("%d state %d\n", nid_init_val, sid); - - for (int i = 0; i < nwords; i++) { - Const thisword = initdata.extract(i*width, width); - if (thisword.is_fully_undef()) - continue; - Const thisaddr(i, abits); - int nid_thisword = get_sig_nid(thisword); - int nid_thisaddr = get_sig_nid(thisaddr); - int last_nid_init_val = nid_init_val; - nid_init_val = next_nid++; - if (verbose) - btorf("; initval[%d] = %s\n", i, log_signal(thisword)); - btorf("%d write %d %d %d %d\n", nid_init_val, sid, last_nid_init_val, nid_thisaddr, nid_thisword); - } - } - } - - - int nid = next_nid++; - int nid_head = nid; - - if (cell->name[0] == '$') - btorf("%d state %d\n", nid, sid); - else - btorf("%d state %d %s\n", nid, sid, log_id(cell)); - - if (nid_init_val >= 0) - { - int nid_init = next_nid++; - btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val); - } - - if (asyncwr) - { - for (int port = 0; port < wrports; port++) - { - SigSpec wa = sig_wr_addr.extract(port*abits, abits); - SigSpec wd = sig_wr_data.extract(port*width, width); - SigSpec we = sig_wr_en.extract(port*width, width); - - int wa_nid = get_sig_nid(wa); - int wd_nid = get_sig_nid(wd); - int we_nid = get_sig_nid(we); - - int nid2 = next_nid++; - btorf("%d read %d %d %d\n", nid2, data_sid, nid_head, wa_nid); - - int nid3 = next_nid++; - btorf("%d not %d %d\n", nid3, data_sid, we_nid); - - int nid4 = next_nid++; - btorf("%d and %d %d %d\n", nid4, data_sid, nid2, nid3); - - int nid5 = next_nid++; - btorf("%d and %d %d %d\n", nid5, data_sid, wd_nid, we_nid); - - int nid6 = next_nid++; - btorf("%d or %d %d %d\n", nid6, data_sid, nid5, nid4); - - int nid7 = next_nid++; - btorf("%d write %d %d %d %d\n", nid7, sid, nid_head, wa_nid, nid6); - - int nid8 = next_nid++; - btorf("%d redor %d %d\n", nid8, bool_sid, we_nid); - - int nid9 = next_nid++; - btorf("%d ite %d %d %d %d\n", nid9, sid, nid8, nid7, nid_head); - - nid_head = nid9; - } - } - - for (int port = 0; port < rdports; port++) - { - SigSpec ra = sig_rd_addr.extract(port*abits, abits); - SigSpec rd = sig_rd_data.extract(port*width, width); - - int ra_nid = get_sig_nid(ra); - int rd_nid = next_nid++; - - btorf("%d read %d %d %d\n", rd_nid, data_sid, nid_head, ra_nid); - - add_nid_sig(rd_nid, rd); - } - - if (!asyncwr) - { - ff_todo.push_back(make_pair(nid, cell)); - } - else - { - int nid2 = next_nid++; - btorf("%d next %d %d %d\n", nid2, sid, nid, nid_head); - } - - goto okay; - } - - log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); - - okay: - btorf_pop(log_id(cell)); - cell_recursion_guard.erase(cell); - } - - int get_sig_nid(SigSpec sig, int to_width = -1, bool is_signed = false) - { - int nid = -1; - sigmap.apply(sig); - - for (auto bit : sig) - if (bit == State::Sx) - goto has_undef_bits; - - if (0) - { - has_undef_bits: - SigSpec sig_mask_undef, sig_noundef; - int first_undef = -1; - - for (int i = 0; i < GetSize(sig); i++) - if (sig[i] == State::Sx) { - if (first_undef < 0) - first_undef = i; - sig_mask_undef.append(State::S1); - sig_noundef.append(State::S0); - } else { - sig_mask_undef.append(State::S0); - sig_noundef.append(sig[i]); - } - - if (to_width < 0 || first_undef < to_width) - { - int sid = get_bv_sid(GetSize(sig)); - - int nid_input = next_nid++; - btorf("%d input %d\n", nid_input, sid); - - int nid_masked_input; - if (sig_mask_undef.is_fully_ones()) { - nid_masked_input = nid_input; - } else { - int nid_mask_undef = get_sig_nid(sig_mask_undef); - nid_masked_input = next_nid++; - btorf("%d and %d %d %d\n", nid_masked_input, sid, nid_input, nid_mask_undef); - } - - if (sig_noundef.is_fully_zero()) { - nid = nid_masked_input; - } else { - int nid_noundef = get_sig_nid(sig_noundef); - nid = next_nid++; - btorf("%d or %d %d %d\n", nid, sid, nid_masked_input, nid_noundef); - } - - goto extend_or_trim; - } - - sig = sig_noundef; - } - - if (sig_nid.count(sig) == 0) - { - // , - vector> nidbits; - - // collect all bits - for (int i = 0; i < GetSize(sig); i++) - { - SigBit bit = sig[i]; - - if (bit_nid.count(bit) == 0) - { - if (bit.wire == nullptr) - { - Const c(bit.data); - - while (i+GetSize(c) < GetSize(sig) && sig[i+GetSize(c)].wire == nullptr) - c.bits.push_back(sig[i+GetSize(c)].data); - - if (consts.count(c) == 0) { - int sid = get_bv_sid(GetSize(c)); - int nid = next_nid++; - btorf("%d const %d %s\n", nid, sid, c.as_string().c_str()); - consts[c] = nid; - nid_width[nid] = GetSize(c); - } - - int nid = consts.at(c); - - for (int j = 0; j < GetSize(c); j++) - nidbits.push_back(make_pair(nid, j)); - - i += GetSize(c)-1; - continue; - } - else - { - if (bit_cell.count(bit) == 0) - { - SigSpec s = bit; - - while (i+GetSize(s) < GetSize(sig) && sig[i+GetSize(s)].wire != nullptr && - bit_cell.count(sig[i+GetSize(s)]) == 0) - s.append(sig[i+GetSize(s)]); - - log_warning("No driver for signal %s.\n", log_signal(s)); - - int sid = get_bv_sid(GetSize(s)); - int nid = next_nid++; - btorf("%d input %d %s\n", nid, sid); - nid_width[nid] = GetSize(s); - - i += GetSize(s)-1; - continue; - } - else - { - export_cell(bit_cell.at(bit)); - log_assert(bit_nid.count(bit)); - } - } - } - - nidbits.push_back(bit_nid.at(bit)); - } - - int width = 0; - int nid = -1; - - // group bits and emit slice-concat chain - for (int i = 0; i < GetSize(nidbits); i++) - { - int nid2 = nidbits[i].first; - int lower = nidbits[i].second; - int upper = lower; - - while (i+1 < GetSize(nidbits) && nidbits[i+1].first == nidbits[i].first && - nidbits[i+1].second == nidbits[i].second+1) - upper++, i++; - - int nid3 = nid2; - - if (lower != 0 || upper+1 != nid_width.at(nid2)) { - int sid = get_bv_sid(upper-lower+1); - nid3 = next_nid++; - btorf("%d slice %d %d %d %d\n", nid3, sid, nid2, upper, lower); - } - - int nid4 = nid3; - - if (nid >= 0) { - int sid = get_bv_sid(width+upper-lower+1); - nid4 = next_nid++; - btorf("%d concat %d %d %d\n", nid4, sid, nid3, nid); - } - - width += upper-lower+1; - nid = nid4; - } - - sig_nid[sig] = nid; - nid_width[nid] = width; - } - - nid = sig_nid.at(sig); - - extend_or_trim: - if (to_width >= 0 && to_width != GetSize(sig)) - { - if (to_width < GetSize(sig)) - { - int sid = get_bv_sid(to_width); - int nid2 = next_nid++; - btorf("%d slice %d %d %d 0\n", nid2, sid, nid, to_width-1); - nid = nid2; - } - else - { - int sid = get_bv_sid(to_width); - int nid2 = next_nid++; - btorf("%d %s %d %d %d\n", nid2, is_signed ? "sext" : "uext", - sid, nid, to_width - GetSize(sig)); - nid = nid2; - } - } - - return nid; - } - - BtorWorker(std::ostream &f, RTLIL::Module *module, bool verbose, bool single_bad) : - f(f), sigmap(module), module(module), verbose(verbose), single_bad(single_bad) - { - btorf_push("inputs"); - - for (auto wire : module->wires()) - { - if (wire->attributes.count("\\init")) { - Const attrval = wire->attributes.at("\\init"); - for (int i = 0; i < GetSize(wire) && i < GetSize(attrval); i++) - if (attrval[i] == State::S0 || attrval[i] == State::S1) - initbits[sigmap(SigBit(wire, i))] = (attrval[i] == State::S1); - } - - if (!wire->port_id || !wire->port_input) - continue; - - SigSpec sig = sigmap(wire); - int sid = get_bv_sid(GetSize(sig)); - int nid = next_nid++; - - btorf("%d input %d %s\n", nid, sid, log_id(wire)); - add_nid_sig(nid, sig); - } - - btorf_pop("inputs"); - - for (auto cell : module->cells()) - for (auto &conn : cell->connections()) - { - if (!cell->output(conn.first)) - continue; - - for (auto bit : sigmap(conn.second)) - bit_cell[bit] = cell; - } - - for (auto wire : module->wires()) - { - if (!wire->port_id || !wire->port_output) - continue; - - btorf_push(stringf("output %s", log_id(wire))); - - int nid = get_sig_nid(wire); - btorf("%d output %d %s\n", next_nid++, nid, log_id(wire)); - - btorf_pop(stringf("output %s", log_id(wire))); - } - - for (auto cell : module->cells()) - { - if (cell->type == "$assume") - { - btorf_push(log_id(cell)); - - int sid = get_bv_sid(1); - int nid_a = get_sig_nid(cell->getPort("\\A")); - int nid_en = get_sig_nid(cell->getPort("\\EN")); - int nid_not_en = next_nid++; - int nid_a_or_not_en = next_nid++; - int nid = next_nid++; - - btorf("%d not %d %d\n", nid_not_en, sid, nid_en); - btorf("%d or %d %d %d\n", nid_a_or_not_en, sid, nid_a, nid_not_en); - btorf("%d constraint %d\n", nid, nid_a_or_not_en); - - btorf_pop(log_id(cell)); - } - - if (cell->type == "$assert") - { - btorf_push(log_id(cell)); - - int sid = get_bv_sid(1); - int nid_a = get_sig_nid(cell->getPort("\\A")); - int nid_en = get_sig_nid(cell->getPort("\\EN")); - int nid_not_a = next_nid++; - int nid_en_and_not_a = next_nid++; - - btorf("%d not %d %d\n", nid_not_a, sid, nid_a); - btorf("%d and %d %d %d\n", nid_en_and_not_a, sid, nid_en, nid_not_a); - - if (single_bad) { - bad_properties.push_back(nid_en_and_not_a); - } else { - int nid = next_nid++; - btorf("%d bad %d\n", nid, nid_en_and_not_a); - } - - btorf_pop(log_id(cell)); - } - } - - for (auto wire : module->wires()) - { - if (wire->port_id || wire->name[0] == '$') - continue; - - btorf_push(stringf("wire %s", log_id(wire))); - - int sid = get_bv_sid(GetSize(wire)); - int nid = get_sig_nid(sigmap(wire)); - - if (statewires.count(wire)) - continue; - - int this_nid = next_nid++; - btorf("%d uext %d %d %d %s\n", this_nid, sid, nid, 0, log_id(wire)); - - btorf_pop(stringf("wire %s", log_id(wire))); - continue; - } - - while (!ff_todo.empty()) - { - vector> todo; - todo.swap(ff_todo); - - for (auto &it : todo) - { - int nid = it.first; - Cell *cell = it.second; - - btorf_push(stringf("next %s", log_id(cell))); - - if (cell->type == "$mem") - { - int abits = cell->getParam("\\ABITS").as_int(); - int width = cell->getParam("\\WIDTH").as_int(); - int wrports = cell->getParam("\\WR_PORTS").as_int(); - - SigSpec sig_wr_addr = sigmap(cell->getPort("\\WR_ADDR")); - SigSpec sig_wr_data = sigmap(cell->getPort("\\WR_DATA")); - SigSpec sig_wr_en = sigmap(cell->getPort("\\WR_EN")); - - int data_sid = get_bv_sid(width); - int bool_sid = get_bv_sid(1); - int sid = get_mem_sid(abits, width); - int nid_head = nid; - - for (int port = 0; port < wrports; port++) - { - SigSpec wa = sig_wr_addr.extract(port*abits, abits); - SigSpec wd = sig_wr_data.extract(port*width, width); - SigSpec we = sig_wr_en.extract(port*width, width); - - int wa_nid = get_sig_nid(wa); - int wd_nid = get_sig_nid(wd); - int we_nid = get_sig_nid(we); - - int nid2 = next_nid++; - btorf("%d read %d %d %d\n", nid2, data_sid, nid_head, wa_nid); - - int nid3 = next_nid++; - btorf("%d not %d %d\n", nid3, data_sid, we_nid); - - int nid4 = next_nid++; - btorf("%d and %d %d %d\n", nid4, data_sid, nid2, nid3); - - int nid5 = next_nid++; - btorf("%d and %d %d %d\n", nid5, data_sid, wd_nid, we_nid); - - int nid6 = next_nid++; - btorf("%d or %d %d %d\n", nid6, data_sid, nid5, nid4); - - int nid7 = next_nid++; - btorf("%d write %d %d %d %d\n", nid7, sid, nid_head, wa_nid, nid6); - - int nid8 = next_nid++; - btorf("%d redor %d %d\n", nid8, bool_sid, we_nid); - - int nid9 = next_nid++; - btorf("%d ite %d %d %d %d\n", nid9, sid, nid8, nid7, nid_head); - - nid_head = nid9; - } - - int nid2 = next_nid++; - btorf("%d next %d %d %d\n", nid2, sid, nid, nid_head); - } - else - { - SigSpec sig = sigmap(cell->getPort("\\D")); - int nid_q = get_sig_nid(sig); - int sid = get_bv_sid(GetSize(sig)); - btorf("%d next %d %d %d\n", next_nid++, sid, nid, nid_q); - } - - btorf_pop(stringf("next %s", log_id(cell))); - } - } - - while (!bad_properties.empty()) - { - vector todo; - bad_properties.swap(todo); - - int sid = get_bv_sid(1); - int cursor = 0; - - while (cursor+1 < GetSize(todo)) - { - int nid_a = todo[cursor++]; - int nid_b = todo[cursor++]; - int nid = next_nid++; - - bad_properties.push_back(nid); - btorf("%d or %d %d %d\n", nid, sid, nid_a, nid_b); - } - - if (!bad_properties.empty()) { - if (cursor < GetSize(todo)) - bad_properties.push_back(todo[cursor++]); - log_assert(cursor == GetSize(todo)); - } else { - int nid = next_nid++; - log_assert(cursor == 0); - log_assert(GetSize(todo) == 1); - btorf("%d bad %d\n", nid, todo[cursor]); - } - } - } -}; - -struct BtorBackend : public Backend { - BtorBackend() : Backend("btor", "write design to BTOR file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_btor [options] [filename]\n"); - log("\n"); - log("Write a BTOR description of the current design.\n"); - log("\n"); - log(" -v\n"); - log(" Add comments and indentation to BTOR output file\n"); - log("\n"); - log(" -s\n"); - log(" Output only a single bad property for all asserts\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - bool verbose = false, single_bad = false; - - log_header(design, "Executing BTOR backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-v") { - verbose = true; - continue; - } - if (args[argidx] == "-s") { - single_bad = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - RTLIL::Module *topmod = design->top_module(); - - if (topmod == nullptr) - log_cmd_error("No top module found.\n"); - - *f << stringf("; BTOR description generated by %s for module %s.\n", - yosys_version_str, log_id(topmod)); - - BtorWorker(*f, topmod, verbose, single_bad); - - *f << stringf("; end of yosys output\n"); - } -} BtorBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/btor/test_cells.sh b/yosys/backends/btor/test_cells.sh deleted file mode 100644 index e0f1a0514..000000000 --- a/yosys/backends/btor/test_cells.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -ex - -rm -rf test_cells.tmp -mkdir -p test_cells.tmp -cd test_cells.tmp - -../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod' - -for fn in test_*.il; do - ../../../yosys -p " - read_ilang $fn - rename gold gate - synth - - read_ilang $fn - miter -equiv -make_assert -flatten gold gate main - hierarchy -top main - write_btor ${fn%.il}.btor - " - boolectormc -kmax 1 --trace-gen --stop-first -v ${fn%.il}.btor > ${fn%.il}.out - if grep " SATISFIABLE" ${fn%.il}.out; then - echo "Check failed for ${fn%.il}." - exit 1 - fi -done - -echo "OK." - diff --git a/yosys/backends/edif/Makefile.inc b/yosys/backends/edif/Makefile.inc deleted file mode 100644 index 93de0e24f..000000000 --- a/yosys/backends/edif/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/edif/edif.o - diff --git a/yosys/backends/edif/edif.cc b/yosys/backends/edif/edif.cc deleted file mode 100644 index 6d9469538..000000000 --- a/yosys/backends/edif/edif.cc +++ /dev/null @@ -1,451 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// [[CITE]] EDIF Version 2 0 0 Grammar -// http://web.archive.org/web/20050730021644/http://www.edif.org/documentation/BNF_GRAMMAR/index.html - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str() -#define EDIF_DEFR(_id, _ren, _bl, _br) edif_names(RTLIL::unescape_id(_id), true, _ren, _bl, _br).c_str() -#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str() - -struct EdifNames -{ - int counter; - char delim_left, delim_right; - std::set generated_names, used_names; - std::map name_map; - - EdifNames() : counter(1), delim_left('['), delim_right(']') { } - - std::string operator()(std::string id, bool define, bool port_rename = false, int range_left = 0, int range_right = 0) - { - if (define) { - std::string new_id = operator()(id, false); - if (port_rename) - return stringf("(rename %s \"%s%c%d:%d%c\")", new_id.c_str(), id.c_str(), delim_left, range_left, range_right, delim_right); - return new_id != id ? stringf("(rename %s \"%s\")", new_id.c_str(), id.c_str()) : id; - } - - if (name_map.count(id) > 0) - return name_map.at(id); - if (generated_names.count(id) > 0) - goto do_rename; - if (id == "GND" || id == "VCC") - goto do_rename; - - for (size_t i = 0; i < id.size(); i++) { - if ('A' <= id[i] && id[i] <= 'Z') - continue; - if ('a' <= id[i] && id[i] <= 'z') - continue; - if ('0' <= id[i] && id[i] <= '9' && i > 0) - continue; - if (id[i] == '_' && i > 0 && i != id.size()-1) - continue; - goto do_rename; - } - - used_names.insert(id); - return id; - - do_rename:; - std::string gen_name; - while (1) { - gen_name = stringf("id%05d", counter++); - if (generated_names.count(gen_name) == 0 && - used_names.count(gen_name) == 0) - break; - } - generated_names.insert(gen_name); - name_map[id] = gen_name; - return gen_name; - } -}; - -struct EdifBackend : public Backend { - EdifBackend() : Backend("edif", "write design to EDIF netlist file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_edif [options] [filename]\n"); - log("\n"); - log("Write the current design to an EDIF netlist file.\n"); - log("\n"); - log(" -top top_module\n"); - log(" set the specified module as design top module\n"); - log("\n"); - log(" -nogndvcc\n"); - log(" do not create \"GND\" and \"VCC\" cells. (this will produce an error\n"); - log(" if the design contains constant nets. use \"hilomap\" to map to custom\n"); - log(" constant drivers first)\n"); - log("\n"); - log(" -gndvccy\n"); - log(" create \"GND\" and \"VCC\" cells with \"Y\" outputs. (the default is \"G\"\n"); - log(" for \"GND\" and \"P\" for \"VCC\".)\n"); - log("\n"); - log(" -attrprop\n"); - log(" create EDIF properties for cell attributes\n"); - log("\n"); - log(" -pvector {par|bra|ang}\n"); - log(" sets the delimiting character for module port rename clauses to\n"); - log(" parentheses, square brackets, or angle brackets.\n"); - log("\n"); - log("Unfortunately there are different \"flavors\" of the EDIF file format. This\n"); - log("command generates EDIF files for the Xilinx place&route tools. It might be\n"); - log("necessary to make small modifications to this command when a different tool\n"); - log("is targeted.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing EDIF backend.\n"); - std::string top_module_name; - bool port_rename = false; - bool attr_properties = false; - std::map> lib_cell_ports; - bool nogndvcc = false, gndvccy = false; - CellTypes ct(design); - EdifNames edif_names; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_module_name = args[++argidx]; - continue; - } - if (args[argidx] == "-nogndvcc") { - nogndvcc = true; - continue; - } - if (args[argidx] == "-gndvccy") { - gndvccy = true; - continue; - } - if (args[argidx] == "-attrprop") { - attr_properties = true; - continue; - } - if (args[argidx] == "-pvector" && argidx+1 < args.size()) { - std::string parray; - port_rename = true; - parray = args[++argidx]; - if (parray == "par") { - edif_names.delim_left = '(';edif_names.delim_right = ')'; - } else if (parray == "ang") { - edif_names.delim_left = '<';edif_names.delim_right = '>'; - } else { - edif_names.delim_left = '[';edif_names.delim_right = ']'; - } - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - if (top_module_name.empty()) - for (auto & mod_it:design->modules_) - if (mod_it.second->get_bool_attribute("\\top")) - top_module_name = mod_it.first.str(); - - for (auto module_it : design->modules_) - { - RTLIL::Module *module = module_it.second; - if (module->get_blackbox_attribute()) - continue; - - if (top_module_name.empty()) - top_module_name = module->name.str(); - - if (module->processes.size() != 0) - log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name)); - if (module->memories.size() != 0) - log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name)); - - for (auto cell_it : module->cells_) - { - RTLIL::Cell *cell = cell_it.second; - if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) { - lib_cell_ports[cell->type]; - for (auto p : cell->connections()) - lib_cell_ports[cell->type][p.first] = GetSize(p.second); - } - } - } - - if (top_module_name.empty()) - log_error("No module found in design!\n"); - - *f << stringf("(edif %s\n", EDIF_DEF(top_module_name)); - *f << stringf(" (edifVersion 2 0 0)\n"); - *f << stringf(" (edifLevel 0)\n"); - *f << stringf(" (keywordMap (keywordLevel 0))\n"); - *f << stringf(" (comment \"Generated by %s\")\n", yosys_version_str); - - *f << stringf(" (external LIB\n"); - *f << stringf(" (edifLevel 0)\n"); - *f << stringf(" (technology (numberDefinition))\n"); - - if (!nogndvcc) - { - *f << stringf(" (cell GND\n"); - *f << stringf(" (cellType GENERIC)\n"); - *f << stringf(" (view VIEW_NETLIST\n"); - *f << stringf(" (viewType NETLIST)\n"); - *f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'G'); - *f << stringf(" )\n"); - *f << stringf(" )\n"); - - *f << stringf(" (cell VCC\n"); - *f << stringf(" (cellType GENERIC)\n"); - *f << stringf(" (view VIEW_NETLIST\n"); - *f << stringf(" (viewType NETLIST)\n"); - *f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'P'); - *f << stringf(" )\n"); - *f << stringf(" )\n"); - } - - for (auto &cell_it : lib_cell_ports) { - *f << stringf(" (cell %s\n", EDIF_DEF(cell_it.first)); - *f << stringf(" (cellType GENERIC)\n"); - *f << stringf(" (view VIEW_NETLIST\n"); - *f << stringf(" (viewType NETLIST)\n"); - *f << stringf(" (interface\n"); - for (auto &port_it : cell_it.second) { - const char *dir = "INOUT"; - if (ct.cell_known(cell_it.first)) { - if (!ct.cell_output(cell_it.first, port_it.first)) - dir = "INPUT"; - else if (!ct.cell_input(cell_it.first, port_it.first)) - dir = "OUTPUT"; - } - if (port_it.second == 1) - *f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it.first), dir); - else { - int b[2] = {port_it.second-1, 0}; - auto m = design->module(cell_it.first); - if (m) { - auto w = m->wire(port_it.first); - if (w) { - b[w->upto ? 0 : 1] = w->start_offset; - b[w->upto ? 1 : 0] = w->start_offset+GetSize(w)-1; - } - } - *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEFR(port_it.first, port_rename, b[0], b[1]), port_it.second, dir); - } - } - *f << stringf(" )\n"); - *f << stringf(" )\n"); - *f << stringf(" )\n"); - } - *f << stringf(" )\n"); - - std::vector sorted_modules; - - // extract module dependencies - std::map> module_deps; - for (auto &mod_it : design->modules_) { - module_deps[mod_it.second] = std::set(); - for (auto &cell_it : mod_it.second->cells_) - if (design->modules_.count(cell_it.second->type) > 0) - module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type)); - } - - // simple good-enough topological sort - // (O(n*m) on n elements and depth m) - while (module_deps.size() > 0) { - size_t sorted_modules_idx = sorted_modules.size(); - for (auto &it : module_deps) { - for (auto &dep : it.second) - if (module_deps.count(dep) > 0) - goto not_ready_yet; - // log("Next in topological sort: %s\n", RTLIL::id2cstr(it.first->name)); - sorted_modules.push_back(it.first); - not_ready_yet:; - } - if (sorted_modules_idx == sorted_modules.size()) - log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", RTLIL::id2cstr(module_deps.begin()->first->name)); - while (sorted_modules_idx < sorted_modules.size()) - module_deps.erase(sorted_modules.at(sorted_modules_idx++)); - } - - - *f << stringf(" (library DESIGN\n"); - *f << stringf(" (edifLevel 0)\n"); - *f << stringf(" (technology (numberDefinition))\n"); - for (auto module : sorted_modules) - { - if (module->get_blackbox_attribute()) - continue; - - SigMap sigmap(module); - std::map> net_join_db; - - *f << stringf(" (cell %s\n", EDIF_DEF(module->name)); - *f << stringf(" (cellType GENERIC)\n"); - *f << stringf(" (view VIEW_NETLIST\n"); - *f << stringf(" (viewType NETLIST)\n"); - *f << stringf(" (interface\n"); - for (auto &wire_it : module->wires_) { - RTLIL::Wire *wire = wire_it.second; - if (wire->port_id == 0) - continue; - const char *dir = "INOUT"; - if (!wire->port_output) - dir = "INPUT"; - else if (!wire->port_input) - dir = "OUTPUT"; - if (wire->width == 1) { - *f << stringf(" (port %s (direction %s))\n", EDIF_DEF(wire->name), dir); - RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire)); - net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name))); - } else { - int b[2]; - b[wire->upto ? 0 : 1] = wire->start_offset; - b[wire->upto ? 1 : 0] = wire->start_offset + GetSize(wire) - 1; - *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEFR(wire->name, port_rename, b[0], b[1]), wire->width, dir); - for (int i = 0; i < wire->width; i++) { - RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i)); - net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1)); - } - } - } - *f << stringf(" )\n"); - *f << stringf(" (contents\n"); - if (!nogndvcc) { - *f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n"); - *f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n"); - } - for (auto &cell_it : module->cells_) { - RTLIL::Cell *cell = cell_it.second; - *f << stringf(" (instance %s\n", EDIF_DEF(cell->name)); - *f << stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type), - lib_cell_ports.count(cell->type) > 0 ? " (libraryRef LIB)" : ""); - - auto add_prop = [&](IdString name, Const val) { - if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) - *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str()); - else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def()) - *f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int()); - else { - std::string hex_string = ""; - for (size_t i = 0; i < val.bits.size(); i += 4) { - int digit_value = 0; - if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1; - if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2; - if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4; - if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8; - char digit_str[2] = { "0123456789abcdef"[digit_value], 0 }; - hex_string = std::string(digit_str) + hex_string; - } - *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str()); - } - }; - - for (auto &p : cell->parameters) - add_prop(p.first, p.second); - if (attr_properties) - for (auto &p : cell->attributes) - add_prop(p.first, p.second); - - *f << stringf(")\n"); - for (auto &p : cell->connections()) { - RTLIL::SigSpec sig = sigmap(p.second); - for (int i = 0; i < GetSize(sig); i++) - if (sig[i].wire == NULL && sig[i] != RTLIL::State::S0 && sig[i] != RTLIL::State::S1) - log_warning("Bit %d of cell port %s.%s.%s driven by %s will be left unconnected in EDIF output.\n", - i, log_id(module), log_id(cell), log_id(p.first), log_signal(sig[i])); - else if (sig.size() == 1) - net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name))); - else { - int member_idx = GetSize(sig)-i-1; - auto m = design->module(cell->type); - if (m) { - auto w = m->wire(p.first); - if (w) - member_idx = GetSize(w)-i-1; - } - net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))", - EDIF_REF(p.first), member_idx, EDIF_REF(cell->name))); - } - } - } - for (auto &it : net_join_db) { - RTLIL::SigBit sig = it.first; - if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) { - if (sig == RTLIL::State::Sx) { - for (auto &ref : it.second) - log_warning("Exporting x-bit on %s as zero bit.\n", ref.c_str()); - sig = RTLIL::State::S0; - } else { - for (auto &ref : it.second) - log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.c_str()); - log_abort(); - } - } - std::string netname; - if (sig == RTLIL::State::S0) - netname = "GND_NET"; - else if (sig == RTLIL::State::S1) - netname = "VCC_NET"; - else { - netname = log_signal(sig); - for (size_t i = 0; i < netname.size(); i++) - if (netname[i] == ' ' || netname[i] == '\\') - netname.erase(netname.begin() + i--); - } - *f << stringf(" (net %s (joined\n", EDIF_DEF(netname)); - for (auto &ref : it.second) - *f << stringf(" %s\n", ref.c_str()); - if (sig.wire == NULL) { - if (nogndvcc) - log_error("Design contains constant nodes (map with \"hilomap\" first).\n"); - if (sig == RTLIL::State::S0) - *f << stringf(" (portRef %c (instanceRef GND))\n", gndvccy ? 'Y' : 'G'); - if (sig == RTLIL::State::S1) - *f << stringf(" (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P'); - } - *f << stringf(" ))\n"); - } - *f << stringf(" )\n"); - *f << stringf(" )\n"); - *f << stringf(" )\n"); - } - *f << stringf(" )\n"); - - *f << stringf(" (design %s\n", EDIF_DEF(top_module_name)); - *f << stringf(" (cellRef %s (libraryRef DESIGN))\n", EDIF_REF(top_module_name)); - *f << stringf(" )\n"); - - *f << stringf(")\n"); - } -} EdifBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/edif/runtest.py b/yosys/backends/edif/runtest.py deleted file mode 100644 index 826876a86..000000000 --- a/yosys/backends/edif/runtest.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python3 - -import os -import numpy as np - -enable_upto = True -enable_offset = True -enable_hierarchy = True -enable_logic = True - -def make_module(f, modname, width, subs): - print("module %s (A, B, C, X, Y, Z);" % modname, file=f) - inbits = list() - outbits = list() - - for p in "ABC": - offset = np.random.randint(10) if enable_offset else 0 - if enable_upto and np.random.randint(2): - print(" input [%d:%d] %s;" % (offset, offset+width-1, p), file=f) - else: - print(" input [%d:%d] %s;" % (offset+width-1, offset, p), file=f) - for i in range(offset, offset+width): - inbits.append("%s[%d]" % (p, i)) - - for p in "XYZ": - offset = np.random.randint(10) if enable_offset else 0 - if enable_upto and np.random.randint(2): - print(" output [%d:%d] %s;" % (offset, offset+width-1, p), file=f) - else: - print(" output [%d:%d] %s;" % (offset+width-1, offset, p), file=f) - for i in range(offset, offset+width): - outbits.append("%s[%d]" % (p, i)) - - instidx = 0 - subcandidates = list(subs.keys()) - - while len(outbits) > 0: - submod = None - if len(subcandidates): - submod = np.random.choice(subcandidates) - subcandidates.remove(submod) - - if submod is None or 3*subs[submod] >= len(outbits): - for bit in outbits: - if enable_logic: - print(" assign %s = %s & ~%s;" % (bit, np.random.choice(inbits), np.random.choice(inbits)), file=f) - else: - print(" assign %s = %s;" % (bit, np.random.choice(inbits)), file=f) - break - - instidx += 1 - print(" %s inst%d (" % (submod, instidx), file=f) - - for p in "ABC": - print(" .%s({%s})," % (p, ",".join(np.random.choice(inbits, subs[submod]))), file=f) - - for p in "XYZ": - bits = list(np.random.choice(outbits, subs[submod], False)) - for bit in bits: - outbits.remove(bit) - print(" .%s({%s})%s" % (p, ",".join(bits), "," if p != "Z" else ""), file=f) - - print(" );", file=f); - - print("endmodule", file=f) - -with open("test_top.v", "w") as f: - if enable_hierarchy: - make_module(f, "sub1", 2, {}) - make_module(f, "sub2", 3, {}) - make_module(f, "sub3", 4, {}) - make_module(f, "sub4", 8, {"sub1": 2, "sub2": 3, "sub3": 4}) - make_module(f, "sub5", 8, {"sub1": 2, "sub2": 3, "sub3": 4}) - make_module(f, "sub6", 8, {"sub1": 2, "sub2": 3, "sub3": 4}) - make_module(f, "top", 32, {"sub4": 8, "sub5": 8, "sub6": 8}) - else: - make_module(f, "top", 32, {}) - -os.system("set -x; ../../yosys -p 'synth_xilinx -top top; write_edif -pvector par test_syn.edif' test_top.v") - -with open("test_syn.tcl", "w") as f: - print("read_edif test_syn.edif", file=f) - print("link_design", file=f) - print("write_verilog -force test_syn.v", file=f) - -os.system("set -x; vivado -nojournal -nolog -mode batch -source test_syn.tcl") - -with open("test_tb.v", "w") as f: - print("module tb;", file=f) - print(" reg [31:0] A, B, C;", file=f) - print(" wire [31:0] X, Y, Z;", file=f) - print("", file=f) - print(" top uut (", file=f) - print(" .A(A),", file=f) - print(" .B(B),", file=f) - print(" .C(C),", file=f) - print(" .X(X),", file=f) - print(" .Y(Y),", file=f) - print(" .Z(Z)", file=f) - print(" );", file=f) - print("", file=f) - print(" initial begin", file=f) - for i in range(100): - print(" A = 32'h%08x;" % np.random.randint(2**32), file=f) - print(" B = 32'h%08x;" % np.random.randint(2**32), file=f) - print(" C = 32'h%08x;" % np.random.randint(2**32), file=f) - print(" #10;", file=f) - print(" $display(\"%x %x %x\", X, Y, Z);", file=f) - print(" #10;", file=f) - print(" $finish;", file=f) - print(" end", file=f) - print("endmodule", file=f) - -os.system("set -x; iverilog -o test_gold test_tb.v test_top.v") -os.system("set -x; iverilog -o test_gate test_tb.v test_syn.v ../../techlibs/xilinx/cells_sim.v") - -os.system("set -x; ./test_gold > test_gold.out") -os.system("set -x; ./test_gate > test_gate.out") - -os.system("set -x; md5sum test_gold.out test_gate.out") - diff --git a/yosys/backends/firrtl/.gitignore b/yosys/backends/firrtl/.gitignore deleted file mode 100644 index a2ac93abe..000000000 --- a/yosys/backends/firrtl/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -test.fir -test_out.v diff --git a/yosys/backends/firrtl/Makefile.inc b/yosys/backends/firrtl/Makefile.inc deleted file mode 100644 index fdf100d34..000000000 --- a/yosys/backends/firrtl/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/firrtl/firrtl.o - diff --git a/yosys/backends/firrtl/firrtl.cc b/yosys/backends/firrtl/firrtl.cc deleted file mode 100644 index 1c7a7351f..000000000 --- a/yosys/backends/firrtl/firrtl.cc +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/cellaigs.h" -#include "kernel/log.h" -#include -#include -#include -#include -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -pool used_names; -dict namecache; -int autoid_counter; - -typedef unsigned FDirection; -static const FDirection FD_NODIRECTION = 0x0; -static const FDirection FD_IN = 0x1; -static const FDirection FD_OUT = 0x2; -static const FDirection FD_INOUT = 0x3; -static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width - -// Get a port direction with respect to a specific module. -FDirection getPortFDirection(IdString id, Module *module) -{ - Wire *wire = module->wires_.at(id); - FDirection direction = FD_NODIRECTION; - if (wire && wire->port_id) - { - if (wire->port_input) - direction |= FD_IN; - if (wire->port_output) - direction |= FD_OUT; - } - return direction; -} - -string next_id() -{ - string new_id; - - while (1) { - new_id = stringf("_%d", autoid_counter++); - if (used_names.count(new_id) == 0) break; - } - - used_names.insert(new_id); - return new_id; -} - -const char *make_id(IdString id) -{ - if (namecache.count(id) != 0) - return namecache.at(id).c_str(); - - string new_id = log_id(id); - - for (int i = 0; i < GetSize(new_id); i++) - { - char &ch = new_id[i]; - if ('a' <= ch && ch <= 'z') continue; - if ('A' <= ch && ch <= 'Z') continue; - if ('0' <= ch && ch <= '9' && i != 0) continue; - if ('_' == ch) continue; - ch = '_'; - } - - while (used_names.count(new_id) != 0) - new_id += '_'; - - namecache[id] = new_id; - used_names.insert(new_id); - return namecache.at(id).c_str(); -} - -struct FirrtlWorker -{ - Module *module; - std::ostream &f; - - dict> reverse_wire_map; - string unconn_id; - RTLIL::Design *design; - std::string indent; - - // Define read/write ports and memories. - // We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction. - // For the moment, we don't handle $readmemh or $readmemb. - // These will be part of a subsequent PR. - struct read_port { - string name; - bool clk_enable; - bool clk_parity; - bool transparent; - RTLIL::SigSpec clk; - RTLIL::SigSpec ena; - RTLIL::SigSpec addr; - read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) { - // Current (3/13/2019) conventions: - // generate a constant 0 for clock and a constant 1 for enable if they are undefined. - if (!clk.is_fully_def()) - this->clk = SigSpec(RTLIL::Const(0, 1)); - if (!ena.is_fully_def()) - this->ena = SigSpec(RTLIL::Const(1, 1)); - } - string gen_read(const char * indent) { - string addr_expr = make_expr(addr); - string ena_expr = make_expr(ena); - string clk_expr = make_expr(clk); - string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str()); - string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str()); - string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str()); - return addr_str + ena_str + clk_str; - } - }; - struct write_port : read_port { - RTLIL::SigSpec mask; - write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) { - if (!clk.is_fully_def()) - this->clk = SigSpec(RTLIL::Const(0)); - if (!ena.is_fully_def()) - this->ena = SigSpec(RTLIL::Const(0)); - if (!mask.is_fully_def()) - this->ena = SigSpec(RTLIL::Const(1)); - } - string gen_read(const char * /* indent */) { - log_error("gen_read called on write_port: %s\n", name.c_str()); - return stringf("gen_read called on write_port: %s\n", name.c_str()); - } - string gen_write(const char * indent) { - string addr_expr = make_expr(addr); - string ena_expr = make_expr(ena); - string clk_expr = make_expr(clk); - string mask_expr = make_expr(mask); - string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str()); - string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str()); - string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str()); - string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str()); - return addr_str + ena_str + clk_str + mask_str; - } - }; - /* Memories defined within this module. */ - struct memory { - Cell *pCell; // for error reporting - string name; // memory name - int abits; // number of address bits - int size; // size (in units) of the memory - int width; // size (in bits) of each element - int read_latency; - int write_latency; - vector read_ports; - vector write_ports; - std::string init_file; - std::string init_file_srcFileSpec; - string srcLine; - memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") { - // Provide defaults for abits or size if one (but not the other) is specified. - if (this->abits == 0 && this->size != 0) { - this->abits = ceil_log2(this->size); - } else if (this->abits != 0 && this->size == 0) { - this->size = 1 << this->abits; - } - // Sanity-check this construction. - if (this->name == "") { - log_error("Nameless memory%s\n", this->atLine()); - } - if (this->abits == 0 && this->size == 0) { - log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine()); - } - if (this->width == 0) { - log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine()); - } - } - // We need a default constructor for the dict insert. - memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} - - const char *atLine() { - if (srcLine == "") { - if (pCell) { - auto p = pCell->attributes.find("\\src"); - srcLine = " at " + p->second.decode_string(); - } - } - return srcLine.c_str(); - } - void add_memory_read_port(read_port &rp) { - read_ports.push_back(rp); - } - void add_memory_write_port(write_port &wp) { - write_ports.push_back(wp); - } - void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { - this->init_file = init_file; - this->init_file_srcFileSpec = init_file_srcFileSpec; - } - - }; - dict memories; - - void register_memory(memory &m) - { - memories[m.name] = m; - } - - void register_reverse_wire_map(string id, SigSpec sig) - { - for (int i = 0; i < GetSize(sig); i++) - reverse_wire_map[sig[i]] = make_pair(id, i); - } - - FirrtlWorker(Module *module, std::ostream &f, RTLIL::Design *theDesign) : module(module), f(f), design(theDesign), indent(" ") - { - } - - static string make_expr(const SigSpec &sig) - { - string expr; - - for (auto chunk : sig.chunks()) - { - string new_expr; - - if (chunk.wire == nullptr) - { - std::vector bits = chunk.data; - new_expr = stringf("UInt<%d>(\"h", GetSize(bits)); - - while (GetSize(bits) % 4 != 0) - bits.push_back(State::S0); - - for (int i = GetSize(bits)-4; i >= 0; i -= 4) - { - int val = 0; - if (bits[i+0] == State::S1) val += 1; - if (bits[i+1] == State::S1) val += 2; - if (bits[i+2] == State::S1) val += 4; - if (bits[i+3] == State::S1) val += 8; - new_expr.push_back(val < 10 ? '0' + val : 'a' + val - 10); - } - - new_expr += "\")"; - } - else if (chunk.offset == 0 && chunk.width == chunk.wire->width) - { - new_expr = make_id(chunk.wire->name); - } - else - { - string wire_id = make_id(chunk.wire->name); - new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset); - } - - if (expr.empty()) - expr = new_expr; - else - expr = "cat(" + new_expr + ", " + expr + ")"; - } - - return expr; - } - - std::string fid(RTLIL::IdString internal_id) - { - return make_id(internal_id); - } - - std::string cellname(RTLIL::Cell *cell) - { - return fid(cell->name).c_str(); - } - - void process_instance(RTLIL::Cell *cell, vector &wire_exprs) - { - std::string cell_type = fid(cell->type); - std::string instanceOf; - // If this is a parameterized module, its parent module is encoded in the cell type - if (cell->type.substr(0, 8) == "$paramod") - { - std::string::iterator it; - for (it = cell_type.begin(); it < cell_type.end(); it++) - { - switch (*it) { - case '\\': /* FALL_THROUGH */ - case '=': /* FALL_THROUGH */ - case '\'': /* FALL_THROUGH */ - case '$': instanceOf.append("_"); break; - default: instanceOf.append(1, *it); break; - } - } - } - else - { - instanceOf = cell_type; - } - - std::string cell_name = cellname(cell); - std::string cell_name_comment; - if (cell_name != fid(cell->name)) - cell_name_comment = " /* " + fid(cell->name) + " */ "; - else - cell_name_comment = ""; - // Find the module corresponding to this instance. - auto instModule = design->module(cell->type); - // If there is no instance for this, just return. - if (instModule == NULL) - { - log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str()); - return; - } - wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str())); - - for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { - if (it->second.size() > 0) { - const SigSpec &secondSig = it->second; - const std::string firstName = cell_name + "." + make_id(it->first); - const std::string secondExpr = make_expr(secondSig); - // Find the direction for this port. - FDirection dir = getPortFDirection(it->first, instModule); - std::string sourceExpr, sinkExpr; - const SigSpec *sinkSig = nullptr; - switch (dir) { - case FD_INOUT: - log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); - /* FALLTHRU */ - case FD_OUT: - sourceExpr = firstName; - sinkExpr = secondExpr; - sinkSig = &secondSig; - break; - case FD_NODIRECTION: - log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); - /* FALLTHRU */ - case FD_IN: - sourceExpr = secondExpr; - sinkExpr = firstName; - break; - default: - log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir); - break; - } - // Check for subfield assignment. - std::string bitsString = "bits("; - if (sinkExpr.substr(0, bitsString.length()) == bitsString ) { - if (sinkSig == nullptr) - log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str()); - // Don't generate the assignment here. - // Add the source and sink to the "reverse_wire_map" and we'll output the assignment - // as part of the coalesced subfield assignments for this wire. - register_reverse_wire_map(sourceExpr, *sinkSig); - } else { - wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str())); - } - } - } - wire_exprs.push_back(stringf("\n")); - - } - - // Given an expression for a shift amount, and a maximum width, - // generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics. - std::string gen_dshl(const string b_expr, const int b_padded_width) - { - string result = b_expr; - if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) { - int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; - string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<name)); - vector port_decls, wire_decls, cell_exprs, wire_exprs; - - for (auto wire : module->wires()) - { - const auto wireName = make_id(wire->name); - // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it. - if (wire->attributes.count("\\init")) { - log_warning("Initial value (%s) for (%s.%s) not supported\n", - wire->attributes.at("\\init").as_string().c_str(), - log_id(module), log_id(wire)); - } - if (wire->port_id) - { - if (wire->port_input && wire->port_output) - log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire)); - port_decls.push_back(stringf(" %s %s: UInt<%d>\n", wire->port_input ? "input" : "output", - wireName, wire->width)); - } - else - { - wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", wireName, wire->width)); - } - } - - for (auto cell : module->cells()) - { - bool extract_y_bits = false; // Assume no extraction of final bits will be required. - // Is this cell is a module instance? - if (cell->type[0] != '$') - { - process_instance(cell, wire_exprs); - continue; - } - if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor")) - { - string y_id = make_id(cell->name); - bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); - string a_expr = make_expr(cell->getPort("\\A")); - wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - - if (cell->parameters.at("\\A_SIGNED").as_bool()) { - a_expr = "asSInt(" + a_expr + ")"; - } - - // Don't use the results of logical operations (a single bit) to control padding - if (!(cell->type.in("$eq", "$eqx", "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$reduce_bool", "$logic_not") && y_width == 1) ) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); - } - - string primop; - bool always_uint = false; - if (cell->type == "$not") primop = "not"; - else if (cell->type == "$neg") { - primop = "neg"; - is_signed = true; // Result of "neg" is signed (an SInt). - } else if (cell->type == "$logic_not") { - primop = "eq"; - a_expr = stringf("%s, UInt(0)", a_expr.c_str()); - } - else if (cell->type == "$reduce_and") primop = "andr"; - else if (cell->type == "$reduce_or") primop = "orr"; - else if (cell->type == "$reduce_xor") primop = "xorr"; - else if (cell->type == "$reduce_xnor") { - primop = "not"; - a_expr = stringf("xorr(%s)", a_expr.c_str()); - } - else if (cell->type == "$reduce_bool") { - primop = "neq"; - // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. - bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - int a_width = cell->parameters.at("\\A_WIDTH").as_int(); - a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width); - } - - string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str()); - - if ((is_signed && !always_uint)) - expr = stringf("asUInt(%s)", expr.c_str()); - - cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, cell->getPort("\\Y")); - - continue; - } - if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx", - "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", - "$logic_and", "$logic_or")) - { - string y_id = make_id(cell->name); - bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); - string a_expr = make_expr(cell->getPort("\\A")); - string b_expr = make_expr(cell->getPort("\\B")); - int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); - wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - - if (cell->parameters.at("\\A_SIGNED").as_bool()) { - a_expr = "asSInt(" + a_expr + ")"; - } - // Shift amount is always unsigned, and needn't be padded to result width. - if (!cell->type.in("$shr", "$sshr", "$shl", "$sshl")) { - if (cell->parameters.at("\\B_SIGNED").as_bool()) { - b_expr = "asSInt(" + b_expr + ")"; - } - if (b_padded_width < y_width) { - auto b_sig = cell->getPort("\\B"); - b_padded_width = y_width; - } - } - - auto a_sig = cell->getPort("\\A"); - - if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) { - a_expr = "asUInt(" + a_expr + ")"; - } - - string primop; - bool always_uint = false; - if (cell->type == "$add") primop = "add"; - else if (cell->type == "$sub") primop = "sub"; - else if (cell->type == "$mul") primop = "mul"; - else if (cell->type == "$div") primop = "div"; - else if (cell->type == "$mod") primop = "rem"; - else if (cell->type == "$and") { - primop = "and"; - always_uint = true; - } - else if (cell->type == "$or" ) { - primop = "or"; - always_uint = true; - } - else if (cell->type == "$xor") { - primop = "xor"; - always_uint = true; - } - else if ((cell->type == "$eq") | (cell->type == "$eqx")) { - primop = "eq"; - always_uint = true; - } - else if ((cell->type == "$ne") | (cell->type == "$nex")) { - primop = "neq"; - always_uint = true; - } - else if (cell->type == "$gt") { - primop = "gt"; - always_uint = true; - } - else if (cell->type == "$ge") { - primop = "geq"; - always_uint = true; - } - else if (cell->type == "$lt") { - primop = "lt"; - always_uint = true; - } - else if (cell->type == "$le") { - primop = "leq"; - always_uint = true; - } - else if ((cell->type == "$shl") | (cell->type == "$sshl")) { - // FIRRTL will widen the result (y) by the amount of the shift. - // We'll need to offset this by extracting the un-widened portion as Verilog would do. - extract_y_bits = true; - // Is the shift amount constant? - auto b_sig = cell->getPort("\\B"); - if (b_sig.is_fully_const()) { - primop = "shl"; - b_expr = std::to_string(b_sig.as_int()); - } else { - primop = "dshl"; - // Convert from FIRRTL left shift semantics. - b_expr = gen_dshl(b_expr, b_padded_width); - } - } - else if ((cell->type == "$shr") | (cell->type == "$sshr")) { - // We don't need to extract a specific range of bits. - extract_y_bits = false; - // Is the shift amount constant? - auto b_sig = cell->getPort("\\B"); - if (b_sig.is_fully_const()) { - primop = "shr"; - b_expr = std::to_string(b_sig.as_int()); - } else { - primop = "dshr"; - } - } - else if ((cell->type == "$logic_and")) { - primop = "and"; - a_expr = "neq(" + a_expr + ", UInt(0))"; - b_expr = "neq(" + b_expr + ", UInt(0))"; - always_uint = true; - } - else if ((cell->type == "$logic_or")) { - primop = "or"; - a_expr = "neq(" + a_expr + ", UInt(0))"; - b_expr = "neq(" + b_expr + ", UInt(0))"; - always_uint = true; - } - - if (!cell->parameters.at("\\B_SIGNED").as_bool()) { - b_expr = "asUInt(" + b_expr + ")"; - } - - string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); - - // Deal with FIRRTL's "shift widens" semantics - if (extract_y_bits) { - expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); - } - - if ((is_signed && !always_uint) || cell->type.in("$sub")) - expr = stringf("asUInt(%s)", expr.c_str()); - - cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, cell->getPort("\\Y")); - - continue; - } - - if (cell->type.in("$mux")) - { - string y_id = make_id(cell->name); - int width = cell->parameters.at("\\WIDTH").as_int(); - string a_expr = make_expr(cell->getPort("\\A")); - string b_expr = make_expr(cell->getPort("\\B")); - string s_expr = make_expr(cell->getPort("\\S")); - wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), width)); - - string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str()); - - cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, cell->getPort("\\Y")); - - continue; - } - - if (cell->type.in("$mem")) - { - string mem_id = make_id(cell->name); - int abits = cell->parameters.at("\\ABITS").as_int(); - int width = cell->parameters.at("\\WIDTH").as_int(); - int size = cell->parameters.at("\\SIZE").as_int(); - memory m(cell, mem_id, abits, size, width); - int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); - int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); - - Const initdata = cell->parameters.at("\\INIT"); - for (State bit : initdata.bits) - if (bit != State::Sx) - log_error("Memory with initialization data: %s.%s\n", log_id(module), log_id(cell)); - - Const rd_clk_enable = cell->parameters.at("\\RD_CLK_ENABLE"); - Const wr_clk_enable = cell->parameters.at("\\WR_CLK_ENABLE"); - Const wr_clk_polarity = cell->parameters.at("\\WR_CLK_POLARITY"); - - int offset = cell->parameters.at("\\OFFSET").as_int(); - if (offset != 0) - log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell)); - - for (int i = 0; i < rd_ports; i++) - { - if (rd_clk_enable[i] != State::S0) - log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - - SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits); - SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width); - string addr_expr = make_expr(addr_sig); - string name(stringf("%s.r%d", m.name.c_str(), i)); - bool clk_enable = false; - bool clk_parity = true; - bool transparency = false; - SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1); - SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1); - read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig); - m.add_memory_read_port(rp); - cell_exprs.push_back(rp.gen_read(indent.c_str())); - register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig); - } - - for (int i = 0; i < wr_ports; i++) - { - if (wr_clk_enable[i] != State::S1) - log_error("Unclocked write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - - if (wr_clk_polarity[i] != State::S1) - log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - - string name(stringf("%s.w%d", m.name.c_str(), i)); - bool clk_enable = true; - bool clk_parity = true; - bool transparency = false; - SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits); - string addr_expr = make_expr(addr_sig); - SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width); - string data_expr = make_expr(data_sig); - SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i); - string clk_expr = make_expr(clk_sig); - - SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width); - string wen_expr = make_expr(wen_sig[0]); - - for (int i = 1; i < GetSize(wen_sig); i++) - if (wen_sig[0] != wen_sig[i]) - log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - - SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1); - write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig); - m.add_memory_write_port(wp); - cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str())); - cell_exprs.push_back(wp.gen_write(indent.c_str())); - } - register_memory(m); - continue; - } - - if (cell->type.in("$memwr", "$memrd", "$meminit")) - { - std::string cell_type = fid(cell->type); - std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); - int abits = cell->parameters.at("\\ABITS").as_int(); - int width = cell->parameters.at("\\WIDTH").as_int(); - memory *mp = nullptr; - if (cell->type == "$meminit" ) { - log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); - } else { - // It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition. - auto addrSig = cell->getPort("\\ADDR"); - auto dataSig = cell->getPort("\\DATA"); - auto enableSig = cell->getPort("\\EN"); - auto clockSig = cell->getPort("\\CLK"); - Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); - Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); - - // Do we already have an entry for this memory? - if (memories.count(mem_id) == 0) { - memory m(cell, mem_id, abits, 0, width); - register_memory(m); - } - mp = &memories.at(mem_id); - int portNum = 0; - bool transparency = false; - string data_expr = make_expr(dataSig); - if (cell->type.in("$memwr")) { - portNum = (int) mp->write_ports.size(); - write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig, dataSig); - mp->add_memory_write_port(wp); - cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str())); - cell_exprs.push_back(wp.gen_write(indent.c_str())); - } else if (cell->type.in("$memrd")) { - portNum = (int) mp->read_ports.size(); - read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig); - mp->add_memory_read_port(rp); - cell_exprs.push_back(rp.gen_read(indent.c_str())); - register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig); - } - } - continue; - } - - if (cell->type.in("$dff")) - { - bool clkpol = cell->parameters.at("\\CLK_POLARITY").as_bool(); - if (clkpol == false) - log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell)); - - string q_id = make_id(cell->name); - int width = cell->parameters.at("\\WIDTH").as_int(); - string expr = make_expr(cell->getPort("\\D")); - string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")"; - - wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", q_id.c_str(), width, clk_expr.c_str())); - - cell_exprs.push_back(stringf(" %s <= %s\n", q_id.c_str(), expr.c_str())); - register_reverse_wire_map(q_id, cell->getPort("\\Q")); - - continue; - } - - // This may be a parameterized module - paramod. - if (cell->type.substr(0, 8) == "$paramod") - { - process_instance(cell, wire_exprs); - continue; - } - if (cell->type == "$shiftx") { - // assign y = a[b +: y_width]; - // We'll extract the correct bits as part of the primop. - - string y_id = make_id(cell->name); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); - string a_expr = make_expr(cell->getPort("\\A")); - // Get the initial bit selector - string b_expr = make_expr(cell->getPort("\\B")); - wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - - if (cell->getParam("\\B_SIGNED").as_bool()) { - // Use validif to constrain the selection (test the sign bit) - auto b_string = b_expr.c_str(); - int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1; - b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string); - } - string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str()); - - cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, cell->getPort("\\Y")); - continue; - } - if (cell->type == "$shift") { - // assign y = a >> b; - // where b may be negative - - string y_id = make_id(cell->name); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); - string a_expr = make_expr(cell->getPort("\\A")); - string b_expr = make_expr(cell->getPort("\\B")); - auto b_string = b_expr.c_str(); - int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); - string expr; - wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - - if (cell->getParam("\\B_SIGNED").as_bool()) { - // We generate a left or right shift based on the sign of b. - std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width); - std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); - expr = stringf("mux(%s < 0, %s, %s)", - b_string, - dshl.c_str(), - dshr.c_str() - ); - } else { - expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); - } - cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, cell->getPort("\\Y")); - continue; - } - log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); - } - - for (auto conn : module->connections()) - { - string y_id = next_id(); - int y_width = GetSize(conn.first); - string expr = make_expr(conn.second); - - wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, conn.first); - } - - for (auto wire : module->wires()) - { - string expr; - - if (wire->port_input) - continue; - - int cursor = 0; - bool is_valid = false; - bool make_unconn_id = false; - - while (cursor < wire->width) - { - int chunk_width = 1; - string new_expr; - - SigBit start_bit(wire, cursor); - - if (reverse_wire_map.count(start_bit)) - { - pair start_map = reverse_wire_map.at(start_bit); - - while (cursor+chunk_width < wire->width) - { - SigBit stop_bit(wire, cursor+chunk_width); - - if (reverse_wire_map.count(stop_bit) == 0) - break; - - pair stop_map = reverse_wire_map.at(stop_bit); - stop_map.second -= chunk_width; - - if (start_map != stop_map) - break; - - chunk_width++; - } - - new_expr = stringf("bits(%s, %d, %d)", start_map.first.c_str(), - start_map.second + chunk_width - 1, start_map.second); - is_valid = true; - } - else - { - if (unconn_id.empty()) { - unconn_id = next_id(); - make_unconn_id = true; - } - new_expr = unconn_id; - } - - if (expr.empty()) - expr = new_expr; - else - expr = "cat(" + new_expr + ", " + expr + ")"; - - cursor += chunk_width; - } - - if (is_valid) { - if (make_unconn_id) { - wire_decls.push_back(stringf(" wire %s: UInt<1>\n", unconn_id.c_str())); - wire_decls.push_back(stringf(" %s is invalid\n", unconn_id.c_str())); - } - wire_exprs.push_back(stringf(" %s <= %s\n", make_id(wire->name), expr.c_str())); - } else { - if (make_unconn_id) { - unconn_id.clear(); - } - wire_decls.push_back(stringf(" %s is invalid\n", make_id(wire->name))); - } - } - - for (auto str : port_decls) - f << str; - - f << stringf("\n"); - - for (auto str : wire_decls) - f << str; - - f << stringf("\n"); - - // If we have any memory definitions, output them. - for (auto kv : memories) { - memory &m = kv.second; - f << stringf(" mem %s:\n", m.name.c_str()); - f << stringf(" data-type => UInt<%d>\n", m.width); - f << stringf(" depth => %d\n", m.size); - for (int i = 0; i < (int) m.read_ports.size(); i += 1) { - f << stringf(" reader => r%d\n", i); - } - for (int i = 0; i < (int) m.write_ports.size(); i += 1) { - f << stringf(" writer => w%d\n", i); - } - f << stringf(" read-latency => %d\n", m.read_latency); - f << stringf(" write-latency => %d\n", m.write_latency); - f << stringf(" read-under-write => undefined\n"); - } - f << stringf("\n"); - - for (auto str : cell_exprs) - f << str; - - f << stringf("\n"); - - for (auto str : wire_exprs) - f << str; - } -}; - -struct FirrtlBackend : public Backend { - FirrtlBackend() : Backend("firrtl", "write design to a FIRRTL file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_firrtl [options] [filename]\n"); - log("\n"); - log("Write a FIRRTL netlist of the current design.\n"); - log("The following commands are executed by this command:\n"); - log(" pmuxtree\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - size_t argidx = args.size(); // We aren't expecting any arguments. - - // If we weren't explicitly passed a filename, use the last argument (if it isn't a flag). - if (filename == "") { - if (argidx > 0 && args[argidx - 1][0] != '-') { - // extra_args and friends need to see this argument. - argidx -= 1; - filename = args[argidx]; - } - } - extra_args(f, filename, args, argidx); - - if (!design->full_selection()) - log_cmd_error("This command only operates on fully selected designs!\n"); - - log_header(design, "Executing FIRRTL backend.\n"); - log_push(); - - Pass::call(design, stringf("pmuxtree")); - - namecache.clear(); - autoid_counter = 0; - - // Get the top module, or a reasonable facsimile - we need something for the circuit name. - Module *top = design->top_module(); - Module *last = nullptr; - // Generate module and wire names. - for (auto module : design->modules()) { - make_id(module->name); - last = module; - if (top == nullptr && module->get_bool_attribute("\\top")) { - top = module; - } - for (auto wire : module->wires()) - if (wire->port_id) - make_id(wire->name); - } - - if (top == nullptr) - top = last; - - *f << stringf("circuit %s:\n", make_id(top->name)); - - for (auto module : design->modules()) - { - FirrtlWorker worker(module, *f, design); - worker.run(); - } - - namecache.clear(); - autoid_counter = 0; - } -} FirrtlBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/firrtl/test.sh b/yosys/backends/firrtl/test.sh deleted file mode 100644 index fe7e3a329..000000000 --- a/yosys/backends/firrtl/test.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -ex - -cd ../../ -make -cd backends/firrtl - -../../yosys -q -p 'prep -nordff; write_firrtl test.fir' $1 - -firrtl -i test.fir -o test_out.v -ll Info - -../../yosys -p " - read_verilog $1 - rename Top gold - - read_verilog test_out.v - rename Top gate - - prep - memory_map - miter -equiv -flatten gold gate miter - hierarchy -top miter - - sat -verify -prove trigger 0 -set-init-zero -seq 10 miter -" diff --git a/yosys/backends/firrtl/test.v b/yosys/backends/firrtl/test.v deleted file mode 100644 index c6d62a847..000000000 --- a/yosys/backends/firrtl/test.v +++ /dev/null @@ -1,63 +0,0 @@ -module test( - input clk, wen, - input [7:0] uns, - input signed [7:0] a, b, - input signed [23:0] c, - input signed [2:0] sel, - output [15:0] s, d, y, z, u, q, p, mul, div, mod, mux, And, Or, Xor, eq, neq, gt, lt, geq, leq, eqx, shr, sshr, shl, sshl, Land, Lor, Lnot, Not, Neg, pos, Andr, Orr, Xorr, Xnorr, Reduce_bool, - output [7:0] PMux -); - //initial begin - //$display("shr = %b", shr); - //end - assign s = a+{b[6:2], 2'b1}; - assign d = a-b; - assign y = x; - assign z[7:0] = s+d; - assign z[15:8] = s-d; - assign p = a & b | x; - assign mul = a * b; - assign div = a / b; - assign mod = a % b; - assign mux = x[0] ? a : b; - assign And = a & b; - assign Or = a | b; - assign Xor = a ^ b; - assign Not = ~a; - assign Neg = -a; - assign eq = a == b; - assign neq = a != b; - assign gt = a > b; - assign lt = a < b; - assign geq = a >= b; - assign leq = a <= b; - assign eqx = a === b; - assign shr = a >> b; //0111111111000000 - assign sshr = a >>> b; - assign shl = a << b; - assign sshl = a <<< b; - assign Land = a && b; - assign Lor = a || b; - assign Lnot = !a; - assign pos = $signed(uns); - assign Andr = &a; - assign Orr = |a; - assign Xorr = ^a; - assign Xnorr = ~^a; - always @* - if(!a) begin - Reduce_bool = a; - end else begin - Reduce_bool = b; - end - //always @(sel or c or a) - // begin - // case (sel) - // 3'b000: PMux = a; - // 3'b001: PMux = c[7:0]; - // 3'b010: PMux = c[15:8]; - // 3'b100: PMux = c[23:16]; - // endcase - // end - -endmodule diff --git a/yosys/backends/ilang/Makefile.inc b/yosys/backends/ilang/Makefile.inc deleted file mode 100644 index 52fc2b891..000000000 --- a/yosys/backends/ilang/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/ilang/ilang_backend.o - diff --git a/yosys/backends/ilang/ilang_backend.cc b/yosys/backends/ilang/ilang_backend.cc deleted file mode 100644 index 313af7d5c..000000000 --- a/yosys/backends/ilang/ilang_backend.cc +++ /dev/null @@ -1,513 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward backend for the RTLIL text - * representation (as understood by the 'ilang' frontend). - * - */ - -#include "ilang_backend.h" -#include "kernel/yosys.h" -#include - -USING_YOSYS_NAMESPACE -using namespace ILANG_BACKEND; -YOSYS_NAMESPACE_BEGIN - -void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint) -{ - if (width < 0) - width = data.bits.size() - offset; - if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { - if (width == 32 && autoint) { - int32_t val = 0; - for (int i = 0; i < width; i++) { - log_assert(offset+i < (int)data.bits.size()); - switch (data.bits[offset+i]) { - case RTLIL::S0: break; - case RTLIL::S1: val |= 1 << i; break; - default: val = -1; break; - } - } - if (val >= 0) { - f << stringf("%d", val); - return; - } - } - f << stringf("%d'", width); - for (int i = offset+width-1; i >= offset; i--) { - log_assert(i < (int)data.bits.size()); - switch (data.bits[i]) { - case RTLIL::S0: f << stringf("0"); break; - case RTLIL::S1: f << stringf("1"); break; - case RTLIL::Sx: f << stringf("x"); break; - case RTLIL::Sz: f << stringf("z"); break; - case RTLIL::Sa: f << stringf("-"); break; - case RTLIL::Sm: f << stringf("m"); break; - } - } - } else { - f << stringf("\""); - std::string str = data.decode_string(); - for (size_t i = 0; i < str.size(); i++) { - if (str[i] == '\n') - f << stringf("\\n"); - else if (str[i] == '\t') - f << stringf("\\t"); - else if (str[i] < 32) - f << stringf("\\%03o", str[i]); - else if (str[i] == '"') - f << stringf("\\\""); - else if (str[i] == '\\') - f << stringf("\\\\"); - else - f << str[i]; - } - f << stringf("\""); - } -} - -void ILANG_BACKEND::dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint) -{ - if (chunk.wire == NULL) { - dump_const(f, chunk.data, chunk.width, chunk.offset, autoint); - } else { - if (chunk.width == chunk.wire->width && chunk.offset == 0) - f << stringf("%s", chunk.wire->name.c_str()); - else if (chunk.width == 1) - f << stringf("%s [%d]", chunk.wire->name.c_str(), chunk.offset); - else - f << stringf("%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset); - } -} - -void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint) -{ - if (sig.is_chunk()) { - dump_sigchunk(f, sig.as_chunk(), autoint); - } else { - f << stringf("{ "); - for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) { - dump_sigchunk(f, *it, false); - f << stringf(" "); - } - f << stringf("}"); - } -} - -void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire) -{ - for (auto &it : wire->attributes) { - f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str()); - dump_const(f, it.second); - f << stringf("\n"); - } - f << stringf("%s" "wire ", indent.c_str()); - if (wire->width != 1) - f << stringf("width %d ", wire->width); - if (wire->upto) - f << stringf("upto "); - if (wire->start_offset != 0) - f << stringf("offset %d ", wire->start_offset); - if (wire->port_input && !wire->port_output) - f << stringf("input %d ", wire->port_id); - if (!wire->port_input && wire->port_output) - f << stringf("output %d ", wire->port_id); - if (wire->port_input && wire->port_output) - f << stringf("inout %d ", wire->port_id); - f << stringf("%s\n", wire->name.c_str()); -} - -void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory) -{ - for (auto &it : memory->attributes) { - f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str()); - dump_const(f, it.second); - f << stringf("\n"); - } - f << stringf("%s" "memory ", indent.c_str()); - if (memory->width != 1) - f << stringf("width %d ", memory->width); - if (memory->size != 0) - f << stringf("size %d ", memory->size); - if (memory->start_offset != 0) - f << stringf("offset %d ", memory->start_offset); - f << stringf("%s\n", memory->name.c_str()); -} - -void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell) -{ - for (auto &it : cell->attributes) { - f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str()); - dump_const(f, it.second); - f << stringf("\n"); - } - f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str()); - for (auto &it : cell->parameters) { - f << stringf("%s parameter%s%s %s ", indent.c_str(), - (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", - (it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "", - it.first.c_str()); - dump_const(f, it.second); - f << stringf("\n"); - } - for (auto &it : cell->connections()) { - f << stringf("%s connect %s ", indent.c_str(), it.first.c_str()); - dump_sigspec(f, it.second); - f << stringf("\n"); - } - f << stringf("%s" "end\n", indent.c_str()); -} - -void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs) -{ - for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, it->first); - f << stringf(" "); - dump_sigspec(f, it->second); - f << stringf("\n"); - } - - for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it) - dump_proc_switch(f, indent, *it); -} - -void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw) -{ - for (auto it = sw->attributes.begin(); it != sw->attributes.end(); ++it) { - f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str()); - dump_const(f, it->second); - f << stringf("\n"); - } - - f << stringf("%s" "switch ", indent.c_str()); - dump_sigspec(f, sw->signal); - f << stringf("\n"); - - for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) - { - for (auto ait = (*it)->attributes.begin(); ait != (*it)->attributes.end(); ++ait) { - f << stringf("%s attribute %s ", indent.c_str(), ait->first.c_str()); - dump_const(f, ait->second); - f << stringf("\n"); - } - f << stringf("%s case ", indent.c_str()); - for (size_t i = 0; i < (*it)->compare.size(); i++) { - if (i > 0) - f << stringf(" , "); - dump_sigspec(f, (*it)->compare[i]); - } - f << stringf("\n"); - - dump_proc_case_body(f, indent + " ", *it); - } - - f << stringf("%s" "end\n", indent.c_str()); -} - -void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy) -{ - f << stringf("%s" "sync ", indent.c_str()); - switch (sy->type) { - case RTLIL::ST0: f << stringf("low "); - if (0) case RTLIL::ST1: f << stringf("high "); - if (0) case RTLIL::STp: f << stringf("posedge "); - if (0) case RTLIL::STn: f << stringf("negedge "); - if (0) case RTLIL::STe: f << stringf("edge "); - dump_sigspec(f, sy->signal); - f << stringf("\n"); - break; - case RTLIL::STa: f << stringf("always\n"); break; - case RTLIL::STg: f << stringf("global\n"); break; - case RTLIL::STi: f << stringf("init\n"); break; - } - - for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) { - f << stringf("%s update ", indent.c_str()); - dump_sigspec(f, it->first); - f << stringf(" "); - dump_sigspec(f, it->second); - f << stringf("\n"); - } -} - -void ILANG_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc) -{ - for (auto it = proc->attributes.begin(); it != proc->attributes.end(); ++it) { - f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str()); - dump_const(f, it->second); - f << stringf("\n"); - } - f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str()); - dump_proc_case_body(f, indent + " ", &proc->root_case); - for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it) - dump_proc_sync(f, indent + " ", *it); - f << stringf("%s" "end\n", indent.c_str()); -} - -void ILANG_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) -{ - f << stringf("%s" "connect ", indent.c_str()); - dump_sigspec(f, left); - f << stringf(" "); - dump_sigspec(f, right); - f << stringf("\n"); -} - -void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n) -{ - bool print_header = flag_m || design->selected_whole_module(module->name); - bool print_body = !flag_n || !design->selected_whole_module(module->name); - - if (print_header) - { - for (auto it = module->attributes.begin(); it != module->attributes.end(); ++it) { - f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str()); - dump_const(f, it->second); - f << stringf("\n"); - } - - f << stringf("%s" "module %s\n", indent.c_str(), module->name.c_str()); - - if (!module->avail_parameters.empty()) { - if (only_selected) - f << stringf("\n"); - for (auto &p : module->avail_parameters) - f << stringf("%s" " parameter %s\n", indent.c_str(), p.c_str()); - } - } - - if (print_body) - { - for (auto it : module->wires()) - if (!only_selected || design->selected(module, it)) { - if (only_selected) - f << stringf("\n"); - dump_wire(f, indent + " ", it); - } - - for (auto it : module->memories) - if (!only_selected || design->selected(module, it.second)) { - if (only_selected) - f << stringf("\n"); - dump_memory(f, indent + " ", it.second); - } - - for (auto it : module->cells()) - if (!only_selected || design->selected(module, it)) { - if (only_selected) - f << stringf("\n"); - dump_cell(f, indent + " ", it); - } - - for (auto it : module->processes) - if (!only_selected || design->selected(module, it.second)) { - if (only_selected) - f << stringf("\n"); - dump_proc(f, indent + " ", it.second); - } - - bool first_conn_line = true; - for (auto it = module->connections().begin(); it != module->connections().end(); ++it) { - bool show_conn = !only_selected; - if (only_selected) { - RTLIL::SigSpec sigs = it->first; - sigs.append(it->second); - for (auto &c : sigs.chunks()) { - if (c.wire == NULL || !design->selected(module, c.wire)) - continue; - show_conn = true; - } - } - if (show_conn) { - if (only_selected && first_conn_line) - f << stringf("\n"); - dump_conn(f, indent + " ", it->first, it->second); - first_conn_line = false; - } - } - } - - if (print_header) - f << stringf("%s" "end\n", indent.c_str()); -} - -void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n) -{ -#ifndef NDEBUG - int init_autoidx = autoidx; -#endif - - if (!flag_m) { - int count_selected_mods = 0; - for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) { - if (design->selected_whole_module(it->first)) - flag_m = true; - if (design->selected(it->second)) - count_selected_mods++; - } - if (count_selected_mods > 1) - flag_m = true; - } - - if (!only_selected || flag_m) { - if (only_selected) - f << stringf("\n"); - f << stringf("autoidx %d\n", autoidx); - } - - for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) { - if (!only_selected || design->selected(it->second)) { - if (only_selected) - f << stringf("\n"); - dump_module(f, "", it->second, design, only_selected, flag_m, flag_n); - } - } - - log_assert(init_autoidx == autoidx); -} - -YOSYS_NAMESPACE_END -PRIVATE_NAMESPACE_BEGIN - -struct IlangBackend : public Backend { - IlangBackend() : Backend("ilang", "write design to ilang file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_ilang [filename]\n"); - log("\n"); - log("Write the current design to an 'ilang' file. (ilang is a text representation\n"); - log("of a design in yosys's internal format.)\n"); - log("\n"); - log(" -selected\n"); - log(" only write selected parts of the design.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - bool selected = false; - - log_header(design, "Executing ILANG backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-selected") { - selected = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - design->sort(); - - log("Output filename: %s\n", filename.c_str()); - *f << stringf("# Generated by %s\n", yosys_version_str); - ILANG_BACKEND::dump_design(*f, design, selected, true, false); - } -} IlangBackend; - -struct DumpPass : public Pass { - DumpPass() : Pass("dump", "print parts of the design in ilang format") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" dump [options] [selection]\n"); - log("\n"); - log("Write the selected parts of the design to the console or specified file in\n"); - log("ilang format.\n"); - log("\n"); - log(" -m\n"); - log(" also dump the module headers, even if only parts of a single\n"); - log(" module is selected\n"); - log("\n"); - log(" -n\n"); - log(" only dump the module headers if the entire module is selected\n"); - log("\n"); - log(" -o \n"); - log(" write to the specified file.\n"); - log("\n"); - log(" -a \n"); - log(" like -outfile but append instead of overwrite\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - std::string filename; - bool flag_m = false, flag_n = false, append = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - std::string arg = args[argidx]; - if ((arg == "-o" || arg == "-outfile") && argidx+1 < args.size()) { - filename = args[++argidx]; - append = false; - continue; - } - if ((arg == "-a" || arg == "-append") && argidx+1 < args.size()) { - filename = args[++argidx]; - append = true; - continue; - } - if (arg == "-m") { - flag_m = true; - continue; - } - if (arg == "-n") { - flag_n = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - std::ostream *f; - std::stringstream buf; - - if (!filename.empty()) { - rewrite_filename(filename); - std::ofstream *ff = new std::ofstream; - ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc); - if (ff->fail()) { - delete ff; - log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); - } - f = ff; - } else { - f = &buf; - } - - ILANG_BACKEND::dump_design(*f, design, true, flag_m, flag_n); - - if (!filename.empty()) { - delete f; - } else { - log("%s", buf.str().c_str()); - } - } -} DumpPass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/ilang/ilang_backend.h b/yosys/backends/ilang/ilang_backend.h deleted file mode 100644 index 97dcbb628..000000000 --- a/yosys/backends/ilang/ilang_backend.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward backend for the RTLIL text - * representation (as understood by the 'ilang' frontend). - * - */ - -#ifndef ILANG_BACKEND_H -#define ILANG_BACKEND_H - -#include "kernel/yosys.h" -#include - -YOSYS_NAMESPACE_BEGIN - -namespace ILANG_BACKEND { - void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true); - void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true); - void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true); - void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); - void dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory); - void dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell); - void dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs); - void dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw); - void dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy); - void dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc); - void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right); - void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false); - void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false); -} - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/backends/intersynth/Makefile.inc b/yosys/backends/intersynth/Makefile.inc deleted file mode 100644 index 85df1b393..000000000 --- a/yosys/backends/intersynth/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/intersynth/intersynth.o - diff --git a/yosys/backends/intersynth/intersynth.cc b/yosys/backends/intersynth/intersynth.cc deleted file mode 100644 index b0e3cd252..000000000 --- a/yosys/backends/intersynth/intersynth.cc +++ /dev/null @@ -1,220 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -static std::string netname(std::set &conntypes_code, std::set &celltypes_code, std::set &constcells_code, RTLIL::SigSpec sig) -{ - if (!sig.is_fully_const() && !sig.is_wire()) - log_error("Can't export composite or non-word-wide signal %s.\n", log_signal(sig)); - - conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size())); - - if (sig.is_fully_const()) { - celltypes_code.insert(stringf("celltype CONST_%d b%d *CONST cfg:%d VALUE\n", sig.size(), sig.size(), sig.size())); - constcells_code.insert(stringf("node CONST_%d_0x%x CONST_%d CONST CONST_%d_0x%x VALUE 0x%x\n", - sig.size(), sig.as_int(), sig.size(), sig.size(), sig.as_int(), sig.as_int())); - return stringf("CONST_%d_0x%x", sig.size(), sig.as_int()); - } - - return RTLIL::unescape_id(sig.as_wire()->name); -} - -struct IntersynthBackend : public Backend { - IntersynthBackend() : Backend("intersynth", "write design to InterSynth netlist file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_intersynth [options] [filename]\n"); - log("\n"); - log("Write the current design to an 'intersynth' netlist file. InterSynth is\n"); - log("a tool for Coarse-Grain Example-Driven Interconnect Synthesis.\n"); - log("\n"); - log(" -notypes\n"); - log(" do not generate celltypes and conntypes commands. i.e. just output\n"); - log(" the netlists. this is used for postsilicon synthesis.\n"); - log("\n"); - log(" -lib \n"); - log(" Use the specified library file for determining whether cell ports are\n"); - log(" inputs or outputs. This option can be used multiple times to specify\n"); - log(" more than one library.\n"); - log("\n"); - log(" -selected\n"); - log(" only write selected modules. modules must be selected entirely or\n"); - log(" not at all.\n"); - log("\n"); - log("http://www.clifford.at/intersynth/\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing INTERSYNTH backend.\n"); - log_push(); - - std::vector libfiles; - std::vector libs; - bool flag_notypes = false; - bool selected = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-notypes") { - flag_notypes = true; - continue; - } - if (args[argidx] == "-lib" && argidx+1 < args.size()) { - libfiles.push_back(args[++argidx]); - continue; - } - if (args[argidx] == "-selected") { - selected = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - log("Output filename: %s\n", filename.c_str()); - - for (auto filename : libfiles) { - std::ifstream f; - f.open(filename.c_str()); - if (f.fail()) - log_error("Can't open lib file `%s'.\n", filename.c_str()); - RTLIL::Design *lib = new RTLIL::Design; - Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog"); - libs.push_back(lib); - } - - if (libs.size() > 0) - log_header(design, "Continuing INTERSYNTH backend.\n"); - - std::set conntypes_code, celltypes_code; - std::string netlists_code; - CellTypes ct(design); - - for (auto lib : libs) - ct.setup_design(lib); - - for (auto module_it : design->modules_) - { - RTLIL::Module *module = module_it.second; - SigMap sigmap(module); - - if (module->get_blackbox_attribute()) - continue; - if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0) - continue; - - if (selected && !design->selected_whole_module(module->name)) { - if (design->selected_module(module->name)) - log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(module->name)); - continue; - } - - log("Generating netlist %s.\n", RTLIL::id2cstr(module->name)); - - if (module->memories.size() != 0 || module->processes.size() != 0) - log_error("Can't generate a netlist for a module with unprocessed memories or processes!\n"); - - std::set constcells_code; - netlists_code += stringf("# Netlist of module %s\n", RTLIL::id2cstr(module->name)); - netlists_code += stringf("netlist %s\n", RTLIL::id2cstr(module->name)); - - // Module Ports: "std::set celltypes_code" prevents duplicate top level ports - for (auto wire_it : module->wires_) { - RTLIL::Wire *wire = wire_it.second; - if (wire->port_input || wire->port_output) { - celltypes_code.insert(stringf("celltype !%s b%d %sPORT\n" "%s %s %d %s PORT\n", - RTLIL::id2cstr(wire->name), wire->width, wire->port_input ? "*" : "", - wire->port_input ? "input" : "output", RTLIL::id2cstr(wire->name), wire->width, RTLIL::id2cstr(wire->name))); - netlists_code += stringf("node %s %s PORT %s\n", RTLIL::id2cstr(wire->name), RTLIL::id2cstr(wire->name), - netname(conntypes_code, celltypes_code, constcells_code, sigmap(wire)).c_str()); - } - } - - // Submodules: "std::set celltypes_code" prevents duplicate cell types - for (auto cell_it : module->cells_) - { - RTLIL::Cell *cell = cell_it.second; - std::string celltype_code, node_code; - - if (!ct.cell_known(cell->type)) - log_error("Found unknown cell type %s in module!\n", RTLIL::id2cstr(cell->type)); - - celltype_code = stringf("celltype %s", RTLIL::id2cstr(cell->type)); - node_code = stringf("node %s %s", RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); - for (auto &port : cell->connections()) { - RTLIL::SigSpec sig = sigmap(port.second); - if (sig.size() != 0) { - conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size())); - celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", RTLIL::id2cstr(port.first)); - node_code += stringf(" %s %s", RTLIL::id2cstr(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str()); - } - } - for (auto ¶m : cell->parameters) { - celltype_code += stringf(" cfg:%d %s", int(param.second.bits.size()), RTLIL::id2cstr(param.first)); - if (param.second.bits.size() != 32) { - node_code += stringf(" %s '", RTLIL::id2cstr(param.first)); - for (int i = param.second.bits.size()-1; i >= 0; i--) - node_code += param.second.bits[i] == RTLIL::S1 ? "1" : "0"; - } else - node_code += stringf(" %s 0x%x", RTLIL::id2cstr(param.first), param.second.as_int()); - } - - celltypes_code.insert(celltype_code + "\n"); - netlists_code += node_code + "\n"; - } - - if (constcells_code.size() > 0) - netlists_code += "# constant cells\n"; - for (auto code : constcells_code) - netlists_code += code; - netlists_code += "\n"; - } - - if (!flag_notypes) { - *f << stringf("### Connection Types\n"); - for (auto code : conntypes_code) - *f << stringf("%s", code.c_str()); - *f << stringf("\n### Cell Types\n"); - for (auto code : celltypes_code) - *f << stringf("%s", code.c_str()); - } - *f << stringf("\n### Netlists\n"); - *f << stringf("%s", netlists_code.c_str()); - - for (auto lib : libs) - delete lib; - - log_pop(); - } -} IntersynthBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/json/Makefile.inc b/yosys/backends/json/Makefile.inc deleted file mode 100644 index a463daf91..000000000 --- a/yosys/backends/json/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/json/json.o - diff --git a/yosys/backends/json/json.cc b/yosys/backends/json/json.cc deleted file mode 100644 index dda4dfedd..000000000 --- a/yosys/backends/json/json.cc +++ /dev/null @@ -1,559 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/cellaigs.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct JsonWriter -{ - std::ostream &f; - bool use_selection; - bool aig_mode; - - Design *design; - Module *module; - - SigMap sigmap; - int sigidcounter; - dict sigids; - pool aig_models; - - JsonWriter(std::ostream &f, bool use_selection, bool aig_mode) : - f(f), use_selection(use_selection), aig_mode(aig_mode) { } - - string get_string(string str) - { - string newstr = "\""; - for (char c : str) { - if (c == '\\') - newstr += c; - newstr += c; - } - return newstr + "\""; - } - - string get_name(IdString name) - { - return get_string(RTLIL::unescape_id(name)); - } - - string get_bits(SigSpec sig) - { - bool first = true; - string str = "["; - for (auto bit : sigmap(sig)) { - str += first ? " " : ", "; - first = false; - if (sigids.count(bit) == 0) { - string &s = sigids[bit]; - if (bit.wire == nullptr) { - if (bit == State::S0) s = "\"0\""; - else if (bit == State::S1) s = "\"1\""; - else if (bit == State::Sz) s = "\"z\""; - else s = "\"x\""; - } else - s = stringf("%d", sigidcounter++); - } - str += sigids[bit]; - } - return str + " ]"; - } - - void write_parameters(const dict ¶meters, bool for_module=false) - { - bool first = true; - for (auto ¶m : parameters) { - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str()); - if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) - f << get_string(param.second.decode_string()); - else if (GetSize(param.second.bits) > 32) - f << get_string(param.second.as_string()); - else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) - f << stringf("%d", param.second.as_int()); - else - f << stringf("%u", param.second.as_int()); - first = false; - } - } - - void write_module(Module *module_) - { - module = module_; - log_assert(module->design == design); - sigmap.set(module); - sigids.clear(); - - // reserve 0 and 1 to avoid confusion with "0" and "1" - sigidcounter = 2; - - f << stringf(" %s: {\n", get_name(module->name).c_str()); - - f << stringf(" \"attributes\": {"); - write_parameters(module->attributes, /*for_module=*/true); - f << stringf("\n },\n"); - - f << stringf(" \"ports\": {"); - bool first = true; - for (auto n : module->ports) { - Wire *w = module->wire(n); - if (use_selection && !module->selected(w)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(n).c_str()); - f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output"); - if (w->start_offset) - f << stringf(" \"offset\": %d,\n", w->start_offset); - if (w->upto) - f << stringf(" \"upto\": 1,\n"); - f << stringf(" \"bits\": %s\n", get_bits(w).c_str()); - f << stringf(" }"); - first = false; - } - f << stringf("\n },\n"); - - f << stringf(" \"cells\": {"); - first = true; - for (auto c : module->cells()) { - if (use_selection && !module->selected(c)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(c->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); - f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); - if (aig_mode) { - Aig aig(c); - if (!aig.name.empty()) { - f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); - aig_models.insert(aig); - } - } - f << stringf(" \"parameters\": {"); - write_parameters(c->parameters); - f << stringf("\n },\n"); - f << stringf(" \"attributes\": {"); - write_parameters(c->attributes); - f << stringf("\n },\n"); - if (c->known()) { - f << stringf(" \"port_directions\": {"); - bool first2 = true; - for (auto &conn : c->connections()) { - string direction = "output"; - if (c->input(conn.first)) - direction = c->output(conn.first) ? "inout" : "input"; - f << stringf("%s\n", first2 ? "" : ","); - f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); - first2 = false; - } - f << stringf("\n },\n"); - } - f << stringf(" \"connections\": {"); - bool first2 = true; - for (auto &conn : c->connections()) { - f << stringf("%s\n", first2 ? "" : ","); - f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str()); - first2 = false; - } - f << stringf("\n }\n"); - f << stringf(" }"); - first = false; - } - f << stringf("\n },\n"); - - f << stringf(" \"netnames\": {"); - first = true; - for (auto w : module->wires()) { - if (use_selection && !module->selected(w)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(w->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); - f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); - if (w->start_offset) - f << stringf(" \"offset\": %d,\n", w->start_offset); - if (w->upto) - f << stringf(" \"upto\": 1,\n"); - f << stringf(" \"attributes\": {"); - write_parameters(w->attributes); - f << stringf("\n }\n"); - f << stringf(" }"); - first = false; - } - f << stringf("\n }\n"); - - f << stringf(" }"); - } - - void write_design(Design *design_) - { - design = design_; - design->sort(); - - f << stringf("{\n"); - f << stringf(" \"creator\": %s,\n", get_string(yosys_version_str).c_str()); - f << stringf(" \"modules\": {\n"); - vector modules = use_selection ? design->selected_modules() : design->modules(); - bool first_module = true; - for (auto mod : modules) { - if (!first_module) - f << stringf(",\n"); - write_module(mod); - first_module = false; - } - f << stringf("\n }"); - if (!aig_models.empty()) { - f << stringf(",\n \"models\": {\n"); - bool first_model = true; - for (auto &aig : aig_models) { - if (!first_model) - f << stringf(",\n"); - f << stringf(" \"%s\": [\n", aig.name.c_str()); - int node_idx = 0; - for (auto &node : aig.nodes) { - if (node_idx != 0) - f << stringf(",\n"); - f << stringf(" /* %3d */ [ ", node_idx); - if (node.portbit >= 0) - f << stringf("\"%sport\", \"%s\", %d", node.inverter ? "n" : "", - log_id(node.portname), node.portbit); - else if (node.left_parent < 0 && node.right_parent < 0) - f << stringf("\"%s\"", node.inverter ? "true" : "false"); - else - f << stringf("\"%s\", %d, %d", node.inverter ? "nand" : "and", node.left_parent, node.right_parent); - for (auto &op : node.outports) - f << stringf(", \"%s\", %d", log_id(op.first), op.second); - f << stringf(" ]"); - node_idx++; - } - f << stringf("\n ]"); - first_model = false; - } - f << stringf("\n }"); - } - f << stringf("\n}\n"); - } -}; - -struct JsonBackend : public Backend { - JsonBackend() : Backend("json", "write design to a JSON file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_json [options] [filename]\n"); - log("\n"); - log("Write a JSON netlist of the current design.\n"); - log("\n"); - log(" -aig\n"); - log(" include AIG models for the different gate types\n"); - log("\n"); - log("\n"); - log("The general syntax of the JSON output created by this command is as follows:\n"); - log("\n"); - log(" {\n"); - log(" \"modules\": {\n"); - log(" : {\n"); - log(" \"ports\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"cells\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"netnames\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" }\n"); - log(" }\n"); - log(" },\n"); - log(" \"models\": {\n"); - log(" ...\n"); - log(" },\n"); - log(" }\n"); - log("\n"); - log("Where is:\n"); - log("\n"); - log(" {\n"); - log(" \"direction\": <\"input\" | \"output\" | \"inout\">,\n"); - log(" \"bits\": \n"); - log(" }\n"); - log("\n"); - log("And is:\n"); - log("\n"); - log(" {\n"); - log(" \"hide_name\": <1 | 0>,\n"); - log(" \"type\": ,\n"); - log(" \"parameters\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"attributes\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"port_directions\": {\n"); - log(" : <\"input\" | \"output\" | \"inout\">,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"connections\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" }\n"); - log("\n"); - log("And is:\n"); - log("\n"); - log(" {\n"); - log(" \"hide_name\": <1 | 0>,\n"); - log(" \"bits\": \n"); - log(" }\n"); - log("\n"); - log("The \"hide_name\" fields are set to 1 when the name of this cell or net is\n"); - log("automatically created and is likely not of interest for a regular user.\n"); - log("\n"); - log("The \"port_directions\" section is only included for cells for which the\n"); - log("interface is known.\n"); - log("\n"); - log("Module and cell ports and nets can be single bit wide or vectors of multiple\n"); - log("bits. Each individual signal bit is assigned a unique integer. The \n"); - log("values referenced above are vectors of this integers. Signal bits that are\n"); - log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n"); - log("a number.\n"); - log("\n"); - log("Numeric parameter and attribute values up to 32 bits are written as decimal\n"); - log("values. Numbers larger than that are written as string holding the binary\n"); - log("representation of the value.\n"); - log("\n"); - log("For example the following Verilog code:\n"); - log("\n"); - log(" module test(input x, y);\n"); - log(" (* keep *) foo #(.P(42), .Q(1337))\n"); - log(" foo_inst (.A({x, y}), .B({y, x}), .C({4'd10, {4{x}}}));\n"); - log(" endmodule\n"); - log("\n"); - log("Translates to the following JSON output:\n"); - log("\n"); - log(" {\n"); - log(" \"modules\": {\n"); - log(" \"test\": {\n"); - log(" \"ports\": {\n"); - log(" \"x\": {\n"); - log(" \"direction\": \"input\",\n"); - log(" \"bits\": [ 2 ]\n"); - log(" },\n"); - log(" \"y\": {\n"); - log(" \"direction\": \"input\",\n"); - log(" \"bits\": [ 3 ]\n"); - log(" }\n"); - log(" },\n"); - log(" \"cells\": {\n"); - log(" \"foo_inst\": {\n"); - log(" \"hide_name\": 0,\n"); - log(" \"type\": \"foo\",\n"); - log(" \"parameters\": {\n"); - log(" \"Q\": 1337,\n"); - log(" \"P\": 42\n"); - log(" },\n"); - log(" \"attributes\": {\n"); - log(" \"keep\": 1,\n"); - log(" \"src\": \"test.v:2\"\n"); - log(" },\n"); - log(" \"connections\": {\n"); - log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ],\n"); - log(" \"B\": [ 2, 3 ],\n"); - log(" \"A\": [ 3, 2 ]\n"); - log(" }\n"); - log(" }\n"); - log(" },\n"); - log(" \"netnames\": {\n"); - log(" \"y\": {\n"); - log(" \"hide_name\": 0,\n"); - log(" \"bits\": [ 3 ],\n"); - log(" \"attributes\": {\n"); - log(" \"src\": \"test.v:1\"\n"); - log(" }\n"); - log(" },\n"); - log(" \"x\": {\n"); - log(" \"hide_name\": 0,\n"); - log(" \"bits\": [ 2 ],\n"); - log(" \"attributes\": {\n"); - log(" \"src\": \"test.v:1\"\n"); - log(" }\n"); - log(" }\n"); - log(" }\n"); - log(" }\n"); - log(" }\n"); - log(" }\n"); - log("\n"); - log("The models are given as And-Inverter-Graphs (AIGs) in the following form:\n"); - log("\n"); - log(" \"models\": {\n"); - log(" : [\n"); - log(" /* 0 */ [ ],\n"); - log(" /* 1 */ [ ],\n"); - log(" /* 2 */ [ ],\n"); - log(" ...\n"); - log(" ],\n"); - log(" ...\n"); - log(" },\n"); - log("\n"); - log("The following node-types may be used:\n"); - log("\n"); - log(" [ \"port\", , , ]\n"); - log(" - the value of the specified input port bit\n"); - log("\n"); - log(" [ \"nport\", , , ]\n"); - log(" - the inverted value of the specified input port bit\n"); - log("\n"); - log(" [ \"and\", , , ]\n"); - log(" - the ANDed value of the specified nodes\n"); - log("\n"); - log(" [ \"nand\", , , ]\n"); - log(" - the inverted ANDed value of the specified nodes\n"); - log("\n"); - log(" [ \"true\", ]\n"); - log(" - the constant value 1\n"); - log("\n"); - log(" [ \"false\", ]\n"); - log(" - the constant value 0\n"); - log("\n"); - log("All nodes appear in topological order. I.e. only nodes with smaller indices\n"); - log("are referenced by \"and\" and \"nand\" nodes.\n"); - log("\n"); - log("The optional at the end of a node specification is a list of\n"); - log("output portname and bitindex pairs, specifying the outputs driven by this node.\n"); - log("\n"); - log("For example, the following is the model for a 3-input 3-output $reduce_and cell\n"); - log("inferred by the following code:\n"); - log("\n"); - log(" module test(input [2:0] in, output [2:0] out);\n"); - log(" assign in = &out;\n"); - log(" endmodule\n"); - log("\n"); - log(" \"$reduce_and:3U:3\": [\n"); - log(" /* 0 */ [ \"port\", \"A\", 0 ],\n"); - log(" /* 1 */ [ \"port\", \"A\", 1 ],\n"); - log(" /* 2 */ [ \"and\", 0, 1 ],\n"); - log(" /* 3 */ [ \"port\", \"A\", 2 ],\n"); - log(" /* 4 */ [ \"and\", 2, 3, \"Y\", 0 ],\n"); - log(" /* 5 */ [ \"false\", \"Y\", 1, \"Y\", 2 ]\n"); - log(" ]\n"); - log("\n"); - log("Future version of Yosys might add support for additional fields in the JSON\n"); - log("format. A program processing this format must ignore all unknown fields.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - bool aig_mode = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-aig") { - aig_mode = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - log_header(design, "Executing JSON backend.\n"); - - JsonWriter json_writer(*f, false, aig_mode); - json_writer.write_design(design); - } -} JsonBackend; - -struct JsonPass : public Pass { - JsonPass() : Pass("json", "write design in JSON format") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" json [options] [selection]\n"); - log("\n"); - log("Write a JSON netlist of all selected objects.\n"); - log("\n"); - log(" -o \n"); - log(" write to the specified file.\n"); - log("\n"); - log(" -aig\n"); - log(" also include AIG models for the different gate types\n"); - log("\n"); - log("See 'help write_json' for a description of the JSON format used.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - std::string filename; - bool aig_mode = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-o" && argidx+1 < args.size()) { - filename = args[++argidx]; - continue; - } - if (args[argidx] == "-aig") { - aig_mode = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - std::ostream *f; - std::stringstream buf; - - if (!filename.empty()) { - rewrite_filename(filename); - std::ofstream *ff = new std::ofstream; - ff->open(filename.c_str(), std::ofstream::trunc); - if (ff->fail()) { - delete ff; - log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); - } - f = ff; - } else { - f = &buf; - } - - JsonWriter json_writer(*f, true, aig_mode); - json_writer.write_design(design); - - if (!filename.empty()) { - delete f; - } else { - log("%s", buf.str().c_str()); - } - } -} JsonPass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/protobuf/.gitignore b/yosys/backends/protobuf/.gitignore deleted file mode 100644 index 849b38d45..000000000 --- a/yosys/backends/protobuf/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -yosys.pb.cc -yosys.pb.h diff --git a/yosys/backends/protobuf/Makefile.inc b/yosys/backends/protobuf/Makefile.inc deleted file mode 100644 index 834cad42c..000000000 --- a/yosys/backends/protobuf/Makefile.inc +++ /dev/null @@ -1,8 +0,0 @@ -ifeq ($(ENABLE_PROTOBUF),1) - -backends/protobuf/yosys.pb.cc backends/protobuf/yosys.pb.h: misc/yosys.proto - $(Q) cd misc && protoc --cpp_out "../backends/protobuf" yosys.proto - -OBJS += backends/protobuf/protobuf.o backends/protobuf/yosys.pb.o - -endif diff --git a/yosys/backends/protobuf/protobuf.cc b/yosys/backends/protobuf/protobuf.cc deleted file mode 100644 index fff110bb0..000000000 --- a/yosys/backends/protobuf/protobuf.cc +++ /dev/null @@ -1,371 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * Copyright (C) 2018 Serge Bazanski - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/cellaigs.h" -#include "kernel/log.h" -#include "yosys.pb.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct ProtobufDesignSerializer -{ - bool aig_mode_; - bool use_selection_; - yosys::pb::Design *pb_; - - Design *design_; - Module *module_; - - SigMap sigmap_; - int sigidcounter_; - dict sigids_; - pool aig_models_; - - - ProtobufDesignSerializer(bool use_selection, bool aig_mode) : - aig_mode_(aig_mode), use_selection_(use_selection) { } - - string get_name(IdString name) - { - return RTLIL::unescape_id(name); - } - - - void serialize_parameters(google::protobuf::Map *out, - const dict ¶meters) - { - for (auto ¶m : parameters) { - std::string key = get_name(param.first); - - - yosys::pb::Parameter pb_param; - - if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) { - pb_param.set_str(param.second.decode_string()); - } else if (GetSize(param.second.bits) > 64) { - pb_param.set_str(param.second.as_string()); - } else { - pb_param.set_int_(param.second.as_int()); - } - - (*out)[key] = pb_param; - } - } - - void get_bits(yosys::pb::BitVector *out, SigSpec sig) - { - for (auto bit : sigmap_(sig)) { - auto sig = out->add_signal(); - - // Constant driver. - if (bit.wire == nullptr) { - if (bit == State::S0) sig->set_constant(sig->CONSTANT_DRIVER_LOW); - else if (bit == State::S1) sig->set_constant(sig->CONSTANT_DRIVER_HIGH); - else if (bit == State::Sz) sig->set_constant(sig->CONSTANT_DRIVER_Z); - else sig->set_constant(sig->CONSTANT_DRIVER_X); - continue; - } - - // Signal - give it a unique identifier. - if (sigids_.count(bit) == 0) { - sigids_[bit] = sigidcounter_++; - } - sig->set_id(sigids_[bit]); - } - } - - void serialize_module(yosys::pb::Module* out, Module *module) - { - module_ = module; - log_assert(module_->design == design_); - sigmap_.set(module_); - sigids_.clear(); - sigidcounter_ = 0; - - serialize_parameters(out->mutable_attribute(), module_->attributes); - - for (auto n : module_->ports) { - Wire *w = module->wire(n); - if (use_selection_ && !module_->selected(w)) - continue; - - yosys::pb::Module::Port pb_port; - pb_port.set_direction(w->port_input ? w->port_output ? - yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT : yosys::pb::DIRECTION_OUTPUT); - get_bits(pb_port.mutable_bits(), w); - (*out->mutable_port())[get_name(n)] = pb_port; - } - - for (auto c : module_->cells()) { - if (use_selection_ && !module_->selected(c)) - continue; - - yosys::pb::Module::Cell pb_cell; - pb_cell.set_hide_name(c->name[0] == '$'); - pb_cell.set_type(get_name(c->type)); - - if (aig_mode_) { - Aig aig(c); - if (aig.name.empty()) - continue; - pb_cell.set_model(aig.name); - aig_models_.insert(aig); - } - serialize_parameters(pb_cell.mutable_parameter(), c->parameters); - serialize_parameters(pb_cell.mutable_attribute(), c->attributes); - - if (c->known()) { - for (auto &conn : c->connections()) { - yosys::pb::Direction direction = yosys::pb::DIRECTION_OUTPUT; - if (c->input(conn.first)) - direction = c->output(conn.first) ? yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT; - (*pb_cell.mutable_port_direction())[get_name(conn.first)] = direction; - } - } - for (auto &conn : c->connections()) { - yosys::pb::BitVector vec; - get_bits(&vec, conn.second); - (*pb_cell.mutable_connection())[get_name(conn.first)] = vec; - } - - (*out->mutable_cell())[get_name(c->name)] = pb_cell; - } - - for (auto w : module_->wires()) { - if (use_selection_ && !module_->selected(w)) - continue; - - auto netname = out->add_netname(); - netname->set_hide_name(w->name[0] == '$'); - get_bits(netname->mutable_bits(), w); - serialize_parameters(netname->mutable_attributes(), w->attributes); - } - } - - - void serialize_models(google::protobuf::Map *models) - { - for (auto &aig : aig_models_) { - yosys::pb::Model pb_model; - for (auto &node : aig.nodes) { - auto pb_node = pb_model.add_node(); - if (node.portbit >= 0) { - if (node.inverter) { - pb_node->set_type(pb_node->TYPE_NPORT); - } else { - pb_node->set_type(pb_node->TYPE_PORT); - } - auto port = pb_node->mutable_port(); - port->set_portname(log_id(node.portname)); - port->set_bitindex(node.portbit); - } else if (node.left_parent < 0 && node.right_parent < 0) { - if (node.inverter) { - pb_node->set_type(pb_node->TYPE_TRUE); - } else { - pb_node->set_type(pb_node->TYPE_FALSE); - } - } else { - if (node.inverter) { - pb_node->set_type(pb_node->TYPE_NAND); - } else { - pb_node->set_type(pb_node->TYPE_AND); - } - auto gate = pb_node->mutable_gate(); - gate->set_left(node.left_parent); - gate->set_right(node.right_parent); - } - for (auto &op : node.outports) { - auto pb_op = pb_node->add_out_port(); - pb_op->set_name(log_id(op.first)); - pb_op->set_bit_index(op.second); - } - } - (*models)[aig.name] = pb_model; - } - } - - void serialize_design(yosys::pb::Design *pb, Design *design) - { - GOOGLE_PROTOBUF_VERIFY_VERSION; - pb_ = pb; - pb_->Clear(); - pb_->set_creator(yosys_version_str); - - design_ = design; - design_->sort(); - - auto modules = use_selection_ ? design_->selected_modules() : design_->modules(); - for (auto mod : modules) { - yosys::pb::Module pb_mod; - serialize_module(&pb_mod, mod); - (*pb->mutable_modules())[mod->name.str()] = pb_mod; - } - - serialize_models(pb_->mutable_models()); - } -}; - -struct ProtobufBackend : public Backend { - ProtobufBackend(): Backend("protobuf", "write design to a Protocol Buffer file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_protobuf [options] [filename]\n"); - log("\n"); - log("Write a JSON netlist of the current design.\n"); - log("\n"); - log(" -aig\n"); - log(" include AIG models for the different gate types\n"); - log("\n"); - log(" -text\n"); - log(" output protobuf in Text/ASCII representation\n"); - log("\n"); - log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n"); - log("Yosys source code distribution.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - bool aig_mode = false; - bool text_mode = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-aig") { - aig_mode = true; - continue; - } - if (args[argidx] == "-text") { - text_mode = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - log_header(design, "Executing Protobuf backend.\n"); - - yosys::pb::Design pb; - ProtobufDesignSerializer serializer(false, aig_mode); - serializer.serialize_design(&pb, design); - - if (text_mode) { - string out; - google::protobuf::TextFormat::PrintToString(pb, &out); - *f << out; - } else { - pb.SerializeToOstream(f); - } - } -} ProtobufBackend; - -struct ProtobufPass : public Pass { - ProtobufPass() : Pass("protobuf", "write design in Protobuf format") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" protobuf [options] [selection]\n"); - log("\n"); - log("Write a JSON netlist of all selected objects.\n"); - log("\n"); - log(" -o \n"); - log(" write to the specified file.\n"); - log("\n"); - log(" -aig\n"); - log(" include AIG models for the different gate types\n"); - log("\n"); - log(" -text\n"); - log(" output protobuf in Text/ASCII representation\n"); - log("\n"); - log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n"); - log("Yosys source code distribution.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - std::string filename; - bool aig_mode = false; - bool text_mode = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-o" && argidx+1 < args.size()) { - filename = args[++argidx]; - continue; - } - if (args[argidx] == "-aig") { - aig_mode = true; - continue; - } - if (args[argidx] == "-text") { - text_mode = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - std::ostream *f; - std::stringstream buf; - - if (!filename.empty()) { - rewrite_filename(filename); - std::ofstream *ff = new std::ofstream; - ff->open(filename.c_str(), std::ofstream::trunc); - if (ff->fail()) { - delete ff; - log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); - } - f = ff; - } else { - f = &buf; - } - - yosys::pb::Design pb; - ProtobufDesignSerializer serializer(true, aig_mode); - serializer.serialize_design(&pb, design); - - if (text_mode) { - string out; - google::protobuf::TextFormat::PrintToString(pb, &out); - *f << out; - } else { - pb.SerializeToOstream(f); - } - - if (!filename.empty()) { - delete f; - } else { - log("%s", buf.str().c_str()); - } - } -} ProtobufPass; - -PRIVATE_NAMESPACE_END; diff --git a/yosys/backends/simplec/.gitignore b/yosys/backends/simplec/.gitignore deleted file mode 100644 index f08796168..000000000 --- a/yosys/backends/simplec/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -test00_tb -test00_uut.c diff --git a/yosys/backends/simplec/Makefile.inc b/yosys/backends/simplec/Makefile.inc deleted file mode 100644 index fee1376c5..000000000 --- a/yosys/backends/simplec/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/simplec/simplec.o - diff --git a/yosys/backends/simplec/simplec.cc b/yosys/backends/simplec/simplec.cc deleted file mode 100644 index 6f2ccbe20..000000000 --- a/yosys/backends/simplec/simplec.cc +++ /dev/null @@ -1,810 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" -#include "kernel/utils.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct HierDirtyFlags; - -static pool reserved_cids; -static dict id2cid; - -static string cid(IdString id) -{ - if (id2cid.count(id) == 0) - { - string s = id.str(); - if (GetSize(s) < 2) log_abort(); - - if (s[0] == '\\') - s = s.substr(1); - - if ('0' <= s[0] && s[0] <= '9') { - s = "_" + s; - } - - for (int i = 0; i < GetSize(s); i++) { - if ('0' <= s[i] && s[i] <= '9') continue; - if ('A' <= s[i] && s[i] <= 'Z') continue; - if ('a' <= s[i] && s[i] <= 'z') continue; - s[i] = '_'; - } - - while (reserved_cids.count(s)) - s += "_"; - - reserved_cids.insert(s); - id2cid[id] = s; - } - - return id2cid.at(id); -} - -struct HierDirtyFlags -{ - int dirty; - Module *module; - IdString hiername; - HierDirtyFlags *parent; - pool dirty_bits; - pool dirty_cells; - pool sticky_dirty_bits; - dict children; - string prefix, log_prefix; - - HierDirtyFlags(Module *module, IdString hiername, HierDirtyFlags *parent, const string &prefix, const string &log_prefix) : - dirty(0), module(module), hiername(hiername), parent(parent), prefix(prefix), log_prefix(log_prefix) - { - for (Cell *cell : module->cells()) { - Module *mod = module->design->module(cell->type); - if (mod) children[cell->name] = new HierDirtyFlags(mod, cell->name, this, - prefix + cid(cell->name) + ".", log_prefix + "." + prefix + log_id(cell->name)); - } - } - - ~HierDirtyFlags() - { - for (auto &child : children) - delete child.second; - } - - void set_dirty(SigBit bit) - { - if (dirty_bits.count(bit)) - return; - - dirty_bits.insert(bit); - sticky_dirty_bits.insert(bit); - - HierDirtyFlags *p = this; - while (p != nullptr) { - p->dirty++; - p = p->parent; - } - } - - void unset_dirty(SigBit bit) - { - if (dirty_bits.count(bit) == 0) - return; - - dirty_bits.erase(bit); - - HierDirtyFlags *p = this; - while (p != nullptr) { - p->dirty--; - log_assert(p->dirty >= 0); - p = p->parent; - } - } - - void set_dirty(Cell *cell) - { - if (dirty_cells.count(cell)) - return; - - dirty_cells.insert(cell); - - HierDirtyFlags *p = this; - while (p != nullptr) { - p->dirty++; - p = p->parent; - } - } - - void unset_dirty(Cell *cell) - { - if (dirty_cells.count(cell) == 0) - return; - - dirty_cells.erase(cell); - - HierDirtyFlags *p = this; - while (p != nullptr) { - p->dirty--; - log_assert(p->dirty >= 0); - p = p->parent; - } - } -}; - -struct SimplecWorker -{ - bool verbose = false; - int max_uintsize = 32; - - Design *design; - dict sigmaps; - - vector signal_declarations; - pool generated_sigtypes; - - vector util_declarations; - pool generated_utils; - - vector struct_declarations; - pool generated_structs; - - vector funct_declarations; - - dict>>> bit2cell; - dict>> bit2output; - dict> driven_bits; - - dict topoidx; - - pool activated_cells; - pool reactivated_cells; - - SimplecWorker(Design *design) : design(design) - { - } - - string sigtype(int n) - { - string struct_name = stringf("signal%d_t", n); - - if (generated_sigtypes.count(n) == 0) - { - signal_declarations.push_back(""); - signal_declarations.push_back(stringf("#ifndef YOSYS_SIMPLEC_SIGNAL%d_T", n)); - signal_declarations.push_back(stringf("#define YOSYS_SIMPLEC_SIGNAL%d_T", n)); - signal_declarations.push_back(stringf("typedef struct {")); - - for (int k = 8; k <= max_uintsize; k = 2*k) - if (n <= k && k <= max_uintsize) { - signal_declarations.push_back(stringf(" uint%d_t value_%d_0 : %d;", k, n-1, n)); - goto end_struct; - } - - for (int k = 0; k < n; k += max_uintsize) { - int bits = std::min(max_uintsize, n-k); - signal_declarations.push_back(stringf(" uint%d_t value_%d_%d : %d;", max_uintsize, k+bits-1, k, bits)); - } - - end_struct: - signal_declarations.push_back(stringf("} signal%d_t;", n)); - signal_declarations.push_back(stringf("#endif")); - generated_sigtypes.insert(n); - } - - return struct_name; - } - - void util_ifdef_guard(string s) - { - for (int i = 0; i < GetSize(s); i++) - if ('a' <= s[i] && s[i] <= 'z') - s[i] -= 'a' - 'A'; - - util_declarations.push_back(""); - util_declarations.push_back(stringf("#ifndef %s", s.c_str())); - util_declarations.push_back(stringf("#define %s", s.c_str())); - } - - string util_get_bit(const string &signame, int n, int idx) - { - if (n == 1 && idx == 0) - return signame + ".value_0_0"; - - string util_name = stringf("yosys_simplec_get_bit_%d_of_%d", idx, n); - - if (generated_utils.count(util_name) == 0) - { - util_ifdef_guard(util_name); - util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str())); - util_declarations.push_back(stringf("{")); - - int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; - string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize); - - util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name.c_str(), word_offset)); - - util_declarations.push_back(stringf("}")); - util_declarations.push_back(stringf("#endif")); - generated_utils.insert(util_name); - } - - return stringf("%s(&%s)", util_name.c_str(), signame.c_str()); - } - - string util_set_bit(const string &signame, int n, int idx, const string &expr) - { - if (n == 1 && idx == 0) - return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str()); - - string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n); - - if (generated_utils.count(util_name) == 0) - { - util_ifdef_guard(util_name); - util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str())); - util_declarations.push_back(stringf("{")); - - int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; - string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize); - - #if 0 - util_declarations.push_back(stringf(" if (value)")); - util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset)); - util_declarations.push_back(stringf(" else")); - util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset)); - #else - util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);", - value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset)); - #endif - - util_declarations.push_back(stringf("}")); - util_declarations.push_back(stringf("#endif")); - generated_utils.insert(util_name); - } - - return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str()); - } - - void create_module_struct(Module *mod) - { - if (generated_structs.count(mod->name)) - return; - - generated_structs.insert(mod->name); - sigmaps[mod].set(mod); - - for (Wire *w : mod->wires()) - { - if (w->port_output) - for (auto bit : SigSpec(w)) - bit2output[mod][sigmaps.at(mod)(bit)].insert(bit); - } - - for (Cell *c : mod->cells()) - { - for (auto &conn : c->connections()) - { - if (!c->input(conn.first)) { - for (auto bit : sigmaps.at(mod)(conn.second)) - driven_bits[mod].insert(bit); - continue; - } - - int idx = 0; - for (auto bit : sigmaps.at(mod)(conn.second)) - bit2cell[mod][bit].insert(tuple(c, conn.first, idx++)); - } - - if (design->module(c->type)) - create_module_struct(design->module(c->type)); - } - - TopoSort topo; - - for (Cell *c : mod->cells()) - { - topo.node(c->name); - - for (auto &conn : c->connections()) - { - if (!c->input(conn.first)) - continue; - - for (auto bit : sigmaps.at(mod)(conn.second)) - for (auto &it : bit2cell[mod][bit]) - topo.edge(c->name, std::get<0>(it)->name); - } - } - - topo.analyze_loops = false; - topo.sort(); - - for (int i = 0; i < GetSize(topo.sorted); i++) - topoidx[mod->cell(topo.sorted[i])] = i; - - string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str()); - - for (int i = 0; i < GetSize(ifdef_name); i++) - if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z') - ifdef_name[i] -= 'a' - 'A'; - - struct_declarations.push_back(""); - struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str())); - struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str())); - struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str())); - struct_declarations.push_back("{"); - - struct_declarations.push_back(" // Input Ports"); - for (Wire *w : mod->wires()) - if (w->port_input) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); - - struct_declarations.push_back(""); - struct_declarations.push_back(" // Output Ports"); - for (Wire *w : mod->wires()) - if (!w->port_input && w->port_output) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); - - struct_declarations.push_back(""); - struct_declarations.push_back(" // Internal Wires"); - for (Wire *w : mod->wires()) - if (!w->port_input && !w->port_output) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); - - for (Cell *c : mod->cells()) - if (design->module(c->type)) - struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c))); - - struct_declarations.push_back(stringf("};")); - struct_declarations.push_back("#endif"); - } - - void eval_cell(HierDirtyFlags *work, Cell *cell) - { - if (cell->type.in("$_BUF_", "$_NOT_")) - { - SigBit a = sigmaps.at(work->module)(cell->getPort("\\A")); - SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y")); - - string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0"; - string expr; - - if (cell->type == "$_BUF_") expr = a_expr; - if (cell->type == "$_NOT_") expr = "!" + a_expr; - - log_assert(y.wire); - funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + - stringf(" // %s (%s)", log_id(cell), log_id(cell->type))); - - work->set_dirty(y); - return; - } - - if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) - { - SigBit a = sigmaps.at(work->module)(cell->getPort("\\A")); - SigBit b = sigmaps.at(work->module)(cell->getPort("\\B")); - SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y")); - - string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0"; - string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0"; - string expr; - - if (cell->type == "$_AND_") expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == "$_NAND_") expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == "$_OR_") expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == "$_NOR_") expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == "$_XOR_") expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == "$_XNOR_") expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == "$_ANDNOT_") expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == "$_ORNOT_") expr = stringf("%s | (!%s)", a_expr.c_str(), b_expr.c_str()); - - log_assert(y.wire); - funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + - stringf(" // %s (%s)", log_id(cell), log_id(cell->type))); - - work->set_dirty(y); - return; - } - - if (cell->type.in("$_AOI3_", "$_OAI3_")) - { - SigBit a = sigmaps.at(work->module)(cell->getPort("\\A")); - SigBit b = sigmaps.at(work->module)(cell->getPort("\\B")); - SigBit c = sigmaps.at(work->module)(cell->getPort("\\C")); - SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y")); - - string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0"; - string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0"; - string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0"; - string expr; - - if (cell->type == "$_AOI3_") expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); - if (cell->type == "$_OAI3_") expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); - - log_assert(y.wire); - funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + - stringf(" // %s (%s)", log_id(cell), log_id(cell->type))); - - work->set_dirty(y); - return; - } - - if (cell->type.in("$_AOI4_", "$_OAI4_")) - { - SigBit a = sigmaps.at(work->module)(cell->getPort("\\A")); - SigBit b = sigmaps.at(work->module)(cell->getPort("\\B")); - SigBit c = sigmaps.at(work->module)(cell->getPort("\\C")); - SigBit d = sigmaps.at(work->module)(cell->getPort("\\D")); - SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y")); - - string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0"; - string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0"; - string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0"; - string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0"; - string expr; - - if (cell->type == "$_AOI4_") expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str()); - if (cell->type == "$_OAI4_") expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str()); - - log_assert(y.wire); - funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + - stringf(" // %s (%s)", log_id(cell), log_id(cell->type))); - - work->set_dirty(y); - return; - } - - if (cell->type == "$_MUX_") - { - SigBit a = sigmaps.at(work->module)(cell->getPort("\\A")); - SigBit b = sigmaps.at(work->module)(cell->getPort("\\B")); - SigBit s = sigmaps.at(work->module)(cell->getPort("\\S")); - SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y")); - - string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0"; - string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0"; - string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0"; - - // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933) - string expr = stringf("%s ? (bool)%s : (bool)%s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str()); - - log_assert(y.wire); - funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + - stringf(" // %s (%s)", log_id(cell), log_id(cell->type))); - - work->set_dirty(y); - return; - } - - log_error("No C model for %s available at the moment (FIXME).\n", log_id(cell->type)); - } - - void eval_dirty(HierDirtyFlags *work) - { - while (work->dirty) - { - if (verbose && (!work->dirty_bits.empty() || !work->dirty_cells.empty())) - log(" In %s:\n", work->log_prefix.c_str()); - - while (!work->dirty_bits.empty() || !work->dirty_cells.empty()) - { - if (!work->dirty_bits.empty()) - { - SigSpec dirtysig(work->dirty_bits); - dirtysig.sort_and_unify(); - - for (SigChunk chunk : dirtysig.chunks()) { - if (chunk.wire == nullptr) - continue; - if (verbose) - log(" Propagating %s.%s[%d:%d].\n", work->log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset); - funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix.c_str(), log_signal(chunk))); - } - - for (SigBit bit : dirtysig) - { - if (bit2output[work->module].count(bit) && work->parent) - for (auto outbit : bit2output[work->module][bit]) - { - Module *parent_mod = work->parent->module; - Cell *parent_cell = parent_mod->cell(work->hiername); - - IdString port_name = outbit.wire->name; - int port_offset = outbit.offset; - SigBit parent_bit = sigmaps.at(parent_mod)(parent_cell->getPort(port_name)[port_offset]); - - log_assert(bit.wire && parent_bit.wire); - funct_declarations.push_back(util_set_bit(work->parent->prefix + cid(parent_bit.wire->name), parent_bit.wire->width, parent_bit.offset, - util_get_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset))); - work->parent->set_dirty(parent_bit); - - if (verbose) - log(" Propagating %s.%s[%d] -> %s.%s[%d].\n", work->log_prefix.c_str(), log_id(bit.wire), bit.offset, - work->parent->log_prefix.c_str(), log_id(parent_bit.wire), parent_bit.offset); - } - - for (auto &port : bit2cell[work->module][bit]) - { - if (work->children.count(std::get<0>(port)->name)) - { - HierDirtyFlags *child = work->children.at(std::get<0>(port)->name); - SigBit child_bit = sigmaps.at(child->module)(SigBit(child->module->wire(std::get<1>(port)), std::get<2>(port))); - log_assert(bit.wire && child_bit.wire); - - funct_declarations.push_back(util_set_bit(work->prefix + cid(child->hiername) + "." + cid(child_bit.wire->name), - child_bit.wire->width, child_bit.offset, util_get_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset))); - child->set_dirty(child_bit); - - if (verbose) - log(" Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", work->log_prefix.c_str(), log_id(bit.wire), bit.offset, - work->log_prefix.c_str(), log_id(std::get<0>(port)), log_id(child_bit.wire), child_bit.offset); - } else { - if (verbose) - log(" Marking cell %s.%s (via %s.%s[%d]).\n", work->log_prefix.c_str(), log_id(std::get<0>(port)), - work->log_prefix.c_str(), log_id(bit.wire), bit.offset); - work->set_dirty(std::get<0>(port)); - } - } - work->unset_dirty(bit); - } - } - - if (!work->dirty_cells.empty()) - { - Cell *cell = nullptr; - for (auto c : work->dirty_cells) - if (cell == nullptr || topoidx.at(cell) < topoidx.at(c)) - cell = c; - - string hiername = work->log_prefix + "." + log_id(cell); - - if (verbose) - log(" Evaluating %s (%s, best of %d).\n", hiername.c_str(), log_id(cell->type), GetSize(work->dirty_cells)); - - if (activated_cells.count(hiername)) - reactivated_cells.insert(hiername); - activated_cells.insert(hiername); - - eval_cell(work, cell); - work->unset_dirty(cell); - } - } - - for (auto &child : work->children) - eval_dirty(child.second); - } - } - - void eval_sticky_dirty(HierDirtyFlags *work) - { - Module *mod = work->module; - - for (Wire *w : mod->wires()) - for (SigBit bit : SigSpec(w)) - { - SigBit canonical_bit = sigmaps.at(mod)(bit); - - if (canonical_bit == bit) - continue; - - if (work->sticky_dirty_bits.count(canonical_bit) == 0) - continue; - - if (bit.wire == nullptr || canonical_bit.wire == nullptr) - continue; - - funct_declarations.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset, - util_get_bit(work->prefix + cid(canonical_bit.wire->name), canonical_bit.wire->width, canonical_bit.offset).c_str())); - - if (verbose) - log(" Propagating alias %s.%s[%d] -> %s.%s[%d].\n", - work->log_prefix.c_str(), log_id(canonical_bit.wire), canonical_bit.offset, - work->log_prefix.c_str(), log_id(bit.wire), bit.offset); - } - - work->sticky_dirty_bits.clear(); - - for (auto &child : work->children) - eval_sticky_dirty(child.second); - } - - void make_func(HierDirtyFlags *work, const string &func_name, const vector &preamble) - { - log("Generating function %s():\n", func_name.c_str()); - - activated_cells.clear(); - reactivated_cells.clear(); - - funct_declarations.push_back(""); - funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str())); - funct_declarations.push_back("{"); - for (auto &line : preamble) - funct_declarations.push_back(line); - eval_dirty(work); - eval_sticky_dirty(work); - funct_declarations.push_back("}"); - - log(" Activated %d cells (%d activated more than once).\n", GetSize(activated_cells), GetSize(reactivated_cells)); - } - - void eval_init(HierDirtyFlags *work, vector &preamble) - { - Module *module = work->module; - - for (Wire *w : module->wires()) - { - if (w->attributes.count("\\init")) - { - SigSpec sig = sigmaps.at(module)(w); - Const val = w->attributes.at("\\init"); - val.bits.resize(GetSize(sig), State::Sx); - - for (int i = 0; i < GetSize(sig); i++) - if (val[i] == State::S0 || val[i] == State::S1) { - SigBit bit = sig[i]; - preamble.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset, val == State::S1 ? "true" : "false")); - work->set_dirty(bit); - } - } - - for (SigBit bit : SigSpec(w)) - { - SigBit val = sigmaps.at(module)(bit); - - if (val == State::S0 || val == State::S1) - preamble.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset, val == State::S1 ? "true" : "false")); - - if (driven_bits.at(module).count(val) == 0) - work->set_dirty(val); - } - } - - work->set_dirty(State::S0); - work->set_dirty(State::S1); - - for (auto &child : work->children) - eval_init(child.second, preamble); - } - - void make_init_func(HierDirtyFlags *work) - { - vector preamble; - eval_init(work, preamble); - make_func(work, cid(work->module->name) + "_init", preamble); - } - - void make_eval_func(HierDirtyFlags *work) - { - Module *mod = work->module; - vector preamble; - - for (Wire *w : mod->wires()) { - if (w->port_input) - for (SigBit bit : sigmaps.at(mod)(w)) - work->set_dirty(bit); - } - - make_func(work, cid(work->module->name) + "_eval", preamble); - } - - void make_tick_func(HierDirtyFlags* /* work */) - { - // FIXME - } - - void run(Module *mod) - { - create_module_struct(mod); - - HierDirtyFlags work(mod, IdString(), nullptr, "state->", log_id(mod->name)); - - make_init_func(&work); - make_eval_func(&work); - make_tick_func(&work); - } - - void write(std::ostream &f) - { - f << "#include " << std::endl; - f << "#include " << std::endl; - - for (auto &line : signal_declarations) - f << line << std::endl; - - for (auto &line : util_declarations) - f << line << std::endl; - - for (auto &line : struct_declarations) - f << line << std::endl; - - for (auto &line : funct_declarations) - f << line << std::endl; - } -}; - -struct SimplecBackend : public Backend { - SimplecBackend() : Backend("simplec", "convert design to simple C code") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_simplec [options] [filename]\n"); - log("\n"); - log("Write simple C code for simulating the design. The C code written can be used to\n"); - log("simulate the design in a C environment, but the purpose of this command is to\n"); - log("generate code that works well with C-based formal verification.\n"); - log("\n"); - log(" -verbose\n"); - log(" this will print the recursive walk used to export the modules.\n"); - log("\n"); - log(" -i8, -i16, -i32, -i64\n"); - log(" set the maximum integer bit width to use in the generated code.\n"); - log("\n"); - log("THIS COMMAND IS UNDER CONSTRUCTION\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - reserved_cids.clear(); - id2cid.clear(); - - SimplecWorker worker(design); - - log_header(design, "Executing SIMPLEC backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-verbose") { - worker.verbose = true; - continue; - } - if (args[argidx] == "-i8") { - worker.max_uintsize = 8; - continue; - } - if (args[argidx] == "-i16") { - worker.max_uintsize = 16; - continue; - } - if (args[argidx] == "-i32") { - worker.max_uintsize = 32; - continue; - } - if (args[argidx] == "-i64") { - worker.max_uintsize = 64; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - Module *topmod = design->top_module(); - - if (topmod == nullptr) - log_error("Current design has no top module.\n"); - - worker.run(topmod); - worker.write(*f); - } -} SimplecBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/simplec/test00.sh b/yosys/backends/simplec/test00.sh deleted file mode 100644 index ede757273..000000000 --- a/yosys/backends/simplec/test00.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -ex -../../yosys -p 'synth -top test; write_simplec -verbose -i8 test00_uut.c' test00_uut.v -clang -o test00_tb test00_tb.c -./test00_tb diff --git a/yosys/backends/simplec/test00_tb.c b/yosys/backends/simplec/test00_tb.c deleted file mode 100644 index 7fac48265..000000000 --- a/yosys/backends/simplec/test00_tb.c +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include "test00_uut.c" - -uint32_t xorshift32() -{ - static uint32_t x32 = 314159265; - x32 ^= x32 << 13; - x32 ^= x32 >> 17; - x32 ^= x32 << 5; - return x32; -} - -int main() -{ - struct test_state_t state; - uint32_t a, b, c, x, y, z, w; - bool first_eval = true; - - for (int i = 0; i < 10; i++) - { - a = xorshift32(); - b = xorshift32(); - c = xorshift32(); - - x = (a & b) | c; - y = a & (b | c); - z = a ^ b ^ c; - w = z; - - state.a.value_7_0 = a; - state.a.value_15_8 = a >> 8; - state.a.value_23_16 = a >> 16; - state.a.value_31_24 = a >> 24; - - state.b.value_7_0 = b; - state.b.value_15_8 = b >> 8; - state.b.value_23_16 = b >> 16; - state.b.value_31_24 = b >> 24; - - state.c.value_7_0 = c; - state.c.value_15_8 = c >> 8; - state.c.value_23_16 = c >> 16; - state.c.value_31_24 = c >> 24; - - if (first_eval) { - first_eval = false; - test_init(&state); - } else { - test_eval(&state); - } - - uint32_t uut_x = 0; - uut_x |= (uint32_t)state.x.value_7_0; - uut_x |= (uint32_t)state.x.value_15_8 << 8; - uut_x |= (uint32_t)state.x.value_23_16 << 16; - uut_x |= (uint32_t)state.x.value_31_24 << 24; - - uint32_t uut_y = 0; - uut_y |= (uint32_t)state.y.value_7_0; - uut_y |= (uint32_t)state.y.value_15_8 << 8; - uut_y |= (uint32_t)state.y.value_23_16 << 16; - uut_y |= (uint32_t)state.y.value_31_24 << 24; - - uint32_t uut_z = 0; - uut_z |= (uint32_t)state.z.value_7_0; - uut_z |= (uint32_t)state.z.value_15_8 << 8; - uut_z |= (uint32_t)state.z.value_23_16 << 16; - uut_z |= (uint32_t)state.z.value_31_24 << 24; - - uint32_t uut_w = 0; - uut_w |= (uint32_t)state.w.value_7_0; - uut_w |= (uint32_t)state.w.value_15_8 << 8; - uut_w |= (uint32_t)state.w.value_23_16 << 16; - uut_w |= (uint32_t)state.w.value_31_24 << 24; - - printf("---\n"); - printf("A: 0x%08x\n", a); - printf("B: 0x%08x\n", b); - printf("C: 0x%08x\n", c); - printf("X: 0x%08x 0x%08x\n", x, uut_x); - printf("Y: 0x%08x 0x%08x\n", y, uut_y); - printf("Z: 0x%08x 0x%08x\n", z, uut_z); - printf("W: 0x%08x 0x%08x\n", w, uut_w); - - assert(x == uut_x); - assert(y == uut_y); - assert(z == uut_z); - assert(w == uut_w); - } - - return 0; -} diff --git a/yosys/backends/simplec/test00_uut.v b/yosys/backends/simplec/test00_uut.v deleted file mode 100644 index 92329a6f9..000000000 --- a/yosys/backends/simplec/test00_uut.v +++ /dev/null @@ -1,14 +0,0 @@ -module test(input [31:0] a, b, c, output [31:0] x, y, z, w); - unit_x unit_x_inst (.a(a), .b(b), .c(c), .x(x)); - unit_y unit_y_inst (.a(a), .b(b), .c(c), .y(y)); - assign z = a ^ b ^ c, w = z; -endmodule - -module unit_x(input [31:0] a, b, c, output [31:0] x); - assign x = (a & b) | c; -endmodule - -module unit_y(input [31:0] a, b, c, output [31:0] y); - assign y = a & (b | c); -endmodule - diff --git a/yosys/backends/smt2/.gitignore b/yosys/backends/smt2/.gitignore deleted file mode 100644 index 313ea0a1a..000000000 --- a/yosys/backends/smt2/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test_cells diff --git a/yosys/backends/smt2/Makefile.inc b/yosys/backends/smt2/Makefile.inc deleted file mode 100644 index 92941d4cf..000000000 --- a/yosys/backends/smt2/Makefile.inc +++ /dev/null @@ -1,32 +0,0 @@ - -OBJS += backends/smt2/smt2.o - -ifneq ($(CONFIG),mxe) -ifneq ($(CONFIG),emcc) - -# MSYS targets support yosys-smtbmc, but require a launcher script -ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64)) -TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py -# Needed to find the Python interpreter for yosys-smtbmc scripts. -# Override if necessary, it is only used for msys2 targets. -PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3) - -yosys-smtbmc-script.py: backends/smt2/smtbmc.py - $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \ - -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ - -yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py - $(P) gcc -DGUI=0 -O -s -o $@ $< -# Other targets -else -TARGETS += yosys-smtbmc - -yosys-smtbmc: backends/smt2/smtbmc.py - $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new - $(Q) chmod +x $@.new - $(Q) mv $@.new $@ -endif - -$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py)) -endif -endif diff --git a/yosys/backends/smt2/example.v b/yosys/backends/smt2/example.v deleted file mode 100644 index b195266eb..000000000 --- a/yosys/backends/smt2/example.v +++ /dev/null @@ -1,11 +0,0 @@ -module main(input clk); - reg [3:0] counter = 0; - always @(posedge clk) begin - if (counter == 10) - counter <= 0; - else - counter <= counter + 1; - end - assert property (counter != 15); - // assert property (counter <= 10); -endmodule diff --git a/yosys/backends/smt2/example.ys b/yosys/backends/smt2/example.ys deleted file mode 100644 index 6fccb344f..000000000 --- a/yosys/backends/smt2/example.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog -formal example.v -hierarchy; proc; opt; memory -nordff -nomap; opt -fast -write_smt2 -bv -mem -wires example.smt2 diff --git a/yosys/backends/smt2/smt2.cc b/yosys/backends/smt2/smt2.cc deleted file mode 100644 index e318a4051..000000000 --- a/yosys/backends/smt2/smt2.cc +++ /dev/null @@ -1,1572 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct Smt2Worker -{ - CellTypes ct; - SigMap sigmap; - RTLIL::Module *module; - bool bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode; - dict &mod_stbv_width; - int idcounter = 0, statebv_width = 0; - - std::vector decls, trans, hier, dtmembers; - std::map bit_driver; - std::set exported_cells, hiercells, hiercells_queue; - pool recursive_cells, registers; - - pool clock_posedge, clock_negedge; - vector ex_state_eq, ex_input_eq; - - std::map> fcache; - std::map memarrays; - std::map bvsizes; - dict ids; - - const char *get_id(IdString n) - { - if (ids.count(n) == 0) { - std::string str = log_id(n); - for (int i = 0; i < GetSize(str); i++) { - if (str[i] == '\\') - str[i] = '/'; - } - ids[n] = strdup(str.c_str()); - } - return ids[n]; - } - - template - const char *get_id(T *obj) { - return get_id(obj->name); - } - - void makebits(std::string name, int width = 0, std::string comment = std::string()) - { - std::string decl_str; - - if (statebv) - { - if (width == 0) { - decl_str = stringf("(define-fun |%s| ((state |%s_s|)) Bool (= ((_ extract %d %d) state) #b1))", name.c_str(), get_id(module), statebv_width, statebv_width); - statebv_width += 1; - } else { - decl_str = stringf("(define-fun |%s| ((state |%s_s|)) (_ BitVec %d) ((_ extract %d %d) state))", name.c_str(), get_id(module), width, statebv_width+width-1, statebv_width); - statebv_width += width; - } - } - else if (statedt) - { - if (width == 0) { - decl_str = stringf(" (|%s| Bool)", name.c_str()); - } else { - decl_str = stringf(" (|%s| (_ BitVec %d))", name.c_str(), width); - } - } - else - { - if (width == 0) { - decl_str = stringf("(declare-fun |%s| (|%s_s|) Bool)", name.c_str(), get_id(module)); - } else { - decl_str = stringf("(declare-fun |%s| (|%s_s|) (_ BitVec %d))", name.c_str(), get_id(module), width); - } - } - - if (!comment.empty()) - decl_str += " ; " + comment; - - if (statedt) - dtmembers.push_back(decl_str + "\n"); - else - decls.push_back(decl_str + "\n"); - } - - Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool wiresmode, bool verbose, bool statebv, bool statedt, bool forallmode, - dict &mod_stbv_width, dict>> &mod_clk_cache) : - ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode), wiresmode(wiresmode), - verbose(verbose), statebv(statebv), statedt(statedt), forallmode(forallmode), mod_stbv_width(mod_stbv_width) - { - pool noclock; - - makebits(stringf("%s_is", get_id(module))); - - for (auto cell : module->cells()) - for (auto &conn : cell->connections()) - { - if (GetSize(conn.second) == 0) - continue; - - bool is_input = ct.cell_input(cell->type, conn.first); - bool is_output = ct.cell_output(cell->type, conn.first); - - if (is_output && !is_input) - for (auto bit : sigmap(conn.second)) { - if (bit_driver.count(bit)) - log_error("Found multiple drivers for %s.\n", log_signal(bit)); - bit_driver[bit] = cell; - } - else if (is_output || !is_input) - log_error("Unsupported or unknown directionality on port %s of cell %s.%s (%s).\n", - log_id(conn.first), log_id(module), log_id(cell), log_id(cell->type)); - - if (cell->type.in("$mem") && conn.first.in("\\RD_CLK", "\\WR_CLK")) - { - SigSpec clk = sigmap(conn.second); - for (int i = 0; i < GetSize(clk); i++) - { - if (clk[i].wire == nullptr) - continue; - - if (cell->getParam(conn.first == "\\RD_CLK" ? "\\RD_CLK_ENABLE" : "\\WR_CLK_ENABLE")[i] != State::S1) - continue; - - if (cell->getParam(conn.first == "\\RD_CLK" ? "\\RD_CLK_POLARITY" : "\\WR_CLK_POLARITY")[i] == State::S1) - clock_posedge.insert(clk[i]); - else - clock_negedge.insert(clk[i]); - } - } - else - if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_") && conn.first.in("\\CLK", "\\C")) - { - bool posedge = (cell->type == "$_DFF_N_") || (cell->type == "$dff" && cell->getParam("\\CLK_POLARITY").as_bool()); - for (auto bit : sigmap(conn.second)) { - if (posedge) - clock_posedge.insert(bit); - else - clock_negedge.insert(bit); - } - } - else - if (mod_clk_cache.count(cell->type) && mod_clk_cache.at(cell->type).count(conn.first)) - { - for (auto bit : sigmap(conn.second)) { - if (mod_clk_cache.at(cell->type).at(conn.first).first) - clock_posedge.insert(bit); - if (mod_clk_cache.at(cell->type).at(conn.first).second) - clock_negedge.insert(bit); - } - } - else - { - for (auto bit : sigmap(conn.second)) - noclock.insert(bit); - } - } - - for (auto bit : noclock) { - clock_posedge.erase(bit); - clock_negedge.erase(bit); - } - - for (auto wire : module->wires()) - { - if (!wire->port_input || GetSize(wire) != 1) - continue; - SigBit bit = sigmap(wire); - if (clock_posedge.count(bit)) - mod_clk_cache[module->name][wire->name].first = true; - if (clock_negedge.count(bit)) - mod_clk_cache[module->name][wire->name].second = true; - } - } - - ~Smt2Worker() - { - for (auto &it : ids) - free(it.second); - ids.clear(); - } - - const char *get_id(Module *m) - { - return get_id(m->name); - } - - const char *get_id(Cell *c) - { - return get_id(c->name); - } - - const char *get_id(Wire *w) - { - return get_id(w->name); - } - - void register_bool(RTLIL::SigBit bit, int id) - { - if (verbose) log("%*s-> register_bool: %s %d\n", 2+2*GetSize(recursive_cells), "", - log_signal(bit), id); - - sigmap.apply(bit); - log_assert(fcache.count(bit) == 0); - fcache[bit] = std::pair(id, -1); - } - - void register_bv(RTLIL::SigSpec sig, int id) - { - if (verbose) log("%*s-> register_bv: %s %d\n", 2+2*GetSize(recursive_cells), "", - log_signal(sig), id); - - log_assert(bvmode); - sigmap.apply(sig); - - log_assert(bvsizes.count(id) == 0); - bvsizes[id] = GetSize(sig); - - for (int i = 0; i < GetSize(sig); i++) { - log_assert(fcache.count(sig[i]) == 0); - fcache[sig[i]] = std::pair(id, i); - } - } - - void register_boolvec(RTLIL::SigSpec sig, int id) - { - if (verbose) log("%*s-> register_boolvec: %s %d\n", 2+2*GetSize(recursive_cells), "", - log_signal(sig), id); - - log_assert(bvmode); - sigmap.apply(sig); - register_bool(sig[0], id); - - for (int i = 1; i < GetSize(sig); i++) - sigmap.add(sig[i], RTLIL::State::S0); - } - - std::string get_bool(RTLIL::SigBit bit, const char *state_name = "state") - { - sigmap.apply(bit); - - if (bit.wire == nullptr) - return bit == RTLIL::State::S1 ? "true" : "false"; - - if (bit_driver.count(bit)) - export_cell(bit_driver.at(bit)); - sigmap.apply(bit); - - if (fcache.count(bit) == 0) { - if (verbose) log("%*s-> external bool: %s\n", 2+2*GetSize(recursive_cells), "", - log_signal(bit)); - makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(bit)); - register_bool(bit, idcounter++); - } - - auto f = fcache.at(bit); - if (f.second >= 0) - return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, get_id(module), f.first, state_name); - return stringf("(|%s#%d| %s)", get_id(module), f.first, state_name); - } - - std::string get_bool(RTLIL::SigSpec sig, const char *state_name = "state") - { - return get_bool(sig.as_bit(), state_name); - } - - std::string get_bv(RTLIL::SigSpec sig, const char *state_name = "state") - { - log_assert(bvmode); - sigmap.apply(sig); - - std::vector subexpr; - - SigSpec orig_sig; - while (orig_sig != sig) { - for (auto bit : sig) - if (bit_driver.count(bit)) - export_cell(bit_driver.at(bit)); - orig_sig = sig; - sigmap.apply(sig); - } - - for (int i = 0, j = 1; i < GetSize(sig); i += j, j = 1) - { - if (sig[i].wire == nullptr) { - while (i+j < GetSize(sig) && sig[i+j].wire == nullptr) j++; - subexpr.push_back("#b"); - for (int k = i+j-1; k >= i; k--) - subexpr.back() += sig[k] == RTLIL::State::S1 ? "1" : "0"; - continue; - } - - if (fcache.count(sig[i]) && fcache.at(sig[i]).second == -1) { - subexpr.push_back(stringf("(ite %s #b1 #b0)", get_bool(sig[i], state_name).c_str())); - continue; - } - - if (fcache.count(sig[i])) { - auto t1 = fcache.at(sig[i]); - while (i+j < GetSize(sig)) { - if (fcache.count(sig[i+j]) == 0) - break; - auto t2 = fcache.at(sig[i+j]); - if (t1.first != t2.first) - break; - if (t1.second+j != t2.second) - break; - j++; - } - if (t1.second == 0 && j == bvsizes.at(t1.first)) - subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), t1.first, state_name)); - else - subexpr.push_back(stringf("((_ extract %d %d) (|%s#%d| %s))", - t1.second + j - 1, t1.second, get_id(module), t1.first, state_name)); - continue; - } - - std::set seen_bits = { sig[i] }; - while (i+j < GetSize(sig) && sig[i+j].wire && !fcache.count(sig[i+j]) && !seen_bits.count(sig[i+j])) - seen_bits.insert(sig[i+j]), j++; - - if (verbose) log("%*s-> external bv: %s\n", 2+2*GetSize(recursive_cells), "", - log_signal(sig.extract(i, j))); - for (auto bit : sig.extract(i, j)) - log_assert(bit_driver.count(bit) == 0); - makebits(stringf("%s#%d", get_id(module), idcounter), j, log_signal(sig.extract(i, j))); - subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), idcounter, state_name)); - register_bv(sig.extract(i, j), idcounter++); - } - - if (GetSize(subexpr) > 1) { - std::string expr = "", end_str = ""; - for (int i = GetSize(subexpr)-1; i >= 0; i--) { - if (i > 0) expr += " (concat", end_str += ")"; - expr += " " + subexpr[i]; - } - return expr.substr(1) + end_str; - } else { - log_assert(GetSize(subexpr) == 1); - return subexpr[0]; - } - } - - void export_gate(RTLIL::Cell *cell, std::string expr) - { - RTLIL::SigBit bit = sigmap(cell->getPort("\\Y").as_bit()); - std::string processed_expr; - - for (char ch : expr) { - if (ch == 'A') processed_expr += get_bool(cell->getPort("\\A")); - else if (ch == 'B') processed_expr += get_bool(cell->getPort("\\B")); - else if (ch == 'C') processed_expr += get_bool(cell->getPort("\\C")); - else if (ch == 'D') processed_expr += get_bool(cell->getPort("\\D")); - else if (ch == 'S') processed_expr += get_bool(cell->getPort("\\S")); - else processed_expr += ch; - } - - if (verbose) - log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); - - decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", - get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(bit))); - register_bool(bit, idcounter++); - recursive_cells.erase(cell); - } - - void export_bvop(RTLIL::Cell *cell, std::string expr, char type = 0) - { - RTLIL::SigSpec sig_a, sig_b; - RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); - int width = GetSize(sig_y); - - if (type == 's' || type == 'd' || type == 'b') { - width = max(width, GetSize(cell->getPort("\\A"))); - if (cell->hasPort("\\B")) - width = max(width, GetSize(cell->getPort("\\B"))); - } - - if (cell->hasPort("\\A")) { - sig_a = cell->getPort("\\A"); - sig_a.extend_u0(width, is_signed); - } - - if (cell->hasPort("\\B")) { - sig_b = cell->getPort("\\B"); - sig_b.extend_u0(width, is_signed && !(type == 's')); - } - - std::string processed_expr; - - for (char ch : expr) { - if (ch == 'A') processed_expr += get_bv(sig_a); - else if (ch == 'B') processed_expr += get_bv(sig_b); - else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B")); - else if (ch == 'L') processed_expr += is_signed ? "a" : "l"; - else if (ch == 'U') processed_expr += is_signed ? "s" : "u"; - else processed_expr += ch; - } - - if (width != GetSize(sig_y) && type != 'b') - processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr.c_str()); - - if (verbose) - log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); - - if (type == 'b') { - decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", - get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y))); - register_boolvec(sig_y, idcounter++); - } else { - decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), idcounter, get_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y))); - register_bv(sig_y, idcounter++); - } - - recursive_cells.erase(cell); - } - - void export_reduce(RTLIL::Cell *cell, std::string expr, bool identity_val) - { - RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); - std::string processed_expr; - - for (char ch : expr) - if (ch == 'A' || ch == 'B') { - RTLIL::SigSpec sig = sigmap(cell->getPort(stringf("\\%c", ch))); - for (auto bit : sig) - processed_expr += " " + get_bool(bit); - if (GetSize(sig) == 1) - processed_expr += identity_val ? " true" : " false"; - } else - processed_expr += ch; - - if (verbose) - log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); - - decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", - get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y))); - register_boolvec(sig_y, idcounter++); - recursive_cells.erase(cell); - } - - void export_cell(RTLIL::Cell *cell) - { - if (verbose) - log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "", - log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new"); - - if (recursive_cells.count(cell)) - log_error("Found logic loop in module %s! See cell %s.\n", get_id(module), get_id(cell)); - - if (exported_cells.count(cell)) - return; - - exported_cells.insert(cell); - recursive_cells.insert(cell); - - if (cell->type == "$initstate") - { - SigBit bit = sigmap(cell->getPort("\\Y").as_bit()); - decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (|%s_is| state)) ; %s\n", - get_id(module), idcounter, get_id(module), get_id(module), log_signal(bit))); - register_bool(bit, idcounter++); - recursive_cells.erase(cell); - return; - } - - if (cell->type.in("$_FF_", "$_DFF_P_", "$_DFF_N_")) - { - registers.insert(cell); - makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(cell->getPort("\\Q"))); - register_bool(cell->getPort("\\Q"), idcounter++); - recursive_cells.erase(cell); - return; - } - - if (cell->type == "$_BUF_") return export_gate(cell, "A"); - if (cell->type == "$_NOT_") return export_gate(cell, "(not A)"); - if (cell->type == "$_AND_") return export_gate(cell, "(and A B)"); - if (cell->type == "$_NAND_") return export_gate(cell, "(not (and A B))"); - if (cell->type == "$_OR_") return export_gate(cell, "(or A B)"); - if (cell->type == "$_NOR_") return export_gate(cell, "(not (or A B))"); - if (cell->type == "$_XOR_") return export_gate(cell, "(xor A B)"); - if (cell->type == "$_XNOR_") return export_gate(cell, "(not (xor A B))"); - if (cell->type == "$_ANDNOT_") return export_gate(cell, "(and A (not B))"); - if (cell->type == "$_ORNOT_") return export_gate(cell, "(or A (not B))"); - if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)"); - if (cell->type == "$_AOI3_") return export_gate(cell, "(not (or (and A B) C))"); - if (cell->type == "$_OAI3_") return export_gate(cell, "(not (and (or A B) C))"); - if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))"); - if (cell->type == "$_OAI4_") return export_gate(cell, "(not (and (or A B) (or C D)))"); - - // FIXME: $lut - - if (bvmode) - { - if (cell->type.in("$ff", "$dff")) - { - registers.insert(cell); - makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))); - register_bv(cell->getPort("\\Q"), idcounter++); - recursive_cells.erase(cell); - return; - } - - if (cell->type.in("$anyconst", "$anyseq", "$allconst", "$allseq")) - { - registers.insert(cell); - string infostr = cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell); - if (cell->attributes.count("\\reg")) - infostr += " " + cell->attributes.at("\\reg").decode_string(); - decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort("\\Y")), infostr.c_str())); - makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort("\\Y")), log_signal(cell->getPort("\\Y"))); - if (cell->type == "$anyseq") - ex_input_eq.push_back(stringf(" (= (|%s#%d| state) (|%s#%d| other_state))", get_id(module), idcounter, get_id(module), idcounter)); - register_bv(cell->getPort("\\Y"), idcounter++); - recursive_cells.erase(cell); - return; - } - - if (cell->type == "$and") return export_bvop(cell, "(bvand A B)"); - if (cell->type == "$or") return export_bvop(cell, "(bvor A B)"); - if (cell->type == "$xor") return export_bvop(cell, "(bvxor A B)"); - if (cell->type == "$xnor") return export_bvop(cell, "(bvxnor A B)"); - - if (cell->type == "$shl") return export_bvop(cell, "(bvshl A B)", 's'); - if (cell->type == "$shr") return export_bvop(cell, "(bvlshr A B)", 's'); - if (cell->type == "$sshl") return export_bvop(cell, "(bvshl A B)", 's'); - if (cell->type == "$sshr") return export_bvop(cell, "(bvLshr A B)", 's'); - - if (cell->type.in("$shift", "$shiftx")) { - if (cell->getParam("\\B_SIGNED").as_bool()) { - return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) " - "(bvlshr A B) (bvlshr A (bvneg B)))", - GetSize(cell->getPort("\\B")), 0), 's'); - } else { - return export_bvop(cell, "(bvlshr A B)", 's'); - } - } - - if (cell->type == "$lt") return export_bvop(cell, "(bvUlt A B)", 'b'); - if (cell->type == "$le") return export_bvop(cell, "(bvUle A B)", 'b'); - if (cell->type == "$ge") return export_bvop(cell, "(bvUge A B)", 'b'); - if (cell->type == "$gt") return export_bvop(cell, "(bvUgt A B)", 'b'); - - if (cell->type == "$ne") return export_bvop(cell, "(distinct A B)", 'b'); - if (cell->type == "$nex") return export_bvop(cell, "(distinct A B)", 'b'); - if (cell->type == "$eq") return export_bvop(cell, "(= A B)", 'b'); - if (cell->type == "$eqx") return export_bvop(cell, "(= A B)", 'b'); - - if (cell->type == "$not") return export_bvop(cell, "(bvnot A)"); - if (cell->type == "$pos") return export_bvop(cell, "A"); - if (cell->type == "$neg") return export_bvop(cell, "(bvneg A)"); - - if (cell->type == "$add") return export_bvop(cell, "(bvadd A B)"); - if (cell->type == "$sub") return export_bvop(cell, "(bvsub A B)"); - if (cell->type == "$mul") return export_bvop(cell, "(bvmul A B)"); - if (cell->type == "$div") return export_bvop(cell, "(bvUdiv A B)", 'd'); - if (cell->type == "$mod") return export_bvop(cell, "(bvUrem A B)", 'd'); - - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool") && - 2*GetSize(cell->getPort("\\A").chunks()) < GetSize(cell->getPort("\\A"))) { - bool is_and = cell->type == "$reduce_and"; - string bits(GetSize(cell->getPort("\\A")), is_and ? '1' : '0'); - return export_bvop(cell, stringf("(%s A #b%s)", is_and ? "=" : "distinct", bits.c_str()), 'b'); - } - - if (cell->type == "$reduce_and") return export_reduce(cell, "(and A)", true); - if (cell->type == "$reduce_or") return export_reduce(cell, "(or A)", false); - if (cell->type == "$reduce_xor") return export_reduce(cell, "(xor A)", false); - if (cell->type == "$reduce_xnor") return export_reduce(cell, "(not (xor A))", false); - if (cell->type == "$reduce_bool") return export_reduce(cell, "(or A)", false); - - if (cell->type == "$logic_not") return export_reduce(cell, "(not (or A))", false); - if (cell->type == "$logic_and") return export_reduce(cell, "(and (or A) (or B))", false); - if (cell->type == "$logic_or") return export_reduce(cell, "(or A B)", false); - - if (cell->type == "$mux" || cell->type == "$pmux") - { - int width = GetSize(cell->getPort("\\Y")); - std::string processed_expr = get_bv(cell->getPort("\\A")); - - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_s = cell->getPort("\\S"); - get_bv(sig_b); - get_bv(sig_s); - - for (int i = 0; i < GetSize(sig_s); i++) - processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(), - get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str()); - - if (verbose) - log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); - - RTLIL::SigSpec sig = sigmap(cell->getPort("\\Y")); - decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), idcounter, get_id(module), width, processed_expr.c_str(), log_signal(sig))); - register_bv(sig, idcounter++); - recursive_cells.erase(cell); - return; - } - - // FIXME: $slice $concat - } - - if (memmode && cell->type == "$mem") - { - int arrayid = idcounter++; - memarrays[cell] = arrayid; - - int abits = cell->getParam("\\ABITS").as_int(); - int width = cell->getParam("\\WIDTH").as_int(); - int rd_ports = cell->getParam("\\RD_PORTS").as_int(); - int wr_ports = cell->getParam("\\WR_PORTS").as_int(); - - bool async_read = false; - if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_ones()) { - if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_zero()) - log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", log_id(cell), log_id(module)); - async_read = true; - } - - decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", get_id(cell), abits, width, rd_ports, wr_ports, async_read ? "async" : "sync")); - - string memstate; - if (async_read) { - memstate = stringf("%s#%d#final", get_id(module), arrayid); - } else { - memstate = stringf("%s#%d#0", get_id(module), arrayid); - } - - if (statebv) - { - int mem_size = cell->getParam("\\SIZE").as_int(); - int mem_offset = cell->getParam("\\OFFSET").as_int(); - - makebits(memstate, width*mem_size, get_id(cell)); - decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (_ BitVec %d) (|%s| state))\n", - get_id(module), get_id(cell), get_id(module), width*mem_size, memstate.c_str())); - - for (int i = 0; i < rd_ports; i++) - { - SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(abits*i, abits); - SigSpec data_sig = cell->getPort("\\RD_DATA").extract(width*i, width); - std::string addr = get_bv(addr_sig); - - if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool()) - log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! " - "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(data_sig), log_id(cell), log_id(module)); - - decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig))); - - std::string read_expr = "#b"; - for (int k = 0; k < width; k++) - read_expr += "0"; - - for (int k = 0; k < mem_size; k++) - read_expr = stringf("(ite (= (|%s_m:R%dA %s| state) #b%s) ((_ extract %d %d) (|%s| state))\n %s)", - get_id(module), i, get_id(cell), Const(k+mem_offset, abits).as_string().c_str(), - width*(k+1)-1, width*k, memstate.c_str(), read_expr.c_str()); - - decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d)\n %s) ; %s\n", - get_id(module), idcounter, get_id(module), width, read_expr.c_str(), log_signal(data_sig))); - - decls.push_back(stringf("(define-fun |%s_m:R%dD %s| ((state |%s_s|)) (_ BitVec %d) (|%s#%d| state))\n", - get_id(module), i, get_id(cell), get_id(module), width, get_id(module), idcounter)); - - register_bv(data_sig, idcounter++); - } - } - else - { - if (statedt) - dtmembers.push_back(stringf(" (|%s| (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n", - memstate.c_str(), abits, width, get_id(cell))); - else - decls.push_back(stringf("(declare-fun |%s| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n", - memstate.c_str(), get_id(module), abits, width, get_id(cell))); - - decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) (|%s| state))\n", - get_id(module), get_id(cell), get_id(module), abits, width, memstate.c_str())); - - for (int i = 0; i < rd_ports; i++) - { - SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(abits*i, abits); - SigSpec data_sig = cell->getPort("\\RD_DATA").extract(width*i, width); - std::string addr = get_bv(addr_sig); - - if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool()) - log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! " - "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(data_sig), log_id(cell), log_id(module)); - - decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig))); - - decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) (select (|%s| state) (|%s_m:R%dA %s| state))) ; %s\n", - get_id(module), idcounter, get_id(module), width, memstate.c_str(), get_id(module), i, get_id(cell), log_signal(data_sig))); - - decls.push_back(stringf("(define-fun |%s_m:R%dD %s| ((state |%s_s|)) (_ BitVec %d) (|%s#%d| state))\n", - get_id(module), i, get_id(cell), get_id(module), width, get_id(module), idcounter)); - - register_bv(data_sig, idcounter++); - } - } - - registers.insert(cell); - recursive_cells.erase(cell); - return; - } - - Module *m = module->design->module(cell->type); - - if (m != nullptr) - { - decls.push_back(stringf("; yosys-smt2-cell %s %s\n", get_id(cell->type), get_id(cell->name))); - string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name)); - - for (auto &conn : cell->connections()) - { - if (GetSize(conn.second) == 0) - continue; - - Wire *w = m->wire(conn.first); - SigSpec sig = sigmap(conn.second); - - if (w->port_output && !w->port_input) { - if (GetSize(w) > 1) { - if (bvmode) { - makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(w), log_signal(sig)); - register_bv(sig, idcounter++); - } else { - for (int i = 0; i < GetSize(w); i++) { - makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(sig[i])); - register_bool(sig[i], idcounter++); - } - } - } else { - makebits(stringf("%s#%d", get_id(module), idcounter), 0, log_signal(sig)); - register_bool(sig, idcounter++); - } - } - } - - if (statebv) - makebits(stringf("%s_h %s", get_id(module), get_id(cell->name)), mod_stbv_width.at(cell->type)); - else if (statedt) - dtmembers.push_back(stringf(" (|%s_h %s| |%s_s|)\n", - get_id(module), get_id(cell->name), get_id(cell->type))); - else - decls.push_back(stringf("(declare-fun |%s_h %s| (|%s_s|) |%s_s|)\n", - get_id(module), get_id(cell->name), get_id(module), get_id(cell->type))); - - hiercells.insert(cell); - hiercells_queue.insert(cell); - recursive_cells.erase(cell); - return; - } - - log_error("Unsupported cell type %s for cell %s.%s.\n", - log_id(cell->type), log_id(module), log_id(cell)); - } - - void run() - { - if (verbose) log("=> export logic driving outputs\n"); - - pool reg_bits; - for (auto cell : module->cells()) - if (cell->type.in("$ff", "$dff", "$_FF_", "$_DFF_P_", "$_DFF_N_")) { - // not using sigmap -- we want the net directly at the dff output - for (auto bit : cell->getPort("\\Q")) - reg_bits.insert(bit); - } - - for (auto wire : module->wires()) { - bool is_register = false; - for (auto bit : SigSpec(wire)) - if (reg_bits.count(bit)) - is_register = true; - if (wire->port_id || is_register || wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\')) { - RTLIL::SigSpec sig = sigmap(wire); - if (wire->port_input) - decls.push_back(stringf("; yosys-smt2-input %s %d\n", get_id(wire), wire->width)); - if (wire->port_output) - decls.push_back(stringf("; yosys-smt2-output %s %d\n", get_id(wire), wire->width)); - if (is_register) - decls.push_back(stringf("; yosys-smt2-register %s %d\n", get_id(wire), wire->width)); - if (wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\')) - decls.push_back(stringf("; yosys-smt2-wire %s %d\n", get_id(wire), wire->width)); - if (GetSize(wire) == 1 && (clock_posedge.count(sig) || clock_negedge.count(sig))) - decls.push_back(stringf("; yosys-smt2-clock %s%s%s\n", get_id(wire), - clock_posedge.count(sig) ? " posedge" : "", clock_negedge.count(sig) ? " negedge" : "")); - if (bvmode && GetSize(sig) > 1) { - decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) (_ BitVec %d) %s)\n", - get_id(module), get_id(wire), get_id(module), GetSize(sig), get_bv(sig).c_str())); - if (wire->port_input) - ex_input_eq.push_back(stringf(" (= (|%s_n %s| state) (|%s_n %s| other_state))", - get_id(module), get_id(wire), get_id(module), get_id(wire))); - } else { - for (int i = 0; i < GetSize(sig); i++) - if (GetSize(sig) > 1) { - decls.push_back(stringf("(define-fun |%s_n %s %d| ((state |%s_s|)) Bool %s)\n", - get_id(module), get_id(wire), i, get_id(module), get_bool(sig[i]).c_str())); - if (wire->port_input) - ex_input_eq.push_back(stringf(" (= (|%s_n %s %d| state) (|%s_n %s %d| other_state))", - get_id(module), get_id(wire), i, get_id(module), get_id(wire), i)); - } else { - decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) Bool %s)\n", - get_id(module), get_id(wire), get_id(module), get_bool(sig[i]).c_str())); - if (wire->port_input) - ex_input_eq.push_back(stringf(" (= (|%s_n %s| state) (|%s_n %s| other_state))", - get_id(module), get_id(wire), get_id(module), get_id(wire))); - } - } - } - } - - if (verbose) log("=> export logic associated with the initial state\n"); - - vector init_list; - for (auto wire : module->wires()) - if (wire->attributes.count("\\init")) { - RTLIL::SigSpec sig = sigmap(wire); - Const val = wire->attributes.at("\\init"); - val.bits.resize(GetSize(sig), State::Sx); - if (bvmode && GetSize(sig) > 1) { - Const mask(State::S1, GetSize(sig)); - bool use_mask = false; - for (int i = 0; i < GetSize(sig); i++) - if (val[i] != State::S0 && val[i] != State::S1) { - val[i] = State::S0; - mask[i] = State::S0; - use_mask = true; - } - if (use_mask) - init_list.push_back(stringf("(= (bvand %s #b%s) #b%s) ; %s", get_bv(sig).c_str(), mask.as_string().c_str(), val.as_string().c_str(), get_id(wire))); - else - init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), get_id(wire))); - } else { - for (int i = 0; i < GetSize(sig); i++) - if (val[i] == State::S0 || val[i] == State::S1) - init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val[i] == State::S1 ? "true" : "false", get_id(wire))); - } - } - - if (verbose) log("=> export logic driving asserts\n"); - - int assert_id = 0, assume_id = 0, cover_id = 0; - vector assert_list, assume_list, cover_list; - - for (auto cell : module->cells()) - { - if (cell->type.in("$assert", "$assume", "$cover")) - { - int &id = cell->type == "$assert" ? assert_id : - cell->type == "$assume" ? assume_id : - cell->type == "$cover" ? cover_id : *(int*)nullptr; - - char postfix = cell->type == "$assert" ? 'a' : - cell->type == "$assume" ? 'u' : - cell->type == "$cover" ? 'c' : 0; - - string name_a = get_bool(cell->getPort("\\A")); - string name_en = get_bool(cell->getPort("\\EN")); - string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell); - decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str())); - - if (cell->type == "$cover") - decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n", - get_id(module), postfix, id, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell))); - else - decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n", - get_id(module), postfix, id, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell))); - - if (cell->type == "$assert") - assert_list.push_back(stringf("(|%s_a %d| state)", get_id(module), id)); - else if (cell->type == "$assume") - assume_list.push_back(stringf("(|%s_u %d| state)", get_id(module), id)); - - id++; - } - } - - if (verbose) log("=> export logic driving hierarchical cells\n"); - - for (auto cell : module->cells()) - if (module->design->module(cell->type) != nullptr) - export_cell(cell); - - while (!hiercells_queue.empty()) - { - std::set queue; - queue.swap(hiercells_queue); - - for (auto cell : queue) - { - string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name)); - Module *m = module->design->module(cell->type); - log_assert(m != nullptr); - - hier.push_back(stringf(" (= (|%s_is| state) (|%s_is| %s))\n", - get_id(module), get_id(cell->type), cell_state.c_str())); - - for (auto &conn : cell->connections()) - { - if (GetSize(conn.second) == 0) - continue; - - Wire *w = m->wire(conn.first); - SigSpec sig = sigmap(conn.second); - - if (bvmode || GetSize(w) == 1) { - hier.push_back(stringf(" (= %s (|%s_n %s| %s)) ; %s.%s\n", (GetSize(w) > 1 ? get_bv(sig) : get_bool(sig)).c_str(), - get_id(cell->type), get_id(w), cell_state.c_str(), get_id(cell->type), get_id(w))); - } else { - for (int i = 0; i < GetSize(w); i++) - hier.push_back(stringf(" (= %s (|%s_n %s %d| %s)) ; %s.%s[%d]\n", get_bool(sig[i]).c_str(), - get_id(cell->type), get_id(w), i, cell_state.c_str(), get_id(cell->type), get_id(w), i)); - } - } - } - } - - for (int iter = 1; !registers.empty(); iter++) - { - pool this_regs; - this_regs.swap(registers); - - if (verbose) log("=> export logic driving registers [iteration %d]\n", iter); - - for (auto cell : this_regs) - { - if (cell->type.in("$_FF_", "$_DFF_P_", "$_DFF_N_")) - { - std::string expr_d = get_bool(cell->getPort("\\D")); - std::string expr_q = get_bool(cell->getPort("\\Q"), "next_state"); - trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Q")))); - ex_state_eq.push_back(stringf("(= %s %s)", get_bool(cell->getPort("\\Q")).c_str(), get_bool(cell->getPort("\\Q"), "other_state").c_str())); - } - - if (cell->type.in("$ff", "$dff")) - { - std::string expr_d = get_bv(cell->getPort("\\D")); - std::string expr_q = get_bv(cell->getPort("\\Q"), "next_state"); - trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Q")))); - ex_state_eq.push_back(stringf("(= %s %s)", get_bv(cell->getPort("\\Q")).c_str(), get_bv(cell->getPort("\\Q"), "other_state").c_str())); - } - - if (cell->type.in("$anyconst", "$allconst")) - { - std::string expr_d = get_bv(cell->getPort("\\Y")); - std::string expr_q = get_bv(cell->getPort("\\Y"), "next_state"); - trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Y")))); - if (cell->type == "$anyconst") - ex_state_eq.push_back(stringf("(= %s %s)", get_bv(cell->getPort("\\Y")).c_str(), get_bv(cell->getPort("\\Y"), "other_state").c_str())); - } - - if (cell->type == "$mem") - { - int arrayid = memarrays.at(cell); - - int abits = cell->getParam("\\ABITS").as_int(); - int width = cell->getParam("\\WIDTH").as_int(); - int wr_ports = cell->getParam("\\WR_PORTS").as_int(); - - bool async_read = false; - string initial_memstate, final_memstate; - - if (!cell->getParam("\\WR_CLK_ENABLE").is_fully_ones()) { - log_assert(cell->getParam("\\WR_CLK_ENABLE").is_fully_zero()); - async_read = true; - initial_memstate = stringf("%s#%d#0", get_id(module), arrayid); - final_memstate = stringf("%s#%d#final", get_id(module), arrayid); - } - - if (statebv) - { - int mem_size = cell->getParam("\\SIZE").as_int(); - int mem_offset = cell->getParam("\\OFFSET").as_int(); - - if (async_read) { - makebits(final_memstate, width*mem_size, get_id(cell)); - } - - for (int i = 0; i < wr_ports; i++) - { - SigSpec addr_sig = cell->getPort("\\WR_ADDR").extract(abits*i, abits); - SigSpec data_sig = cell->getPort("\\WR_DATA").extract(width*i, width); - SigSpec mask_sig = cell->getPort("\\WR_EN").extract(width*i, width); - - std::string addr = get_bv(addr_sig); - std::string data = get_bv(data_sig); - std::string mask = get_bv(mask_sig); - - decls.push_back(stringf("(define-fun |%s_m:W%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig))); - addr = stringf("(|%s_m:W%dA %s| state)", get_id(module), i, get_id(cell)); - - decls.push_back(stringf("(define-fun |%s_m:W%dD %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), i, get_id(cell), get_id(module), width, data.c_str(), log_signal(data_sig))); - data = stringf("(|%s_m:W%dD %s| state)", get_id(module), i, get_id(cell)); - - decls.push_back(stringf("(define-fun |%s_m:W%dM %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), i, get_id(cell), get_id(module), width, mask.c_str(), log_signal(mask_sig))); - mask = stringf("(|%s_m:W%dM %s| state)", get_id(module), i, get_id(cell)); - - std::string data_expr; - - for (int k = mem_size-1; k >= 0; k--) { - std::string new_data = stringf("(bvor (bvand %s %s) (bvand ((_ extract %d %d) (|%s#%d#%d| state)) (bvnot %s)))", - data.c_str(), mask.c_str(), width*(k+1)-1, width*k, get_id(module), arrayid, i, mask.c_str()); - data_expr += stringf("\n (ite (= %s #b%s) %s ((_ extract %d %d) (|%s#%d#%d| state)))", - addr.c_str(), Const(k+mem_offset, abits).as_string().c_str(), new_data.c_str(), - width*(k+1)-1, width*k, get_id(module), arrayid, i); - } - - decls.push_back(stringf("(define-fun |%s#%d#%d| ((state |%s_s|)) (_ BitVec %d) (concat%s)) ; %s\n", - get_id(module), arrayid, i+1, get_id(module), width*mem_size, data_expr.c_str(), get_id(cell))); - } - } - else - { - if (async_read) { - if (statedt) - dtmembers.push_back(stringf(" (|%s| (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n", - initial_memstate.c_str(), abits, width, get_id(cell))); - else - decls.push_back(stringf("(declare-fun |%s| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n", - initial_memstate.c_str(), get_id(module), abits, width, get_id(cell))); - } - - for (int i = 0; i < wr_ports; i++) - { - SigSpec addr_sig = cell->getPort("\\WR_ADDR").extract(abits*i, abits); - SigSpec data_sig = cell->getPort("\\WR_DATA").extract(width*i, width); - SigSpec mask_sig = cell->getPort("\\WR_EN").extract(width*i, width); - - std::string addr = get_bv(addr_sig); - std::string data = get_bv(data_sig); - std::string mask = get_bv(mask_sig); - - decls.push_back(stringf("(define-fun |%s_m:W%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig))); - addr = stringf("(|%s_m:W%dA %s| state)", get_id(module), i, get_id(cell)); - - decls.push_back(stringf("(define-fun |%s_m:W%dD %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), i, get_id(cell), get_id(module), width, data.c_str(), log_signal(data_sig))); - data = stringf("(|%s_m:W%dD %s| state)", get_id(module), i, get_id(cell)); - - decls.push_back(stringf("(define-fun |%s_m:W%dM %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", - get_id(module), i, get_id(cell), get_id(module), width, mask.c_str(), log_signal(mask_sig))); - mask = stringf("(|%s_m:W%dM %s| state)", get_id(module), i, get_id(cell)); - - data = stringf("(bvor (bvand %s %s) (bvand (select (|%s#%d#%d| state) %s) (bvnot %s)))", - data.c_str(), mask.c_str(), get_id(module), arrayid, i, addr.c_str(), mask.c_str()); - - decls.push_back(stringf("(define-fun |%s#%d#%d| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) " - "(store (|%s#%d#%d| state) %s %s)) ; %s\n", - get_id(module), arrayid, i+1, get_id(module), abits, width, - get_id(module), arrayid, i, addr.c_str(), data.c_str(), get_id(cell))); - } - } - - std::string expr_d = stringf("(|%s#%d#%d| state)", get_id(module), arrayid, wr_ports); - std::string expr_q = stringf("(|%s#%d#0| next_state)", get_id(module), arrayid); - trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell))); - ex_state_eq.push_back(stringf("(= (|%s#%d#0| state) (|%s#%d#0| other_state))", get_id(module), arrayid, get_id(module), arrayid)); - - if (async_read) - hier.push_back(stringf(" (= %s (|%s| state)) ; %s\n", expr_d.c_str(), final_memstate.c_str(), get_id(cell))); - - Const init_data = cell->getParam("\\INIT"); - int memsize = cell->getParam("\\SIZE").as_int(); - - for (int i = 0; i < memsize; i++) - { - if (i*width >= GetSize(init_data)) - break; - - Const initword = init_data.extract(i*width, width, State::Sx); - Const initmask = initword; - bool gen_init_constr = false; - - for (int k = 0; k < GetSize(initword); k++) { - if (initword[k] == State::S0 || initword[k] == State::S1) { - gen_init_constr = true; - initmask[k] = State::S1; - } else { - initmask[k] = State::S0; - initword[k] = State::S0; - } - } - - if (gen_init_constr) - { - if (statebv) - /* FIXME */; - else - init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]", - get_id(module), arrayid, Const(i, abits).as_string().c_str(), - initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i)); - } - } - } - } - } - - if (verbose) log("=> finalizing SMT2 representation of %s.\n", log_id(module)); - - for (auto c : hiercells) { - assert_list.push_back(stringf("(|%s_a| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name))); - assume_list.push_back(stringf("(|%s_u| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name))); - init_list.push_back(stringf("(|%s_i| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name))); - hier.push_back(stringf(" (|%s_h| (|%s_h %s| state))\n", get_id(c->type), get_id(module), get_id(c->name))); - trans.push_back(stringf(" (|%s_t| (|%s_h %s| state) (|%s_h %s| next_state))\n", - get_id(c->type), get_id(module), get_id(c->name), get_id(module), get_id(c->name))); - ex_state_eq.push_back(stringf("(|%s_ex_state_eq| (|%s_h %s| state) (|%s_h %s| other_state))\n", - get_id(c->type), get_id(module), get_id(c->name), get_id(module), get_id(c->name))); - } - - if (forallmode) - { - string expr = ex_state_eq.empty() ? "true" : "(and"; - if (!ex_state_eq.empty()) { - if (GetSize(ex_state_eq) == 1) { - expr = "\n " + ex_state_eq.front() + "\n"; - } else { - for (auto &str : ex_state_eq) - expr += stringf("\n %s", str.c_str()); - expr += "\n)"; - } - } - decls.push_back(stringf("(define-fun |%s_ex_state_eq| ((state |%s_s|) (other_state |%s_s|)) Bool %s)\n", - get_id(module), get_id(module), get_id(module), expr.c_str())); - - expr = ex_input_eq.empty() ? "true" : "(and"; - if (!ex_input_eq.empty()) { - if (GetSize(ex_input_eq) == 1) { - expr = "\n " + ex_input_eq.front() + "\n"; - } else { - for (auto &str : ex_input_eq) - expr += stringf("\n %s", str.c_str()); - expr += "\n)"; - } - } - decls.push_back(stringf("(define-fun |%s_ex_input_eq| ((state |%s_s|) (other_state |%s_s|)) Bool %s)\n", - get_id(module), get_id(module), get_id(module), expr.c_str())); - } - - string assert_expr = assert_list.empty() ? "true" : "(and"; - if (!assert_list.empty()) { - if (GetSize(assert_list) == 1) { - assert_expr = "\n " + assert_list.front() + "\n"; - } else { - for (auto &str : assert_list) - assert_expr += stringf("\n %s", str.c_str()); - assert_expr += "\n)"; - } - } - decls.push_back(stringf("(define-fun |%s_a| ((state |%s_s|)) Bool %s)\n", - get_id(module), get_id(module), assert_expr.c_str())); - - string assume_expr = assume_list.empty() ? "true" : "(and"; - if (!assume_list.empty()) { - if (GetSize(assume_list) == 1) { - assume_expr = "\n " + assume_list.front() + "\n"; - } else { - for (auto &str : assume_list) - assume_expr += stringf("\n %s", str.c_str()); - assume_expr += "\n)"; - } - } - decls.push_back(stringf("(define-fun |%s_u| ((state |%s_s|)) Bool %s)\n", - get_id(module), get_id(module), assume_expr.c_str())); - - string init_expr = init_list.empty() ? "true" : "(and"; - if (!init_list.empty()) { - if (GetSize(init_list) == 1) { - init_expr = "\n " + init_list.front() + "\n"; - } else { - for (auto &str : init_list) - init_expr += stringf("\n %s", str.c_str()); - init_expr += "\n)"; - } - } - decls.push_back(stringf("(define-fun |%s_i| ((state |%s_s|)) Bool %s)\n", - get_id(module), get_id(module), init_expr.c_str())); - } - - void write(std::ostream &f) - { - f << stringf("; yosys-smt2-module %s\n", get_id(module)); - - if (statebv) { - f << stringf("(define-sort |%s_s| () (_ BitVec %d))\n", get_id(module), statebv_width); - mod_stbv_width[module->name] = statebv_width; - } else - if (statedt) { - f << stringf("(declare-datatype |%s_s| ((|%s_mk|\n", get_id(module), get_id(module)); - for (auto it : dtmembers) - f << it; - f << stringf(")))\n"); - } else - f << stringf("(declare-sort |%s_s| 0)\n", get_id(module)); - - for (auto it : decls) - f << it; - - f << stringf("(define-fun |%s_h| ((state |%s_s|)) Bool ", get_id(module), get_id(module)); - if (GetSize(hier) > 1) { - f << "(and\n"; - for (auto it : hier) - f << it; - f << "))\n"; - } else - if (GetSize(hier) == 1) - f << "\n" + hier.front() + ")\n"; - else - f << "true)\n"; - - f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", get_id(module), get_id(module), get_id(module)); - if (GetSize(trans) > 1) { - f << "(and\n"; - for (auto it : trans) - f << it; - f << "))"; - } else - if (GetSize(trans) == 1) - f << "\n" + trans.front() + ")"; - else - f << "true)"; - f << stringf(" ; end of module %s\n", get_id(module)); - } -}; - -struct Smt2Backend : public Backend { - Smt2Backend() : Backend("smt2", "write design to SMT-LIBv2 file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_smt2 [options] [filename]\n"); - log("\n"); - log("Write a SMT-LIBv2 [1] description of the current design. For a module with name\n"); - log("'' this will declare the sort '_s' (state of the module) and will\n"); - log("define and declare functions operating on that state.\n"); - log("\n"); - log("The following SMT2 functions are generated for a module with name ''.\n"); - log("Some declarations/definitions are printed with a special comment. A prover\n"); - log("using the SMT2 files can use those comments to collect all relevant metadata\n"); - log("about the design.\n"); - log("\n"); - log(" ; yosys-smt2-module \n"); - log(" (declare-sort |_s| 0)\n"); - log(" The sort representing a state of module .\n"); - log("\n"); - log(" (define-fun |_h| ((state |_s|)) Bool (...))\n"); - log(" This function must be asserted for each state to establish the\n"); - log(" design hierarchy.\n"); - log("\n"); - log(" ; yosys-smt2-input \n"); - log(" ; yosys-smt2-output \n"); - log(" ; yosys-smt2-register \n"); - log(" ; yosys-smt2-wire \n"); - log(" (define-fun |_n | (|_s|) (_ BitVec ))\n"); - log(" (define-fun |_n | (|_s|) Bool)\n"); - log(" For each port, register, and wire with the 'keep' attribute set an\n"); - log(" accessor function is generated. Single-bit wires are returned as Bool,\n"); - log(" multi-bit wires as BitVec.\n"); - log("\n"); - log(" ; yosys-smt2-cell \n"); - log(" (declare-fun |_h | (|_s|) |_s|)\n"); - log(" There is a function like that for each hierarchical instance. It\n"); - log(" returns the sort that represents the state of the sub-module that\n"); - log(" implements the instance.\n"); - log("\n"); - log(" (declare-fun |_is| (|_s|) Bool)\n"); - log(" This function must be asserted 'true' for initial states, and 'false'\n"); - log(" otherwise.\n"); - log("\n"); - log(" (define-fun |_i| ((state |_s|)) Bool (...))\n"); - log(" This function must be asserted 'true' for initial states. For\n"); - log(" non-initial states it must be left unconstrained.\n"); - log("\n"); - log(" (define-fun |_t| ((state |_s|) (next_state |_s|)) Bool (...))\n"); - log(" This function evaluates to 'true' if the states 'state' and\n"); - log(" 'next_state' form a valid state transition.\n"); - log("\n"); - log(" (define-fun |_a| ((state |_s|)) Bool (...))\n"); - log(" This function evaluates to 'true' if all assertions hold in the state.\n"); - log("\n"); - log(" (define-fun |_u| ((state |_s|)) Bool (...))\n"); - log(" This function evaluates to 'true' if all assumptions hold in the state.\n"); - log("\n"); - log(" ; yosys-smt2-assert \n"); - log(" (define-fun |_a | ((state |_s|)) Bool (...))\n"); - log(" Each $assert cell is converted into one of this functions. The function\n"); - log(" evaluates to 'true' if the assert statement holds in the state.\n"); - log("\n"); - log(" ; yosys-smt2-assume \n"); - log(" (define-fun |_u | ((state |_s|)) Bool (...))\n"); - log(" Each $assume cell is converted into one of this functions. The function\n"); - log(" evaluates to 'true' if the assume statement holds in the state.\n"); - log("\n"); - log(" ; yosys-smt2-cover \n"); - log(" (define-fun |_c | ((state |_s|)) Bool (...))\n"); - log(" Each $cover cell is converted into one of this functions. The function\n"); - log(" evaluates to 'true' if the cover statement is activated in the state.\n"); - log("\n"); - log("Options:\n"); - log("\n"); - log(" -verbose\n"); - log(" this will print the recursive walk used to export the modules.\n"); - log("\n"); - log(" -stbv\n"); - log(" Use a BitVec sort to represent a state instead of an uninterpreted\n"); - log(" sort. As a side-effect this will prevent use of arrays to model\n"); - log(" memories.\n"); - log("\n"); - log(" -stdt\n"); - log(" Use SMT-LIB 2.6 style datatypes to represent a state instead of an\n"); - log(" uninterpreted sort.\n"); - log("\n"); - log(" -nobv\n"); - log(" disable support for BitVec (FixedSizeBitVectors theory). without this\n"); - log(" option multi-bit wires are represented using the BitVec sort and\n"); - log(" support for coarse grain cells (incl. arithmetic) is enabled.\n"); - log("\n"); - log(" -nomem\n"); - log(" disable support for memories (via ArraysEx theory). this option is\n"); - log(" implied by -nobv. only $mem cells without merged registers in\n"); - log(" read ports are supported. call \"memory\" with -nordff to make sure\n"); - log(" that no registers are merged into $mem read ports. '_m' functions\n"); - log(" will be generated for accessing the arrays that are used to represent\n"); - log(" memories.\n"); - log("\n"); - log(" -wires\n"); - log(" create '_n' functions for all public wires. by default only ports,\n"); - log(" registers, and wires with the 'keep' attribute are exported.\n"); - log("\n"); - log(" -tpl \n"); - log(" use the given template file. the line containing only the token '%%%%'\n"); - log(" is replaced with the regular output of this command.\n"); - log("\n"); - log("[1] For more information on SMT-LIBv2 visit http://smt-lib.org/ or read David\n"); - log("R. Cok's tutorial: http://www.grammatech.com/resources/smt/SMTLIBTutorial.pdf\n"); - log("\n"); - log("---------------------------------------------------------------------------\n"); - log("\n"); - log("Example:\n"); - log("\n"); - log("Consider the following module (test.v). We want to prove that the output can\n"); - log("never transition from a non-zero value to a zero value.\n"); - log("\n"); - log(" module test(input clk, output reg [3:0] y);\n"); - log(" always @(posedge clk)\n"); - log(" y <= (y << 1) | ^y;\n"); - log(" endmodule\n"); - log("\n"); - log("For this proof we create the following template (test.tpl).\n"); - log("\n"); - log(" ; we need QF_UFBV for this poof\n"); - log(" (set-logic QF_UFBV)\n"); - log("\n"); - log(" ; insert the auto-generated code here\n"); - log(" %%%%\n"); - log("\n"); - log(" ; declare two state variables s1 and s2\n"); - log(" (declare-fun s1 () test_s)\n"); - log(" (declare-fun s2 () test_s)\n"); - log("\n"); - log(" ; state s2 is the successor of state s1\n"); - log(" (assert (test_t s1 s2))\n"); - log("\n"); - log(" ; we are looking for a model with y non-zero in s1\n"); - log(" (assert (distinct (|test_n y| s1) #b0000))\n"); - log("\n"); - log(" ; we are looking for a model with y zero in s2\n"); - log(" (assert (= (|test_n y| s2) #b0000))\n"); - log("\n"); - log(" ; is there such a model?\n"); - log(" (check-sat)\n"); - log("\n"); - log("The following yosys script will create a 'test.smt2' file for our proof:\n"); - log("\n"); - log(" read_verilog test.v\n"); - log(" hierarchy -check; proc; opt; check -assert\n"); - log(" write_smt2 -bv -tpl test.tpl test.smt2\n"); - log("\n"); - log("Running 'cvc4 test.smt2' will print 'unsat' because y can never transition\n"); - log("from non-zero to zero in the test design.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - std::ifstream template_f; - bool bvmode = true, memmode = true, wiresmode = false, verbose = false, statebv = false, statedt = false; - bool forallmode = false; - - log_header(design, "Executing SMT2 backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-tpl" && argidx+1 < args.size()) { - template_f.open(args[++argidx]); - if (template_f.fail()) - log_error("Can't open template file `%s'.\n", args[argidx].c_str()); - continue; - } - if (args[argidx] == "-bv" || args[argidx] == "-mem") { - log_warning("Options -bv and -mem are now the default. Support for -bv and -mem will be removed in the future.\n"); - continue; - } - if (args[argidx] == "-stbv") { - statebv = true; - statedt = false; - continue; - } - if (args[argidx] == "-stdt") { - statebv = false; - statedt = true; - continue; - } - if (args[argidx] == "-nobv") { - bvmode = false; - memmode = false; - continue; - } - if (args[argidx] == "-nomem") { - memmode = false; - continue; - } - if (args[argidx] == "-wires") { - wiresmode = true; - continue; - } - if (args[argidx] == "-verbose") { - verbose = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - if (template_f.is_open()) { - std::string line; - while (std::getline(template_f, line)) { - int indent = 0; - while (indent < GetSize(line) && (line[indent] == ' ' || line[indent] == '\t')) - indent++; - if (line.substr(indent, 2) == "%%") - break; - *f << line << std::endl; - } - } - - *f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_version_str); - - if (!bvmode) - *f << stringf("; yosys-smt2-nobv\n"); - - if (!memmode) - *f << stringf("; yosys-smt2-nomem\n"); - - if (statebv) - *f << stringf("; yosys-smt2-stbv\n"); - - if (statedt) - *f << stringf("; yosys-smt2-stdt\n"); - - std::vector sorted_modules; - - // extract module dependencies - std::map> module_deps; - for (auto &mod_it : design->modules_) { - module_deps[mod_it.second] = std::set(); - for (auto &cell_it : mod_it.second->cells_) - if (design->modules_.count(cell_it.second->type) > 0) - module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type)); - } - - // simple good-enough topological sort - // (O(n*m) on n elements and depth m) - while (module_deps.size() > 0) { - size_t sorted_modules_idx = sorted_modules.size(); - for (auto &it : module_deps) { - for (auto &dep : it.second) - if (module_deps.count(dep) > 0) - goto not_ready_yet; - // log("Next in topological sort: %s\n", RTLIL::id2cstr(it.first->name)); - sorted_modules.push_back(it.first); - not_ready_yet:; - } - if (sorted_modules_idx == sorted_modules.size()) - log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", RTLIL::id2cstr(module_deps.begin()->first->name)); - while (sorted_modules_idx < sorted_modules.size()) - module_deps.erase(sorted_modules.at(sorted_modules_idx++)); - } - - dict mod_stbv_width; - dict>> mod_clk_cache; - Module *topmod = design->top_module(); - std::string topmod_id; - - for (auto module : sorted_modules) - for (auto cell : module->cells()) - if (cell->type.in("$allconst", "$allseq")) - goto found_forall; - if (0) { - found_forall: - forallmode = true; - *f << stringf("; yosys-smt2-forall\n"); - if (!statebv && !statedt) - log_error("Forall-exists problems are only supported in -stbv or -stdt mode.\n"); - } - - for (auto module : sorted_modules) - { - if (module->get_blackbox_attribute() || module->has_memories_warn() || module->has_processes_warn()) - continue; - - log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module)); - - Smt2Worker worker(module, bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode, mod_stbv_width, mod_clk_cache); - worker.run(); - worker.write(*f); - - if (module == topmod) - topmod_id = worker.get_id(module); - } - - if (topmod) - *f << stringf("; yosys-smt2-topmod %s\n", topmod_id.c_str()); - - *f << stringf("; end of yosys output\n"); - - if (template_f.is_open()) { - std::string line; - while (std::getline(template_f, line)) - *f << line << std::endl; - } - } -} Smt2Backend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/smt2/smtbmc.py b/yosys/backends/smt2/smtbmc.py deleted file mode 100644 index 445a42e0d..000000000 --- a/yosys/backends/smt2/smtbmc.py +++ /dev/null @@ -1,1555 +0,0 @@ -#!/usr/bin/env python3 -# -# yosys -- Yosys Open SYnthesis Suite -# -# Copyright (C) 2012 Clifford Wolf -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -import os, sys, getopt, re -##yosys-sys-path## -from smtio import SmtIo, SmtOpts, MkVcd -from collections import defaultdict - -got_topt = False -skip_steps = 0 -step_size = 1 -num_steps = 20 -append_steps = 0 -vcdfile = None -cexfile = None -aimfile = None -aiwfile = None -aigheader = True -btorwitfile = None -vlogtbfile = None -vlogtbtop = None -inconstr = list() -outconstr = None -gentrace = False -covermode = False -tempind = False -dumpall = False -assume_skipped = None -final_only = False -topmod = None -noinfo = False -presat = False -smtcinit = False -smtctop = None -noinit = False -so = SmtOpts() - - -def usage(): - print(""" -yosys-smtbmc [options] - - -t - -t : - -t :: - default: skip_steps=0, step_size=1, num_steps=20 - - -g - generate an arbitrary trace that satisfies - all assertions and assumptions. - - -i - instead of BMC run temporal induction - - -c - instead of regular BMC run cover analysis - - -m - name of the top module - - --smtc - read constraints file - - --cex - read cex file as written by ABC's "write_cex -n" - - --aig - read AIGER map file (as written by Yosys' "write_aiger -map") - and AIGER witness file. The file names are .aim for - the map file and .aiw for the witness file. - - --aig : - like above, but for map files and witness files that do not - share a filename prefix (or use different file extensions). - - --aig-noheader - the AIGER witness file does not include the status and - properties lines. - - --btorwit - read a BTOR witness. - - --noinfo - only run the core proof, do not collect and print any - additional information (e.g. which assert failed) - - --presat - check if the design with assumptions but without assertions - is SAT before checking if assertions are UNSAT. This will - detect if there are contradicting assumptions. In some cases - this will also help to "warm up" the solver, potentially - yielding a speedup. - - --final-only - only check final constraints, assume base case - - --assume-skipped - assume asserts in skipped steps in BMC. - no assumptions are created for skipped steps - before . - - --dump-vcd - write trace to this VCD file - (hint: use 'write_smt2 -wires' for maximum - coverage of signals in generated VCD file) - - --dump-vlogtb - write trace as Verilog test bench - - --vlogtb-top - use the given entity as top module for the generated - Verilog test bench. The is relative - to the design top module without the top module name. - - --dump-smtc - write trace as constraints file - - --smtc-init - write just the last state as initial constraint to smtc file - - --smtc-top [:] - replace with in constraints dumped to smtc - file and only dump object below in design hierarchy. - - --noinit - do not assume initial conditions in state 0 - - --dump-all - when using -g or -i, create a dump file for each - step. The character '%' is replaces in all dump - filenames with the step number. - - --append - add time steps at the end of the trace - when creating a counter example (this additional time - steps will still be constrained by assumptions) -""" + so.helpmsg()) - sys.exit(1) - - -try: - opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts + - ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat", - "dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=", - "smtc-init", "smtc-top=", "noinit"]) -except: - usage() - -for o, a in opts: - if o == "-t": - got_topt = True - a = a.split(":") - if len(a) == 1: - num_steps = int(a[0]) - elif len(a) == 2: - skip_steps = int(a[0]) - num_steps = int(a[1]) - elif len(a) == 3: - skip_steps = int(a[0]) - step_size = int(a[1]) - num_steps = int(a[2]) - else: - assert False - elif o == "--assume-skipped": - assume_skipped = int(a) - elif o == "--final-only": - final_only = True - elif o == "--smtc": - inconstr.append(a) - elif o == "--cex": - cexfile = a - elif o == "--aig": - if ":" in a: - aimfile, aiwfile = a.split(":") - else: - aimfile = a + ".aim" - aiwfile = a + ".aiw" - elif o == "--aig-noheader": - aigheader = False - elif o == "--btorwit": - btorwitfile = a - elif o == "--dump-vcd": - vcdfile = a - elif o == "--dump-vlogtb": - vlogtbfile = a - elif o == "--vlogtb-top": - vlogtbtop = a - elif o == "--dump-smtc": - outconstr = a - elif o == "--smtc-init": - smtcinit = True - elif o == "--smtc-top": - smtctop = a.split(":") - if len(smtctop) == 1: - smtctop.append("") - assert len(smtctop) == 2 - smtctop = tuple(smtctop) - elif o == "--dump-all": - dumpall = True - elif o == "--presat": - presat = True - elif o == "--noinfo": - noinfo = True - elif o == "--noinit": - noinit = True - elif o == "--append": - append_steps = int(a) - elif o == "-i": - tempind = True - elif o == "-g": - gentrace = True - elif o == "-c": - covermode = True - elif o == "-m": - topmod = a - elif so.handle(o, a): - pass - else: - usage() - -if len(args) != 1: - usage() - -if sum([tempind, gentrace, covermode]) > 1: - usage() - -constr_final_start = None -constr_asserts = defaultdict(list) -constr_assumes = defaultdict(list) -constr_write = list() - -for fn in inconstr: - current_states = None - current_line = 0 - - with open(fn, "r") as f: - for line in f: - current_line += 1 - - if line.startswith("#"): - continue - - tokens = line.split() - - if len(tokens) == 0: - continue - - if tokens[0] == "initial": - current_states = set() - if not tempind: - current_states.add(0) - continue - - if tokens[0] == "final": - constr_final = True - if len(tokens) == 1: - current_states = set(["final-%d" % i for i in range(0, num_steps+1)]) - constr_final_start = 0 - elif len(tokens) == 2: - arg = abs(int(tokens[1])) - current_states = set(["final-%d" % i for i in range(arg, num_steps+1)]) - constr_final_start = arg if constr_final_start is None else min(constr_final_start, arg) - else: - assert False - continue - - if tokens[0] == "state": - current_states = set() - if not tempind: - for token in tokens[1:]: - tok = token.split(":") - if len(tok) == 1: - current_states.add(int(token)) - elif len(tok) == 2: - lower = int(tok[0]) - if tok[1] == "*": - upper = num_steps - else: - upper = int(tok[1]) - for i in range(lower, upper+1): - current_states.add(i) - else: - assert False - continue - - if tokens[0] == "always": - if len(tokens) == 1: - current_states = set(range(0, num_steps+1)) - elif len(tokens) == 2: - arg = abs(int(tokens[1])) - current_states = set(range(arg, num_steps+1)) - else: - assert False - continue - - if tokens[0] == "assert": - assert current_states is not None - - for state in current_states: - constr_asserts[state].append(("%s:%d" % (fn, current_line), " ".join(tokens[1:]))) - - continue - - if tokens[0] == "assume": - assert current_states is not None - - for state in current_states: - constr_assumes[state].append(("%s:%d" % (fn, current_line), " ".join(tokens[1:]))) - - continue - - if tokens[0] == "write": - constr_write.append(" ".join(tokens[1:])) - continue - - if tokens[0] == "logic": - so.logic = " ".join(tokens[1:]) - continue - - assert False - - -def get_constr_expr(db, state, final=False, getvalues=False): - if final: - if ("final-%d" % state) not in db: - return ([], [], []) if getvalues else "true" - else: - if state not in db: - return ([], [], []) if getvalues else "true" - - netref_regex = re.compile(r'(^|[( ])\[(-?[0-9]+:|)([^\]]*|\S*)\](?=[ )]|$)') - - def replace_netref(match): - state_sel = match.group(2) - - if state_sel == "": - st = state - elif state_sel[0] == "-": - st = state + int(state_sel[:-1]) - else: - st = int(state_sel[:-1]) - - expr = smt.net_expr(topmod, "s%d" % st, smt.get_path(topmod, match.group(3))) - - return match.group(1) + expr - - expr_list = list() - for loc, expr in db[("final-%d" % state) if final else state]: - actual_expr = netref_regex.sub(replace_netref, expr) - if getvalues: - expr_list.append((loc, expr, actual_expr)) - else: - expr_list.append(actual_expr) - - if getvalues: - loc_list, expr_list, acual_expr_list = zip(*expr_list) - value_list = smt.get_list(acual_expr_list) - return loc_list, expr_list, value_list - - if len(expr_list) == 0: - return "true" - - if len(expr_list) == 1: - return expr_list[0] - - return "(and %s)" % " ".join(expr_list) - - -smt = SmtIo(opts=so) - -if noinfo and vcdfile is None and vlogtbfile is None and outconstr is None: - smt.produce_models = False - -def print_msg(msg): - print("%s %s" % (smt.timestamp(), msg)) - sys.stdout.flush() - -print_msg("Solver: %s" % (so.solver)) - -with open(args[0], "r") as f: - for line in f: - smt.write(line) - -for line in constr_write: - smt.write(line) - -if topmod is None: - topmod = smt.topmod - -assert topmod is not None -assert topmod in smt.modinfo - -if cexfile is not None: - if not got_topt: - assume_skipped = 0 - skip_steps = 0 - num_steps = 0 - - with open(cexfile, "r") as f: - cex_regex = re.compile(r'([^\[@=]+)(\[\d+\])?([^@=]*)(@\d+)=([01])') - for entry in f.read().split(): - match = cex_regex.match(entry) - assert match - - name, bit, extra_name, step, val = match.group(1), match.group(2), match.group(3), match.group(4), match.group(5) - - if extra_name != "": - continue - - if name not in smt.modinfo[topmod].inputs: - continue - - if bit is None: - bit = 0 - else: - bit = int(bit[1:-1]) - - step = int(step[1:]) - val = int(val) - - if smt.modinfo[topmod].wsize[name] == 1: - assert bit == 0 - smtexpr = "(= [%s] %s)" % (name, "true" if val else "false") - else: - smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bit, bit, name, val) - - # print("cex@%d: %s" % (step, smtexpr)) - constr_assumes[step].append((cexfile, smtexpr)) - - if not got_topt: - skip_steps = max(skip_steps, step) - num_steps = max(num_steps, step+1) - -if aimfile is not None: - input_map = dict() - init_map = dict() - latch_map = dict() - - if not got_topt: - assume_skipped = 0 - skip_steps = 0 - num_steps = 0 - - with open(aimfile, "r") as f: - for entry in f.read().splitlines(): - entry = entry.split() - - if entry[0] == "input": - input_map[int(entry[1])] = (entry[3], int(entry[2])) - continue - - if entry[0] == "init": - init_map[int(entry[1])] = (entry[3], int(entry[2])) - continue - - if entry[0] in ["latch", "invlatch"]: - latch_map[int(entry[1])] = (entry[3], int(entry[2]), entry[0] == "invlatch") - continue - - if entry[0] in ["output", "wire"]: - continue - - assert False - - with open(aiwfile, "r") as f: - got_state = False - got_ffinit = False - step = 0 - - if not aigheader: - got_state = True - - for entry in f.read().splitlines(): - if len(entry) == 0 or entry[0] in "bcjfu.": - continue - - if not got_state: - got_state = True - assert entry == "1" - continue - - if not got_ffinit: - got_ffinit = True - if len(init_map) == 0: - for i in range(len(entry)): - if entry[i] == "x": - continue - - if i in latch_map: - value = int(entry[i]) - name = latch_map[i][0] - bitidx = latch_map[i][1] - invert = latch_map[i][2] - - if invert: - value = 1 - value - - path = smt.get_path(topmod, name) - width = smt.net_width(topmod, path) - - if width == 1: - assert bitidx == 0 - smtexpr = "(= [%s] %s)" % (name, "true" if value else "false") - else: - smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx, bitidx, name, value) - - constr_assumes[0].append((cexfile, smtexpr)) - continue - - for i in range(len(entry)): - if entry[i] == "x": - continue - - if (step == 0) and (i in init_map): - value = int(entry[i]) - name = init_map[i][0] - bitidx = init_map[i][1] - - path = smt.get_path(topmod, name) - - if not smt.net_exists(topmod, path): - match = re.match(r"(.*)\[(\d+)\]$", path[-1]) - if match: - path[-1] = match.group(1) - addr = int(match.group(2)) - - if not match or not smt.mem_exists(topmod, path): - print_msg("Ignoring init value for unknown net: %s" % (name)) - continue - - meminfo = smt.mem_info(topmod, path) - smtexpr = "(select [%s] #b%s)" % (".".join(path), bin(addr)[2:].zfill(meminfo[0])) - width = meminfo[1] - - else: - smtexpr = "[%s]" % name - width = smt.net_width(topmod, path) - - if width == 1: - assert bitidx == 0 - smtexpr = "(= %s %s)" % (smtexpr, "true" if value else "false") - else: - smtexpr = "(= ((_ extract %d %d) %s) #b%d)" % (bitidx, bitidx, smtexpr, value) - - constr_assumes[0].append((cexfile, smtexpr)) - - if i in input_map: - value = int(entry[i]) - name = input_map[i][0] - bitidx = input_map[i][1] - - path = smt.get_path(topmod, name) - width = smt.net_width(topmod, path) - - if width == 1: - assert bitidx == 0 - smtexpr = "(= [%s] %s)" % (name, "true" if value else "false") - else: - smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx, bitidx, name, value) - - constr_assumes[step].append((cexfile, smtexpr)) - - if not got_topt: - skip_steps = max(skip_steps, step) - num_steps = max(num_steps, step+1) - step += 1 - -if btorwitfile is not None: - with open(btorwitfile, "r") as f: - step = None - suffix = None - altsuffix = None - header_okay = False - - for line in f: - line = line.strip() - - if line == "sat": - header_okay = True - continue - - if not header_okay: - continue - - if line == "" or line[0] == "b" or line[0] == "j": - continue - - if line == ".": - break - - if line[0] == '#' or line[0] == '@': - step = int(line[1:]) - suffix = line - altsuffix = suffix - if suffix[0] == "@": - altsuffix = "#" + suffix[1:] - else: - altsuffix = "@" + suffix[1:] - continue - - line = line.split() - - if len(line) == 0: - continue - - if line[-1].endswith(suffix): - line[-1] = line[-1][0:len(line[-1]) - len(suffix)] - - if line[-1].endswith(altsuffix): - line[-1] = line[-1][0:len(line[-1]) - len(altsuffix)] - - if line[-1][0] == "$": - continue - - # BV assignments - if len(line) == 3 and line[1][0] != "[": - value = line[1] - name = line[2] - - path = smt.get_path(topmod, name) - - if not smt.net_exists(topmod, path): - continue - - width = smt.net_width(topmod, path) - - if width == 1: - assert value in ["0", "1"] - value = "true" if value == "1" else "false" - else: - value = "#b" + value - - smtexpr = "(= [%s] %s)" % (name, value) - constr_assumes[step].append((btorwitfile, smtexpr)) - - # Array assignments - if len(line) == 4 and line[1][0] == "[": - index = line[1] - value = line[2] - name = line[3] - - path = smt.get_path(topmod, name) - - if not smt.mem_exists(topmod, path): - continue - - meminfo = smt.mem_info(topmod, path) - - if meminfo[1] == 1: - assert value in ["0", "1"] - value = "true" if value == "1" else "false" - else: - value = "#b" + value - - assert index[0] == "[" - assert index[-1] == "]" - index = "#b" + index[1:-1] - - smtexpr = "(= (select [%s] %s) %s)" % (name, index, value) - constr_assumes[step].append((btorwitfile, smtexpr)) - - skip_steps = step - num_steps = step+1 - -def write_vcd_trace(steps_start, steps_stop, index): - filename = vcdfile.replace("%", index) - print_msg("Writing trace to VCD file: %s" % (filename)) - - with open(filename, "w") as vcd_file: - vcd = MkVcd(vcd_file) - path_list = list() - - for netpath in sorted(smt.hiernets(topmod)): - hidden_net = False - for n in netpath: - if n.startswith("$"): - hidden_net = True - if not hidden_net: - edge = smt.net_clock(topmod, netpath) - if edge is None: - vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath)) - else: - vcd.add_clock([topmod] + netpath, edge) - path_list.append(netpath) - - mem_trace_data = dict() - for mempath in sorted(smt.hiermems(topmod)): - abits, width, rports, wports, asyncwr = smt.mem_info(topmod, mempath) - - expr_id = list() - expr_list = list() - for i in range(steps_start, steps_stop): - for j in range(rports): - expr_id.append(('R', i-steps_start, j, 'A')) - expr_id.append(('R', i-steps_start, j, 'D')) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dA" % j)) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dD" % j)) - for j in range(wports): - expr_id.append(('W', i-steps_start, j, 'A')) - expr_id.append(('W', i-steps_start, j, 'D')) - expr_id.append(('W', i-steps_start, j, 'M')) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dA" % j)) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dD" % j)) - expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "W%dM" % j)) - - rdata = list() - wdata = list() - addrs = set() - - for eid, edat in zip(expr_id, smt.get_list(expr_list)): - t, i, j, f = eid - - if t == 'R': - c = rdata - elif t == 'W': - c = wdata - else: - assert False - - while len(c) <= i: - c.append(list()) - c = c[i] - - while len(c) <= j: - c.append(dict()) - c = c[j] - - c[f] = smt.bv2bin(edat) - - if f == 'A': - addrs.add(c[f]) - - for addr in addrs: - tdata = list() - data = ["x"] * width - gotread = False - - if len(wdata) == 0 and len(rdata) != 0: - wdata = [[]] * len(rdata) - - assert len(rdata) == len(wdata) - - for i in range(len(wdata)): - if not gotread: - for j_data in rdata[i]: - if j_data["A"] == addr: - data = list(j_data["D"]) - gotread = True - break - - if gotread: - buf = data[:] - for i in reversed(range(len(tdata))): - for k in range(width): - if tdata[i][k] == "x": - tdata[i][k] = buf[k] - else: - buf[k] = tdata[i][k] - - if not asyncwr: - tdata.append(data[:]) - - for j_data in wdata[i]: - if j_data["A"] != addr: - continue - - D = j_data["D"] - M = j_data["M"] - - for k in range(width): - if M[k] == "1": - data[k] = D[k] - - if asyncwr: - tdata.append(data[:]) - - assert len(tdata) == len(rdata) - - netpath = mempath[:] - netpath[-1] += "<%0*x>" % ((len(addr)+3) // 4, int(addr, 2)) - vcd.add_net([topmod] + netpath, width) - - for i in range(steps_start, steps_stop): - if i not in mem_trace_data: - mem_trace_data[i] = list() - mem_trace_data[i].append((netpath, "".join(tdata[i-steps_start]))) - - for i in range(steps_start, steps_stop): - vcd.set_time(i) - value_list = smt.get_net_bin_list(topmod, path_list, "s%d" % i) - for path, value in zip(path_list, value_list): - vcd.set_net([topmod] + path, value) - if i in mem_trace_data: - for path, value in mem_trace_data[i]: - vcd.set_net([topmod] + path, value) - - vcd.set_time(steps_stop) - - -def write_vlogtb_trace(steps_start, steps_stop, index): - filename = vlogtbfile.replace("%", index) - print_msg("Writing trace to Verilog testbench: %s" % (filename)) - - vlogtb_topmod = topmod - vlogtb_state = "s@@step_idx@@" - - if vlogtbtop is not None: - for item in vlogtbtop.split("."): - if item in smt.modinfo[vlogtb_topmod].cells: - vlogtb_state = "(|%s_h %s| %s)" % (vlogtb_topmod, item, vlogtb_state) - vlogtb_topmod = smt.modinfo[vlogtb_topmod].cells[item] - else: - print_msg("Vlog top module '%s' not found: no cell '%s' in module '%s'" % (vlogtbtop, item, vlogtb_topmod)) - break - - with open(filename, "w") as f: - print("`ifndef VERILATOR", file=f) - print("module testbench;", file=f) - print(" reg [4095:0] vcdfile;", file=f) - print(" reg clock;", file=f) - print("`else", file=f) - print("module testbench(input clock, output reg genclock);", file=f) - print(" initial genclock = 1;", file=f) - print("`endif", file=f) - - print(" reg genclock = 1;", file=f) - print(" reg [31:0] cycle = 0;", file=f) - - primary_inputs = list() - clock_inputs = set() - - for name in smt.modinfo[vlogtb_topmod].inputs: - if name in ["clk", "clock", "CLK", "CLOCK"]: - clock_inputs.add(name) - width = smt.modinfo[vlogtb_topmod].wsize[name] - primary_inputs.append((name, width)) - - for name, width in primary_inputs: - if name in clock_inputs: - print(" wire [%d:0] PI_%s = clock;" % (width-1, name), file=f) - else: - print(" reg [%d:0] PI_%s;" % (width-1, name), file=f) - - print(" %s UUT (" % vlogtb_topmod, file=f) - print(",\n".join(" .{name}(PI_{name})".format(name=name) for name, _ in primary_inputs), file=f) - print(" );", file=f) - - print("`ifndef VERILATOR", file=f) - print(" initial begin", file=f) - print(" if ($value$plusargs(\"vcd=%s\", vcdfile)) begin", file=f) - print(" $dumpfile(vcdfile);", file=f) - print(" $dumpvars(0, testbench);", file=f) - print(" end", file=f) - print(" #5 clock = 0;", file=f) - print(" while (genclock) begin", file=f) - print(" #5 clock = 0;", file=f) - print(" #5 clock = 1;", file=f) - print(" end", file=f) - print(" end", file=f) - print("`endif", file=f) - - print(" initial begin", file=f) - - regs = sorted(smt.hiernets(vlogtb_topmod, regs_only=True)) - regvals = smt.get_net_bin_list(vlogtb_topmod, regs, vlogtb_state.replace("@@step_idx@@", str(steps_start))) - - print("`ifndef VERILATOR", file=f) - print(" #1;", file=f) - print("`endif", file=f) - for reg, val in zip(regs, regvals): - hidden_net = False - for n in reg: - if n.startswith("$"): - hidden_net = True - print(" %sUUT.%s = %d'b%s;" % ("// " if hidden_net else "", ".".join(reg), len(val), val), file=f) - - anyconsts = sorted(smt.hieranyconsts(vlogtb_topmod)) - for info in anyconsts: - if info[3] is not None: - modstate = smt.net_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(steps_start)), info[0]) - value = smt.bv2bin(smt.get("(|%s| %s)" % (info[1], modstate))) - print(" UUT.%s = %d'b%s;" % (".".join(info[0] + [info[3]]), len(value), value), file=f); - - mems = sorted(smt.hiermems(vlogtb_topmod)) - for mempath in mems: - abits, width, rports, wports, asyncwr = smt.mem_info(vlogtb_topmod, mempath) - - addr_expr_list = list() - data_expr_list = list() - for i in range(steps_start, steps_stop): - for j in range(rports): - addr_expr_list.append(smt.mem_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), mempath, "R%dA" % j)) - data_expr_list.append(smt.mem_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), mempath, "R%dD" % j)) - - addr_list = smt.get_list(addr_expr_list) - data_list = smt.get_list(data_expr_list) - - addr_data = dict() - for addr, data in zip(addr_list, data_list): - addr = smt.bv2bin(addr) - data = smt.bv2bin(data) - if addr not in addr_data: - addr_data[addr] = data - - for addr, data in addr_data.items(): - print(" UUT.%s[%d'b%s] = %d'b%s;" % (".".join(mempath), len(addr), addr, len(data), data), file=f) - - print("", file=f) - anyseqs = sorted(smt.hieranyseqs(vlogtb_topmod)) - - for i in range(steps_start, steps_stop): - pi_names = [[name] for name, _ in primary_inputs if name not in clock_inputs] - pi_values = smt.get_net_bin_list(vlogtb_topmod, pi_names, vlogtb_state.replace("@@step_idx@@", str(i))) - - print(" // state %d" % i, file=f) - - if i > 0: - print(" if (cycle == %d) begin" % (i-1), file=f) - - for name, val in zip(pi_names, pi_values): - if i > 0: - print(" PI_%s <= %d'b%s;" % (".".join(name), len(val), val), file=f) - else: - print(" PI_%s = %d'b%s;" % (".".join(name), len(val), val), file=f) - - for info in anyseqs: - if info[3] is not None: - modstate = smt.net_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), info[0]) - value = smt.bv2bin(smt.get("(|%s| %s)" % (info[1], modstate))) - if i > 0: - print(" UUT.%s <= %d'b%s;" % (".".join(info[0] + [info[3]]), len(value), value), file=f); - else: - print(" UUT.%s = %d'b%s;" % (".".join(info[0] + [info[3]]), len(value), value), file=f); - - if i > 0: - print(" end", file=f) - print("", file=f) - - if i == 0: - print(" end", file=f) - print(" always @(posedge clock) begin", file=f) - - print(" genclock <= cycle < %d;" % (steps_stop-1), file=f) - print(" cycle <= cycle + 1;", file=f) - print(" end", file=f) - - print("endmodule", file=f) - - -def write_constr_trace(steps_start, steps_stop, index): - filename = outconstr.replace("%", index) - print_msg("Writing trace to constraints file: %s" % (filename)) - - constr_topmod = topmod - constr_state = "s@@step_idx@@" - constr_prefix = "" - - if smtctop is not None: - for item in smtctop[0].split("."): - assert item in smt.modinfo[constr_topmod].cells - constr_state = "(|%s_h %s| %s)" % (constr_topmod, item, constr_state) - constr_topmod = smt.modinfo[constr_topmod].cells[item] - if smtctop[1] != "": - constr_prefix = smtctop[1] + "." - - if smtcinit: - steps_start = steps_stop - 1 - - with open(filename, "w") as f: - primary_inputs = list() - - for name in smt.modinfo[constr_topmod].inputs: - width = smt.modinfo[constr_topmod].wsize[name] - primary_inputs.append((name, width)) - - if steps_start == 0 or smtcinit: - print("initial", file=f) - else: - print("state %d" % steps_start, file=f) - - regnames = sorted(smt.hiernets(constr_topmod, regs_only=True)) - regvals = smt.get_net_list(constr_topmod, regnames, constr_state.replace("@@step_idx@@", str(steps_start))) - - for name, val in zip(regnames, regvals): - print("assume (= [%s%s] %s)" % (constr_prefix, ".".join(name), val), file=f) - - mems = sorted(smt.hiermems(constr_topmod)) - for mempath in mems: - abits, width, rports, wports, asyncwr = smt.mem_info(constr_topmod, mempath) - - addr_expr_list = list() - data_expr_list = list() - for i in range(steps_start, steps_stop): - for j in range(rports): - addr_expr_list.append(smt.mem_expr(constr_topmod, constr_state.replace("@@step_idx@@", str(i)), mempath, "R%dA" % j)) - data_expr_list.append(smt.mem_expr(constr_topmod, constr_state.replace("@@step_idx@@", str(i)), mempath, "R%dD" % j)) - - addr_list = smt.get_list(addr_expr_list) - data_list = smt.get_list(data_expr_list) - - addr_data = dict() - for addr, data in zip(addr_list, data_list): - if addr not in addr_data: - addr_data[addr] = data - - for addr, data in addr_data.items(): - print("assume (= (select [%s%s] %s) %s)" % (constr_prefix, ".".join(mempath), addr, data), file=f) - - for k in range(steps_start, steps_stop): - if not smtcinit: - print("", file=f) - print("state %d" % k, file=f) - - pi_names = [[name] for name, _ in sorted(primary_inputs)] - pi_values = smt.get_net_list(constr_topmod, pi_names, constr_state.replace("@@step_idx@@", str(k))) - - for name, val in zip(pi_names, pi_values): - print("assume (= [%s%s] %s)" % (constr_prefix, ".".join(name), val), file=f) - - -def write_trace(steps_start, steps_stop, index): - if vcdfile is not None: - write_vcd_trace(steps_start, steps_stop, index) - - if vlogtbfile is not None: - write_vlogtb_trace(steps_start, steps_stop, index) - - if outconstr is not None: - write_constr_trace(steps_start, steps_stop, index) - - -def print_failed_asserts_worker(mod, state, path, extrainfo): - assert mod in smt.modinfo - found_failed_assert = False - - if smt.get("(|%s_a| %s)" % (mod, state)) in ["true", "#b1"]: - return - - for cellname, celltype in smt.modinfo[mod].cells.items(): - if print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname, extrainfo): - found_failed_assert = True - - for assertfun, assertinfo in smt.modinfo[mod].asserts.items(): - if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]: - print_msg("Assert failed in %s: %s%s" % (path, assertinfo, extrainfo)) - found_failed_assert = True - - return found_failed_assert - - -def print_failed_asserts(state, final=False, extrainfo=""): - if noinfo: return - loc_list, expr_list, value_list = get_constr_expr(constr_asserts, state, final=final, getvalues=True) - found_failed_assert = False - - for loc, expr, value in zip(loc_list, expr_list, value_list): - if smt.bv2int(value) == 0: - print_msg("Assert %s failed: %s%s" % (loc, expr, extrainfo)) - found_failed_assert = True - - if not final: - if print_failed_asserts_worker(topmod, "s%d" % state, topmod, extrainfo): - found_failed_assert = True - - return found_failed_assert - - -def print_anyconsts_worker(mod, state, path): - assert mod in smt.modinfo - - for cellname, celltype in smt.modinfo[mod].cells.items(): - print_anyconsts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname) - - for fun, info in smt.modinfo[mod].anyconsts.items(): - if info[1] is None: - print_msg("Value for anyconst in %s (%s): %d" % (path, info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state))))) - else: - print_msg("Value for anyconst %s.%s (%s): %d" % (path, info[1], info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state))))) - - -def print_anyconsts(state): - if noinfo: return - print_anyconsts_worker(topmod, "s%d" % state, topmod) - - -def get_cover_list(mod, base): - assert mod in smt.modinfo - - cover_expr = list() - cover_desc = list() - - for expr, desc in smt.modinfo[mod].covers.items(): - cover_expr.append("(ite (|%s| %s) #b1 #b0)" % (expr, base)) - cover_desc.append(desc) - - for cell, submod in smt.modinfo[mod].cells.items(): - e, d = get_cover_list(submod, "(|%s_h %s| %s)" % (mod, cell, base)) - cover_expr += e - cover_desc += d - - return cover_expr, cover_desc - -states = list() -asserts_antecedent_cache = [list()] -asserts_consequent_cache = [list()] -asserts_cache_dirty = False - -def smt_state(step): - smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod)) - states.append("s%d" % step) - -def smt_assert(expr): - if expr == "true": - return - - smt.write("(assert %s)" % expr) - -def smt_assert_antecedent(expr): - if expr == "true": - return - - smt.write("(assert %s)" % expr) - - global asserts_cache_dirty - asserts_cache_dirty = True - asserts_antecedent_cache[-1].append(expr) - -def smt_assert_consequent(expr): - if expr == "true": - return - - smt.write("(assert %s)" % expr) - - global asserts_cache_dirty - asserts_cache_dirty = True - asserts_consequent_cache[-1].append(expr) - -def smt_forall_assert(): - if not smt.forall: - return - - global asserts_cache_dirty - asserts_cache_dirty = False - - def make_assert_expr(asserts_cache): - expr = list() - for lst in asserts_cache: - expr += lst - - assert len(expr) != 0 - - if len(expr) == 1: - expr = expr[0] - else: - expr = "(and %s)" % (" ".join(expr)) - return expr - - antecedent_expr = make_assert_expr(asserts_antecedent_cache) - consequent_expr = make_assert_expr(asserts_consequent_cache) - - states_db = set(states) - used_states_db = set() - new_antecedent_expr = list() - new_consequent_expr = list() - assert_expr = list() - - def make_new_expr(new_expr, expr): - cursor = 0 - while cursor < len(expr): - l = 1 - if expr[cursor] in '|"': - while cursor+l+1 < len(expr) and expr[cursor] != expr[cursor+l]: - l += 1 - l += 1 - elif expr[cursor] not in '() ': - while cursor+l < len(expr) and expr[cursor+l] not in '|"() ': - l += 1 - - word = expr[cursor:cursor+l] - if word in states_db: - used_states_db.add(word) - word += "_" - - new_expr.append(word) - cursor += l - - make_new_expr(new_antecedent_expr, antecedent_expr) - make_new_expr(new_consequent_expr, consequent_expr) - - new_antecedent_expr = ["".join(new_antecedent_expr)] - new_consequent_expr = ["".join(new_consequent_expr)] - - if states[0] in used_states_db: - new_antecedent_expr.append("(|%s_ex_state_eq| %s %s_)" % (topmod, states[0], states[0])) - for s in states: - if s in used_states_db: - new_antecedent_expr.append("(|%s_ex_input_eq| %s %s_)" % (topmod, s, s)) - - if len(new_antecedent_expr) == 0: - new_antecedent_expr = "true" - elif len(new_antecedent_expr) == 1: - new_antecedent_expr = new_antecedent_expr[0] - else: - new_antecedent_expr = "(and %s)" % (" ".join(new_antecedent_expr)) - - if len(new_consequent_expr) == 0: - new_consequent_expr = "true" - elif len(new_consequent_expr) == 1: - new_consequent_expr = new_consequent_expr[0] - else: - new_consequent_expr = "(and %s)" % (" ".join(new_consequent_expr)) - - assert_expr.append("(assert (forall (") - first_state = True - for s in states: - if s in used_states_db: - assert_expr.append("%s(%s_ |%s_s|)" % ("" if first_state else " ", s, topmod)) - first_state = False - assert_expr.append(") (=> %s %s)))" % (new_antecedent_expr, new_consequent_expr)) - - smt.write("".join(assert_expr)) - -def smt_push(): - global asserts_cache_dirty - asserts_cache_dirty = True - asserts_antecedent_cache.append(list()) - asserts_consequent_cache.append(list()) - smt.write("(push 1)") - -def smt_pop(): - global asserts_cache_dirty - asserts_cache_dirty = True - asserts_antecedent_cache.pop() - asserts_consequent_cache.pop() - smt.write("(pop 1)") - -def smt_check_sat(): - if asserts_cache_dirty: - smt_forall_assert() - return smt.check_sat() - -if tempind: - retstatus = False - skip_counter = step_size - for step in range(num_steps, -1, -1): - if smt.forall: - print_msg("Temporal induction not supported for exists-forall problems.") - break - - smt_state(step) - smt_assert_consequent("(|%s_u| s%d)" % (topmod, step)) - smt_assert_antecedent("(|%s_h| s%d)" % (topmod, step)) - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step)) - smt_assert_consequent(get_constr_expr(constr_assumes, step)) - - if step == num_steps: - smt_assert("(not (and (|%s_a| s%d) %s))" % (topmod, step, get_constr_expr(constr_asserts, step))) - - else: - smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step, step+1)) - smt_assert("(|%s_a| s%d)" % (topmod, step)) - smt_assert(get_constr_expr(constr_asserts, step)) - - if step > num_steps-skip_steps: - print_msg("Skipping induction in step %d.." % (step)) - continue - - skip_counter += 1 - if skip_counter < step_size: - print_msg("Skipping induction in step %d.." % (step)) - continue - - skip_counter = 0 - print_msg("Trying induction in step %d.." % (step)) - - if smt_check_sat() == "sat": - if step == 0: - print_msg("Temporal induction failed!") - print_anyconsts(num_steps) - print_failed_asserts(num_steps) - write_trace(step, num_steps+1, '%') - - elif dumpall: - print_anyconsts(num_steps) - print_failed_asserts(num_steps) - write_trace(step, num_steps+1, "%d" % step) - - else: - print_msg("Temporal induction successful.") - retstatus = True - break - -elif covermode: - cover_expr, cover_desc = get_cover_list(topmod, "state") - cover_mask = "1" * len(cover_desc) - - if len(cover_expr) > 1: - cover_expr = "(concat %s)" % " ".join(cover_expr) - elif len(cover_expr) == 1: - cover_expr = cover_expr[0] - else: - cover_expr = "#b0" - - coveridx = 0 - smt.write("(define-fun covers_0 ((state |%s_s|)) (_ BitVec %d) %s)" % (topmod, len(cover_desc), cover_expr)) - - step = 0 - retstatus = False - found_failed_assert = False - - assert step_size == 1 - - while step < num_steps: - smt_state(step) - smt_assert_consequent("(|%s_u| s%d)" % (topmod, step)) - smt_assert_antecedent("(|%s_h| s%d)" % (topmod, step)) - smt_assert_consequent(get_constr_expr(constr_assumes, step)) - - if step == 0: - if noinit: - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step)) - else: - smt_assert_antecedent("(|%s_i| s0)" % (topmod)) - smt_assert_antecedent("(|%s_is| s0)" % (topmod)) - - else: - smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step)) - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step)) - - while "1" in cover_mask: - print_msg("Checking cover reachability in step %d.." % (step)) - smt_push() - smt_assert("(distinct (covers_%d s%d) #b%s)" % (coveridx, step, "0" * len(cover_desc))) - - if smt_check_sat() == "unsat": - smt_pop() - break - - if append_steps > 0: - for i in range(step+1, step+1+append_steps): - print_msg("Appending additional step %d." % i) - smt_state(i) - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, i)) - smt_assert_consequent("(|%s_u| s%d)" % (topmod, i)) - smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i)) - smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i)) - smt_assert_consequent(get_constr_expr(constr_assumes, i)) - print_msg("Re-solving with appended steps..") - if smt_check_sat() == "unsat": - print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) - found_failed_assert = True - retstatus = False - break - - reached_covers = smt.bv2bin(smt.get("(covers_%d s%d)" % (coveridx, step))) - assert len(reached_covers) == len(cover_desc) - - new_cover_mask = [] - - for i in range(len(reached_covers)): - if reached_covers[i] == "0": - new_cover_mask.append(cover_mask[i]) - continue - - print_msg("Reached cover statement at %s in step %d." % (cover_desc[i], step)) - new_cover_mask.append("0") - - cover_mask = "".join(new_cover_mask) - - for i in range(step+1+append_steps): - if print_failed_asserts(i, extrainfo=" (step %d)" % i): - found_failed_assert = True - - write_trace(0, step+1+append_steps, "%d" % coveridx) - - if found_failed_assert: - break - - coveridx += 1 - smt_pop() - smt.write("(define-fun covers_%d ((state |%s_s|)) (_ BitVec %d) (bvand (covers_%d state) #b%s))" % (coveridx, topmod, len(cover_desc), coveridx-1, cover_mask)) - - if found_failed_assert: - break - - if "1" not in cover_mask: - retstatus = True - break - - step += 1 - - if "1" in cover_mask: - for i in range(len(cover_mask)): - if cover_mask[i] == "1": - print_msg("Unreached cover statement at %s." % cover_desc[i]) - -else: # not tempind, covermode - step = 0 - retstatus = True - while step < num_steps: - smt_state(step) - smt_assert_consequent("(|%s_u| s%d)" % (topmod, step)) - smt_assert_antecedent("(|%s_h| s%d)" % (topmod, step)) - smt_assert_consequent(get_constr_expr(constr_assumes, step)) - - if step == 0: - if noinit: - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step)) - else: - smt_assert_antecedent("(|%s_i| s0)" % (topmod)) - smt_assert_antecedent("(|%s_is| s0)" % (topmod)) - - else: - smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step)) - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step)) - - if step < skip_steps: - if assume_skipped is not None and step >= assume_skipped: - print_msg("Skipping step %d (and assuming pass).." % (step)) - smt_assert("(|%s_a| s%d)" % (topmod, step)) - smt_assert(get_constr_expr(constr_asserts, step)) - else: - print_msg("Skipping step %d.." % (step)) - step += 1 - continue - - last_check_step = step - for i in range(1, step_size): - if step+i < num_steps: - smt_state(step+i) - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step+i)) - smt_assert_consequent("(|%s_u| s%d)" % (topmod, step+i)) - smt_assert_antecedent("(|%s_h| s%d)" % (topmod, step+i)) - smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step+i-1, step+i)) - smt_assert_consequent(get_constr_expr(constr_assumes, step+i)) - last_check_step = step+i - - if not gentrace: - if presat: - if last_check_step == step: - print_msg("Checking assumptions in step %d.." % (step)) - else: - print_msg("Checking assumptions in steps %d to %d.." % (step, last_check_step)) - - if smt_check_sat() == "unsat": - print("%s Warmup failed!" % smt.timestamp()) - retstatus = False - break - - if not final_only: - if last_check_step == step: - print_msg("Checking assertions in step %d.." % (step)) - else: - print_msg("Checking assertions in steps %d to %d.." % (step, last_check_step)) - smt_push() - - smt_assert("(not (and %s))" % " ".join(["(|%s_a| s%d)" % (topmod, i) for i in range(step, last_check_step+1)] + - [get_constr_expr(constr_asserts, i) for i in range(step, last_check_step+1)])) - - if smt_check_sat() == "sat": - print("%s BMC failed!" % smt.timestamp()) - if append_steps > 0: - for i in range(last_check_step+1, last_check_step+1+append_steps): - print_msg("Appending additional step %d." % i) - smt_state(i) - smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, i)) - smt_assert_consequent("(|%s_u| s%d)" % (topmod, i)) - smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i)) - smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i)) - smt_assert_consequent(get_constr_expr(constr_assumes, i)) - print_msg("Re-solving with appended steps..") - if smt_check_sat() == "unsat": - print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) - retstatus = False - break - print_anyconsts(step) - for i in range(step, last_check_step+1): - print_failed_asserts(i) - write_trace(0, last_check_step+1+append_steps, '%') - retstatus = False - break - - smt_pop() - - if (constr_final_start is not None) or (last_check_step+1 != num_steps): - for i in range(step, last_check_step+1): - smt_assert("(|%s_a| s%d)" % (topmod, i)) - smt_assert(get_constr_expr(constr_asserts, i)) - - if constr_final_start is not None: - for i in range(step, last_check_step+1): - if i < constr_final_start: - continue - - print_msg("Checking final constraints in step %d.." % (i)) - smt_push() - - smt_assert_consequent(get_constr_expr(constr_assumes, i, final=True)) - smt_assert("(not %s)" % get_constr_expr(constr_asserts, i, final=True)) - - if smt_check_sat() == "sat": - print("%s BMC failed!" % smt.timestamp()) - print_anyconsts(i) - print_failed_asserts(i, final=True) - write_trace(0, i+1, '%') - retstatus = False - break - - smt_pop() - if not retstatus: - break - - else: # gentrace - for i in range(step, last_check_step+1): - smt_assert("(|%s_a| s%d)" % (topmod, i)) - smt_assert(get_constr_expr(constr_asserts, i)) - - print_msg("Solving for step %d.." % (last_check_step)) - if smt_check_sat() != "sat": - print("%s No solution found!" % smt.timestamp()) - retstatus = False - break - - elif dumpall: - print_anyconsts(0) - write_trace(0, last_check_step+1, "%d" % step) - - step += step_size - - if gentrace and retstatus: - print_anyconsts(0) - write_trace(0, num_steps, '%') - - -smt.write("(exit)") -smt.wait() - -print_msg("Status: %s" % ("PASSED" if retstatus else "FAILED (!)")) -sys.exit(0 if retstatus else 1) diff --git a/yosys/backends/smt2/smtio.py b/yosys/backends/smt2/smtio.py deleted file mode 100644 index ae7968a1b..000000000 --- a/yosys/backends/smt2/smtio.py +++ /dev/null @@ -1,1081 +0,0 @@ -# -# yosys -- Yosys Open SYnthesis Suite -# -# Copyright (C) 2012 Clifford Wolf -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# - -import sys, re, os, signal -import subprocess -if os.name == "posix": - import resource -from copy import deepcopy -from select import select -from time import time -from queue import Queue, Empty -from threading import Thread - - -# This is needed so that the recursive SMT2 S-expression parser -# does not run out of stack frames when parsing large expressions -if os.name == "posix": - smtio_reclimit = 64 * 1024 - if sys.getrecursionlimit() < smtio_reclimit: - sys.setrecursionlimit(smtio_reclimit) - - current_rlimit_stack = resource.getrlimit(resource.RLIMIT_STACK) - if current_rlimit_stack[0] != resource.RLIM_INFINITY: - smtio_stacksize = 128 * 1024 * 1024 - if os.uname().sysname == "Darwin": - # MacOS has rather conservative stack limits - smtio_stacksize = 16 * 1024 * 1024 - if current_rlimit_stack[1] != resource.RLIM_INFINITY: - smtio_stacksize = min(smtio_stacksize, current_rlimit_stack[1]) - if current_rlimit_stack[0] < smtio_stacksize: - resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1])) - - -# currently running solvers (so we can kill them) -running_solvers = dict() -forced_shutdown = False -solvers_index = 0 - -def force_shutdown(signum, frame): - global forced_shutdown - if not forced_shutdown: - forced_shutdown = True - if signum is not None: - print("<%s>" % signal.Signals(signum).name) - for p in running_solvers.values(): - # os.killpg(os.getpgid(p.pid), signal.SIGTERM) - os.kill(p.pid, signal.SIGTERM) - sys.exit(1) - -if os.name == "posix": - signal.signal(signal.SIGHUP, force_shutdown) -signal.signal(signal.SIGINT, force_shutdown) -signal.signal(signal.SIGTERM, force_shutdown) - -def except_hook(exctype, value, traceback): - if not forced_shutdown: - sys.__excepthook__(exctype, value, traceback) - force_shutdown(None, None) - -sys.excepthook = except_hook - - -hex_dict = { - "0": "0000", "1": "0001", "2": "0010", "3": "0011", - "4": "0100", "5": "0101", "6": "0110", "7": "0111", - "8": "1000", "9": "1001", "A": "1010", "B": "1011", - "C": "1100", "D": "1101", "E": "1110", "F": "1111", - "a": "1010", "b": "1011", "c": "1100", "d": "1101", - "e": "1110", "f": "1111" -} - - -class SmtModInfo: - def __init__(self): - self.inputs = set() - self.outputs = set() - self.registers = set() - self.memories = dict() - self.wires = set() - self.wsize = dict() - self.clocks = dict() - self.cells = dict() - self.asserts = dict() - self.covers = dict() - self.anyconsts = dict() - self.anyseqs = dict() - self.allconsts = dict() - self.allseqs = dict() - self.asize = dict() - - -class SmtIo: - def __init__(self, opts=None): - global solvers_index - - self.logic = None - self.logic_qf = True - self.logic_ax = True - self.logic_uf = True - self.logic_bv = True - self.logic_dt = False - self.forall = False - self.produce_models = True - self.smt2cache = [list()] - self.p = None - self.p_index = solvers_index - solvers_index += 1 - - if opts is not None: - self.logic = opts.logic - self.solver = opts.solver - self.solver_opts = opts.solver_opts - self.debug_print = opts.debug_print - self.debug_file = opts.debug_file - self.dummy_file = opts.dummy_file - self.timeinfo = opts.timeinfo - self.unroll = opts.unroll - self.noincr = opts.noincr - self.info_stmts = opts.info_stmts - self.nocomments = opts.nocomments - - else: - self.solver = "yices" - self.solver_opts = list() - self.debug_print = False - self.debug_file = None - self.dummy_file = None - self.timeinfo = os.name != "nt" - self.unroll = False - self.noincr = False - self.info_stmts = list() - self.nocomments = False - - self.start_time = time() - - self.modinfo = dict() - self.curmod = None - self.topmod = None - self.setup_done = False - - def __del__(self): - if self.p is not None and not forced_shutdown: - os.killpg(os.getpgid(self.p.pid), signal.SIGTERM) - if running_solvers is not None: - del running_solvers[self.p_index] - - def setup(self): - assert not self.setup_done - - if self.forall: - self.unroll = False - - if self.solver == "yices": - if self.noincr: - self.popen_vargs = ['yices-smt2'] + self.solver_opts - else: - self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts - - if self.solver == "z3": - self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts - - if self.solver == "cvc4": - if self.noincr: - self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts - else: - self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts - - if self.solver == "mathsat": - self.popen_vargs = ['mathsat'] + self.solver_opts - - if self.solver == "boolector": - if self.noincr: - self.popen_vargs = ['boolector', '--smt2'] + self.solver_opts - else: - self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts - self.unroll = True - - if self.solver == "abc": - if len(self.solver_opts) > 0: - self.popen_vargs = ['yosys-abc', '-S', '; '.join(self.solver_opts)] - else: - self.popen_vargs = ['yosys-abc', '-S', '%blast; &sweep -C 5000; &syn4; &cec -s -m -C 2000'] - self.logic_ax = False - self.unroll = True - self.noincr = True - - if self.solver == "dummy": - assert self.dummy_file is not None - self.dummy_fd = open(self.dummy_file, "r") - else: - if self.dummy_file is not None: - self.dummy_fd = open(self.dummy_file, "w") - if not self.noincr: - self.p_open() - - if self.unroll: - assert not self.forall - self.logic_uf = False - self.unroll_idcnt = 0 - self.unroll_buffer = "" - self.unroll_sorts = set() - self.unroll_objs = set() - self.unroll_decls = dict() - self.unroll_cache = dict() - self.unroll_stack = list() - - if self.logic is None: - self.logic = "" - if self.logic_qf: self.logic += "QF_" - if self.logic_ax: self.logic += "A" - if self.logic_uf: self.logic += "UF" - if self.logic_bv: self.logic += "BV" - if self.logic_dt: self.logic = "ALL" - - self.setup_done = True - - for stmt in self.info_stmts: - self.write(stmt) - - if self.produce_models: - self.write("(set-option :produce-models true)") - - self.write("(set-logic %s)" % self.logic) - - def timestamp(self): - secs = int(time() - self.start_time) - return "## %3d:%02d:%02d " % (secs // (60*60), (secs // 60) % 60, secs % 60) - - def replace_in_stmt(self, stmt, pat, repl): - if stmt == pat: - return repl - - if isinstance(stmt, list): - return [self.replace_in_stmt(s, pat, repl) for s in stmt] - - return stmt - - def unroll_stmt(self, stmt): - if not isinstance(stmt, list): - return stmt - - stmt = [self.unroll_stmt(s) for s in stmt] - - if len(stmt) >= 2 and not isinstance(stmt[0], list) and stmt[0] in self.unroll_decls: - assert stmt[1] in self.unroll_objs - - key = tuple(stmt) - if key not in self.unroll_cache: - decl = deepcopy(self.unroll_decls[key[0]]) - - self.unroll_cache[key] = "|UNROLL#%d|" % self.unroll_idcnt - decl[1] = self.unroll_cache[key] - self.unroll_idcnt += 1 - - if decl[0] == "declare-fun": - if isinstance(decl[3], list) or decl[3] not in self.unroll_sorts: - self.unroll_objs.add(decl[1]) - decl[2] = list() - else: - self.unroll_objs.add(decl[1]) - decl = list() - - elif decl[0] == "define-fun": - arg_index = 1 - for arg_name, arg_sort in decl[2]: - decl[4] = self.replace_in_stmt(decl[4], arg_name, key[arg_index]) - arg_index += 1 - decl[2] = list() - - if len(decl) > 0: - decl = self.unroll_stmt(decl) - self.write(self.unparse(decl), unroll=False) - - return self.unroll_cache[key] - - return stmt - - def p_thread_main(self): - while True: - data = self.p.stdout.readline().decode("ascii") - if data == "": break - self.p_queue.put(data) - self.p_queue.put("") - self.p_running = False - - def p_open(self): - assert self.p is None - self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - running_solvers[self.p_index] = self.p - self.p_running = True - self.p_next = None - self.p_queue = Queue() - self.p_thread = Thread(target=self.p_thread_main) - self.p_thread.start() - - def p_write(self, data, flush): - assert self.p is not None - self.p.stdin.write(bytes(data, "ascii")) - if flush: self.p.stdin.flush() - - def p_read(self): - assert self.p is not None - if self.p_next is not None: - data = self.p_next - self.p_next = None - return data - if not self.p_running: - return "" - return self.p_queue.get() - - def p_poll(self, timeout=0.1): - assert self.p is not None - assert self.p_running - if self.p_next is not None: - return False - try: - self.p_next = self.p_queue.get(True, timeout) - return False - except Empty: - return True - - def p_close(self): - assert self.p is not None - self.p.stdin.close() - self.p_thread.join() - assert not self.p_running - del running_solvers[self.p_index] - self.p = None - self.p_next = None - self.p_queue = None - self.p_thread = None - - def write(self, stmt, unroll=True): - if stmt.startswith(";"): - self.info(stmt) - if not self.setup_done: - self.info_stmts.append(stmt) - return - elif not self.setup_done: - self.setup() - - stmt = stmt.strip() - - if self.nocomments or self.unroll: - stmt = re.sub(r" *;.*", "", stmt) - if stmt == "": return - - if unroll and self.unroll: - stmt = self.unroll_buffer + stmt - self.unroll_buffer = "" - - s = re.sub(r"\|[^|]*\|", "", stmt) - if s.count("(") != s.count(")"): - self.unroll_buffer = stmt + " " - return - - s = self.parse(stmt) - - if self.debug_print: - print("-> %s" % s) - - if len(s) == 3 and s[0] == "declare-sort" and s[2] == "0": - self.unroll_sorts.add(s[1]) - return - - elif len(s) == 4 and s[0] == "declare-fun" and s[2] == [] and s[3] in self.unroll_sorts: - self.unroll_objs.add(s[1]) - return - - elif len(s) >= 4 and s[0] == "declare-fun": - for arg_sort in s[2]: - if arg_sort in self.unroll_sorts: - self.unroll_decls[s[1]] = s - return - - elif len(s) >= 4 and s[0] == "define-fun": - for arg_name, arg_sort in s[2]: - if arg_sort in self.unroll_sorts: - self.unroll_decls[s[1]] = s - return - - stmt = self.unparse(self.unroll_stmt(s)) - - if stmt == "(push 1)": - self.unroll_stack.append(( - deepcopy(self.unroll_sorts), - deepcopy(self.unroll_objs), - deepcopy(self.unroll_decls), - deepcopy(self.unroll_cache), - )) - - if stmt == "(pop 1)": - self.unroll_sorts, self.unroll_objs, self.unroll_decls, self.unroll_cache = self.unroll_stack.pop() - - if self.debug_print: - print("> %s" % stmt) - - if self.debug_file: - print(stmt, file=self.debug_file) - self.debug_file.flush() - - if self.solver != "dummy": - if self.noincr: - if self.p is not None and not stmt.startswith("(get-"): - self.p_close() - if stmt == "(push 1)": - self.smt2cache.append(list()) - elif stmt == "(pop 1)": - self.smt2cache.pop() - else: - if self.p is not None: - self.p_write(stmt + "\n", True) - self.smt2cache[-1].append(stmt) - else: - self.p_write(stmt + "\n", True) - - def info(self, stmt): - if not stmt.startswith("; yosys-smt2-"): - return - - fields = stmt.split() - - if fields[1] == "yosys-smt2-nomem": - if self.logic is None: - self.logic_ax = False - - if fields[1] == "yosys-smt2-nobv": - if self.logic is None: - self.logic_bv = False - - if fields[1] == "yosys-smt2-stdt": - if self.logic is None: - self.logic_dt = True - - if fields[1] == "yosys-smt2-forall": - if self.logic is None: - self.logic_qf = False - self.forall = True - - if fields[1] == "yosys-smt2-module": - self.curmod = fields[2] - self.modinfo[self.curmod] = SmtModInfo() - - if fields[1] == "yosys-smt2-cell": - self.modinfo[self.curmod].cells[fields[3]] = fields[2] - - if fields[1] == "yosys-smt2-topmod": - self.topmod = fields[2] - - if fields[1] == "yosys-smt2-input": - self.modinfo[self.curmod].inputs.add(fields[2]) - self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3]) - - if fields[1] == "yosys-smt2-output": - self.modinfo[self.curmod].outputs.add(fields[2]) - self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3]) - - if fields[1] == "yosys-smt2-register": - self.modinfo[self.curmod].registers.add(fields[2]) - self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3]) - - if fields[1] == "yosys-smt2-memory": - self.modinfo[self.curmod].memories[fields[2]] = (int(fields[3]), int(fields[4]), int(fields[5]), int(fields[6]), fields[7] == "async") - - if fields[1] == "yosys-smt2-wire": - self.modinfo[self.curmod].wires.add(fields[2]) - self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3]) - - if fields[1] == "yosys-smt2-clock": - for edge in fields[3:]: - if fields[2] not in self.modinfo[self.curmod].clocks: - self.modinfo[self.curmod].clocks[fields[2]] = edge - elif self.modinfo[self.curmod].clocks[fields[2]] != edge: - self.modinfo[self.curmod].clocks[fields[2]] = "event" - - if fields[1] == "yosys-smt2-assert": - self.modinfo[self.curmod].asserts["%s_a %s" % (self.curmod, fields[2])] = fields[3] - - if fields[1] == "yosys-smt2-cover": - self.modinfo[self.curmod].covers["%s_c %s" % (self.curmod, fields[2])] = fields[3] - - if fields[1] == "yosys-smt2-anyconst": - self.modinfo[self.curmod].anyconsts[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5]) - self.modinfo[self.curmod].asize[fields[2]] = int(fields[3]) - - if fields[1] == "yosys-smt2-anyseq": - self.modinfo[self.curmod].anyseqs[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5]) - self.modinfo[self.curmod].asize[fields[2]] = int(fields[3]) - - if fields[1] == "yosys-smt2-allconst": - self.modinfo[self.curmod].allconsts[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5]) - self.modinfo[self.curmod].asize[fields[2]] = int(fields[3]) - - if fields[1] == "yosys-smt2-allseq": - self.modinfo[self.curmod].allseqs[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5]) - self.modinfo[self.curmod].asize[fields[2]] = int(fields[3]) - - def hiernets(self, top, regs_only=False): - def hiernets_worker(nets, mod, cursor): - for netname in sorted(self.modinfo[mod].wsize.keys()): - if not regs_only or netname in self.modinfo[mod].registers: - nets.append(cursor + [netname]) - for cellname, celltype in sorted(self.modinfo[mod].cells.items()): - hiernets_worker(nets, celltype, cursor + [cellname]) - - nets = list() - hiernets_worker(nets, top, []) - return nets - - def hieranyconsts(self, top): - def worker(results, mod, cursor): - for name, value in sorted(self.modinfo[mod].anyconsts.items()): - width = self.modinfo[mod].asize[name] - results.append((cursor, name, value[0], value[1], width)) - for cellname, celltype in sorted(self.modinfo[mod].cells.items()): - worker(results, celltype, cursor + [cellname]) - - results = list() - worker(results, top, []) - return results - - def hieranyseqs(self, top): - def worker(results, mod, cursor): - for name, value in sorted(self.modinfo[mod].anyseqs.items()): - width = self.modinfo[mod].asize[name] - results.append((cursor, name, value[0], value[1], width)) - for cellname, celltype in sorted(self.modinfo[mod].cells.items()): - worker(results, celltype, cursor + [cellname]) - - results = list() - worker(results, top, []) - return results - - def hierallconsts(self, top): - def worker(results, mod, cursor): - for name, value in sorted(self.modinfo[mod].allconsts.items()): - width = self.modinfo[mod].asize[name] - results.append((cursor, name, value[0], value[1], width)) - for cellname, celltype in sorted(self.modinfo[mod].cells.items()): - worker(results, celltype, cursor + [cellname]) - - results = list() - worker(results, top, []) - return results - - def hierallseqs(self, top): - def worker(results, mod, cursor): - for name, value in sorted(self.modinfo[mod].allseqs.items()): - width = self.modinfo[mod].asize[name] - results.append((cursor, name, value[0], value[1], width)) - for cellname, celltype in sorted(self.modinfo[mod].cells.items()): - worker(results, celltype, cursor + [cellname]) - - results = list() - worker(results, top, []) - return results - - def hiermems(self, top): - def hiermems_worker(mems, mod, cursor): - for memname in sorted(self.modinfo[mod].memories.keys()): - mems.append(cursor + [memname]) - for cellname, celltype in sorted(self.modinfo[mod].cells.items()): - hiermems_worker(mems, celltype, cursor + [cellname]) - - mems = list() - hiermems_worker(mems, top, []) - return mems - - def read(self): - stmt = [] - count_brackets = 0 - - while True: - if self.solver == "dummy": - line = self.dummy_fd.readline().strip() - else: - line = self.p_read().strip() - if self.dummy_file is not None: - self.dummy_fd.write(line + "\n") - - count_brackets += line.count("(") - count_brackets -= line.count(")") - stmt.append(line) - - if self.debug_print: - print("< %s" % line) - if count_brackets == 0: - break - if self.solver != "dummy" and self.p.poll(): - print("%s Solver terminated unexpectedly: %s" % (self.timestamp(), "".join(stmt)), flush=True) - sys.exit(1) - - stmt = "".join(stmt) - if stmt.startswith("(error"): - print("%s Solver Error: %s" % (self.timestamp(), stmt), flush=True) - if self.solver != "dummy": - self.p_close() - sys.exit(1) - - return stmt - - def check_sat(self): - if self.debug_print: - print("> (check-sat)") - if self.debug_file and not self.nocomments: - print("; running check-sat..", file=self.debug_file) - self.debug_file.flush() - - if self.solver != "dummy": - if self.noincr: - if self.p is not None: - self.p_close() - self.p_open() - for cache_ctx in self.smt2cache: - for cache_stmt in cache_ctx: - self.p_write(cache_stmt + "\n", False) - - self.p_write("(check-sat)\n", True) - - if self.timeinfo: - i = 0 - s = "/-\|" - - count = 0 - num_bs = 0 - while self.p_poll(): - count += 1 - - if count < 25: - continue - - if count % 10 == 0 or count == 25: - secs = count // 10 - - if secs < 60: - m = "(%d seconds)" % secs - elif secs < 60*60: - m = "(%d seconds -- %d:%02d)" % (secs, secs // 60, secs % 60) - else: - m = "(%d seconds -- %d:%02d:%02d)" % (secs, secs // (60*60), (secs // 60) % 60, secs % 60) - - print("%s %s %c" % ("\b \b" * num_bs, m, s[i]), end="", file=sys.stderr) - num_bs = len(m) + 3 - - else: - print("\b" + s[i], end="", file=sys.stderr) - - sys.stderr.flush() - i = (i + 1) % len(s) - - if num_bs != 0: - print("\b \b" * num_bs, end="", file=sys.stderr) - sys.stderr.flush() - - else: - count = 0 - while self.p_poll(60): - count += 1 - msg = None - - if count == 1: - msg = "1 minute" - - elif count in [5, 10, 15, 30]: - msg = "%d minutes" % count - - elif count == 60: - msg = "1 hour" - - elif count % 60 == 0: - msg = "%d hours" % (count // 60) - - if msg is not None: - print("%s waiting for solver (%s)" % (self.timestamp(), msg), flush=True) - - result = self.read() - - if self.debug_file: - print("(set-info :status %s)" % result, file=self.debug_file) - print("(check-sat)", file=self.debug_file) - self.debug_file.flush() - - if result not in ["sat", "unsat"]: - if result == "": - print("%s Unexpected EOF response from solver." % (self.timestamp()), flush=True) - else: - print("%s Unexpected response from solver: %s" % (self.timestamp(), result), flush=True) - if self.solver != "dummy": - self.p_close() - sys.exit(1) - - return result - - def parse(self, stmt): - def worker(stmt): - if stmt[0] == '(': - expr = [] - cursor = 1 - while stmt[cursor] != ')': - el, le = worker(stmt[cursor:]) - expr.append(el) - cursor += le - return expr, cursor+1 - - if stmt[0] == '|': - expr = "|" - cursor = 1 - while stmt[cursor] != '|': - expr += stmt[cursor] - cursor += 1 - expr += "|" - return expr, cursor+1 - - if stmt[0] in [" ", "\t", "\r", "\n"]: - el, le = worker(stmt[1:]) - return el, le+1 - - expr = "" - cursor = 0 - while stmt[cursor] not in ["(", ")", "|", " ", "\t", "\r", "\n"]: - expr += stmt[cursor] - cursor += 1 - return expr, cursor - return worker(stmt)[0] - - def unparse(self, stmt): - if isinstance(stmt, list): - return "(" + " ".join([self.unparse(s) for s in stmt]) + ")" - return stmt - - def bv2hex(self, v): - h = "" - v = self.bv2bin(v) - while len(v) > 0: - d = 0 - if len(v) > 0 and v[-1] == "1": d += 1 - if len(v) > 1 and v[-2] == "1": d += 2 - if len(v) > 2 and v[-3] == "1": d += 4 - if len(v) > 3 and v[-4] == "1": d += 8 - h = hex(d)[2:] + h - if len(v) < 4: break - v = v[:-4] - return h - - def bv2bin(self, v): - if type(v) is list and len(v) == 3 and v[0] == "_" and v[1].startswith("bv"): - x, n = int(v[1][2:]), int(v[2]) - return "".join("1" if (x & (1 << i)) else "0" for i in range(n-1, -1, -1)) - if v == "true": return "1" - if v == "false": return "0" - if v.startswith("#b"): - return v[2:] - if v.startswith("#x"): - return "".join(hex_dict.get(x) for x in v[2:]) - assert False - - def bv2int(self, v): - return int(self.bv2bin(v), 2) - - def get(self, expr): - self.write("(get-value (%s))" % (expr)) - return self.parse(self.read())[0][1] - - def get_list(self, expr_list): - if len(expr_list) == 0: - return [] - self.write("(get-value (%s))" % " ".join(expr_list)) - return [n[1] for n in self.parse(self.read())] - - def get_path(self, mod, path): - assert mod in self.modinfo - path = path.replace("\\", "/").split(".") - - for i in range(len(path)-1): - first = ".".join(path[0:i+1]) - second = ".".join(path[i+1:]) - - if first in self.modinfo[mod].cells: - nextmod = self.modinfo[mod].cells[first] - return [first] + self.get_path(nextmod, second) - - return [".".join(path)] - - def net_expr(self, mod, base, path): - if len(path) == 0: - return base - - if len(path) == 1: - assert mod in self.modinfo - if path[0] == "": - return base - if path[0] in self.modinfo[mod].cells: - return "(|%s_h %s| %s)" % (mod, path[0], base) - if path[0] in self.modinfo[mod].wsize: - return "(|%s_n %s| %s)" % (mod, path[0], base) - if path[0] in self.modinfo[mod].memories: - return "(|%s_m %s| %s)" % (mod, path[0], base) - assert 0 - - assert mod in self.modinfo - assert path[0] in self.modinfo[mod].cells - - nextmod = self.modinfo[mod].cells[path[0]] - nextbase = "(|%s_h %s| %s)" % (mod, path[0], base) - return self.net_expr(nextmod, nextbase, path[1:]) - - def net_width(self, mod, net_path): - for i in range(len(net_path)-1): - assert mod in self.modinfo - assert net_path[i] in self.modinfo[mod].cells - mod = self.modinfo[mod].cells[net_path[i]] - - assert mod in self.modinfo - assert net_path[-1] in self.modinfo[mod].wsize - return self.modinfo[mod].wsize[net_path[-1]] - - def net_clock(self, mod, net_path): - for i in range(len(net_path)-1): - assert mod in self.modinfo - assert net_path[i] in self.modinfo[mod].cells - mod = self.modinfo[mod].cells[net_path[i]] - - assert mod in self.modinfo - if net_path[-1] not in self.modinfo[mod].clocks: - return None - return self.modinfo[mod].clocks[net_path[-1]] - - def net_exists(self, mod, net_path): - for i in range(len(net_path)-1): - if mod not in self.modinfo: return False - if net_path[i] not in self.modinfo[mod].cells: return False - mod = self.modinfo[mod].cells[net_path[i]] - - if mod not in self.modinfo: return False - if net_path[-1] not in self.modinfo[mod].wsize: return False - return True - - def mem_exists(self, mod, mem_path): - for i in range(len(mem_path)-1): - if mod not in self.modinfo: return False - if mem_path[i] not in self.modinfo[mod].cells: return False - mod = self.modinfo[mod].cells[mem_path[i]] - - if mod not in self.modinfo: return False - if mem_path[-1] not in self.modinfo[mod].memories: return False - return True - - def mem_expr(self, mod, base, path, port=None, infomode=False): - if len(path) == 1: - assert mod in self.modinfo - assert path[0] in self.modinfo[mod].memories - if infomode: - return self.modinfo[mod].memories[path[0]] - return "(|%s_m%s %s| %s)" % (mod, "" if port is None else ":%s" % port, path[0], base) - - assert mod in self.modinfo - assert path[0] in self.modinfo[mod].cells - - nextmod = self.modinfo[mod].cells[path[0]] - nextbase = "(|%s_h %s| %s)" % (mod, path[0], base) - return self.mem_expr(nextmod, nextbase, path[1:], port=port, infomode=infomode) - - def mem_info(self, mod, path): - return self.mem_expr(mod, "", path, infomode=True) - - def get_net(self, mod_name, net_path, state_name): - return self.get(self.net_expr(mod_name, state_name, net_path)) - - def get_net_list(self, mod_name, net_path_list, state_name): - return self.get_list([self.net_expr(mod_name, state_name, n) for n in net_path_list]) - - def get_net_hex(self, mod_name, net_path, state_name): - return self.bv2hex(self.get_net(mod_name, net_path, state_name)) - - def get_net_hex_list(self, mod_name, net_path_list, state_name): - return [self.bv2hex(v) for v in self.get_net_list(mod_name, net_path_list, state_name)] - - def get_net_bin(self, mod_name, net_path, state_name): - return self.bv2bin(self.get_net(mod_name, net_path, state_name)) - - def get_net_bin_list(self, mod_name, net_path_list, state_name): - return [self.bv2bin(v) for v in self.get_net_list(mod_name, net_path_list, state_name)] - - def wait(self): - if self.p is not None: - self.p.wait() - self.p_close() - - -class SmtOpts: - def __init__(self): - self.shortopts = "s:S:v" - self.longopts = ["unroll", "noincr", "noprogress", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"] - self.solver = "yices" - self.solver_opts = list() - self.debug_print = False - self.debug_file = None - self.dummy_file = None - self.unroll = False - self.noincr = False - self.timeinfo = os.name != "nt" - self.logic = None - self.info_stmts = list() - self.nocomments = False - - def handle(self, o, a): - if o == "-s": - self.solver = a - elif o == "-S": - self.solver_opts.append(a) - elif o == "-v": - self.debug_print = True - elif o == "--unroll": - self.unroll = True - elif o == "--noincr": - self.noincr = True - elif o == "--noprogress": - self.timeinfo = False - elif o == "--dump-smt2": - self.debug_file = open(a, "w") - elif o == "--logic": - self.logic = a - elif o == "--dummy": - self.dummy_file = a - elif o == "--info": - self.info_stmts.append(a) - elif o == "--nocomments": - self.nocomments = True - else: - return False - return True - - def helpmsg(self): - return """ - -s - set SMT solver: z3, yices, boolector, cvc4, mathsat, dummy - default: yices - - -S - pass as command line argument to the solver - - --logic - use the specified SMT2 logic (e.g. QF_AUFBV) - - --dummy - if solver is "dummy", read solver output from that file - otherwise: write solver output to that file - - -v - enable debug output - - --unroll - unroll uninterpreted functions - - --noincr - don't use incremental solving, instead restart solver for - each (check-sat). This also avoids (push) and (pop). - - --noprogress - disable timer display during solving - (this option is set implicitly on Windows) - - --dump-smt2 - write smt2 statements to file - - --info - include the specified smt2 info statement in the smt2 output - - --nocomments - strip all comments from the generated smt2 code -""" - - -class MkVcd: - def __init__(self, f): - self.f = f - self.t = -1 - self.nets = dict() - self.clocks = dict() - - def add_net(self, path, width): - path = tuple(path) - assert self.t == -1 - key = "n%d" % len(self.nets) - self.nets[path] = (key, width) - - def add_clock(self, path, edge): - path = tuple(path) - assert self.t == -1 - key = "n%d" % len(self.nets) - self.nets[path] = (key, 1) - self.clocks[path] = (key, edge) - - def set_net(self, path, bits): - path = tuple(path) - assert self.t >= 0 - assert path in self.nets - if path not in self.clocks: - print("b%s %s" % (bits, self.nets[path][0]), file=self.f) - - def escape_name(self, name): - name = re.sub(r"\[([0-9a-zA-Z_]*[a-zA-Z_][0-9a-zA-Z_]*)\]", r"<\1>", name) - if re.match("[\[\]]", name) and name[0] != "\\": - name = "\\" + name - return name - - def set_time(self, t): - assert t >= self.t - if t != self.t: - if self.t == -1: - print("$version Generated by Yosys-SMTBMC $end", file=self.f) - print("$timescale 1ns $end", file=self.f) - print("$var integer 32 t smt_step $end", file=self.f) - print("$var event 1 ! smt_clock $end", file=self.f) - - scope = [] - for path in sorted(self.nets): - key, width = self.nets[path] - - uipath = list(path) - if "." in uipath[-1]: - uipath = uipath[0:-1] + uipath[-1].split(".") - for i in range(len(uipath)): - uipath[i] = re.sub(r"\[([^\]]*)\]", r"<\1>", uipath[i]) - - while uipath[:len(scope)] != scope: - print("$upscope $end", file=self.f) - scope = scope[:-1] - - while uipath[:-1] != scope: - scopename = uipath[len(scope)] - if scopename.startswith("$"): - scopename = "\\" + scopename - print("$scope module %s $end" % scopename, file=self.f) - scope.append(uipath[len(scope)]) - - if path in self.clocks and self.clocks[path][1] == "event": - print("$var event 1 %s %s $end" % (key, uipath[-1]), file=self.f) - else: - print("$var wire %d %s %s $end" % (width, key, uipath[-1]), file=self.f) - - for i in range(len(scope)): - print("$upscope $end", file=self.f) - - print("$enddefinitions $end", file=self.f) - - self.t = t - assert self.t >= 0 - - if self.t > 0: - print("#%d" % (10 * self.t - 5), file=self.f) - for path in sorted(self.clocks.keys()): - if self.clocks[path][1] == "posedge": - print("b0 %s" % self.nets[path][0], file=self.f) - elif self.clocks[path][1] == "negedge": - print("b1 %s" % self.nets[path][0], file=self.f) - - print("#%d" % (10 * self.t), file=self.f) - print("1!", file=self.f) - print("b%s t" % format(self.t, "032b"), file=self.f) - - for path in sorted(self.clocks.keys()): - if self.clocks[path][1] == "negedge": - print("b0 %s" % self.nets[path][0], file=self.f) - else: - print("b1 %s" % self.nets[path][0], file=self.f) diff --git a/yosys/backends/smt2/test_cells.sh b/yosys/backends/smt2/test_cells.sh deleted file mode 100644 index 34adb7af3..000000000 --- a/yosys/backends/smt2/test_cells.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -set -ex - -rm -rf test_cells -mkdir test_cells -cd test_cells - -../../../yosys -p 'test_cell -muxdiv -w test all /$alu /$macc /$fa /$lcu /$lut /$shift /$shiftx' - -cat > miter.tpl <<- EOT -; #model# (set-option :produce-models true) -(set-logic QF_UFBV) -%% -(declare-fun s () miter_s) -(assert (|miter_n trigger| s)) -(check-sat) -; #model# (get-value ((|miter_n in_A| s) (|miter_n in_B| s) (|miter_n gold_Y| s) (|miter_n gate_Y| s) (|miter_n trigger| s))) -EOT - -for x in $(set +x; ls test_*.il | sort -R); do - x=${x%.il} - cat > $x.ys <<- EOT - read_ilang $x.il - copy gold gate - - cd gate - techmap; opt; abc;; - cd .. - - miter -equiv -flatten -make_outputs gold gate miter - hierarchy -check -top miter - - dump - write_smt2 -bv -tpl miter.tpl $x.smt2 - EOT - ../../../yosys -q $x.ys - if ! cvc4 $x.smt2 > $x.result; then - cat $x.result - exit 1 - fi - if ! grep unsat $x.result; then - echo "Proof failed! Extracting model..." - sed -i 's/^; #model# //' $x.smt2 - cvc4 $x.smt2 - exit 1 - fi -done - -set +x -echo "" -echo " All tests passed." -echo "" -exit 0 - diff --git a/yosys/backends/smv/Makefile.inc b/yosys/backends/smv/Makefile.inc deleted file mode 100644 index 66c192d80..000000000 --- a/yosys/backends/smv/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/smv/smv.o - diff --git a/yosys/backends/smv/smv.cc b/yosys/backends/smv/smv.cc deleted file mode 100644 index d75456c1b..000000000 --- a/yosys/backends/smv/smv.cc +++ /dev/null @@ -1,807 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct SmvWorker -{ - CellTypes ct; - SigMap sigmap; - RTLIL::Module *module; - std::ostream &f; - bool verbose; - - int idcounter; - dict idcache; - pool used_names; - vector strbuf; - - pool partial_assignment_wires; - dict> partial_assignment_bits; - vector inputvars, vars, definitions, assignments, invarspecs; - - const char *cid() - { - while (true) { - shared_str s(stringf("_%d", idcounter++)); - if (!used_names.count(s)) { - used_names.insert(s); - return s.c_str(); - } - } - } - - const char *cid(IdString id, bool precache = false) - { - if (!idcache.count(id)) - { - string name = stringf("_%s", id.c_str()); - - if (name.substr(0, 2) == "_\\") - name = "_" + name.substr(2); - - for (auto &c : name) { - if (c == '|' || c == '$' || c == '_') continue; - if (c >= 'a' && c <='z') continue; - if (c >= 'A' && c <='Z') continue; - if (c >= '0' && c <='9') continue; - if (precache) return nullptr; - c = '#'; - } - - if (name == "_main") - name = "main"; - - while (used_names.count(name)) - name += "_"; - - shared_str s(name); - used_names.insert(s); - idcache[id] = s; - } - - return idcache.at(id).c_str(); - } - - SmvWorker(RTLIL::Module *module, bool verbose, std::ostream &f) : - ct(module->design), sigmap(module), module(module), f(f), verbose(verbose), idcounter(0) - { - for (auto mod : module->design->modules()) - cid(mod->name, true); - - for (auto wire : module->wires()) - cid(wire->name, true); - - for (auto cell : module->cells()) { - cid(cell->name, true); - cid(cell->type, true); - for (auto &conn : cell->connections()) - cid(conn.first, true); - } - } - - const char *rvalue(SigSpec sig, int width = -1, bool is_signed = false) - { - string s; - int count_chunks = 0; - sigmap.apply(sig); - - for (int i = 0; i < GetSize(sig); i++) - if (partial_assignment_bits.count(sig[i])) - { - int width = 1; - const auto &bit_a = partial_assignment_bits.at(sig[i]); - - while (i+width < GetSize(sig)) - { - if (!partial_assignment_bits.count(sig[i+width])) - break; - - const auto &bit_b = partial_assignment_bits.at(sig[i+width]); - if (strcmp(bit_a.first, bit_b.first)) - break; - if (bit_a.second+width != bit_b.second) - break; - - width++; - } - - if (i+width < GetSize(sig)) - s = stringf("%s :: ", rvalue(sig.extract(i+width, GetSize(sig)-(width+i)))); - - s += stringf("%s[%d:%d]", bit_a.first, bit_a.second+width-1, bit_a.second); - - if (i > 0) - s += stringf(" :: %s", rvalue(sig.extract(0, i))); - - count_chunks = 3; - goto continue_with_resize; - } - - for (auto &c : sig.chunks()) { - count_chunks++; - if (!s.empty()) - s = " :: " + s; - if (c.wire) { - if (c.offset != 0 || c.width != c.wire->width) - s = stringf("%s[%d:%d]", cid(c.wire->name), c.offset+c.width-1, c.offset) + s; - else - s = cid(c.wire->name) + s; - } else { - string v = stringf("0ub%d_", c.width); - for (int i = c.width-1; i >= 0; i--) - v += c.data.at(i) == State::S1 ? '1' : '0'; - s = v + s; - } - } - - continue_with_resize:; - if (width >= 0) { - if (is_signed) { - if (GetSize(sig) > width) - s = stringf("signed(resize(%s, %d))", s.c_str(), width); - else - s = stringf("resize(signed(%s), %d)", s.c_str(), width); - } else - s = stringf("resize(%s, %d)", s.c_str(), width); - } else if (is_signed) - s = stringf("signed(%s)", s.c_str()); - else if (count_chunks > 1) - s = stringf("(%s)", s.c_str()); - - strbuf.push_back(s); - return strbuf.back().c_str(); - } - - const char *rvalue_u(SigSpec sig, int width = -1) - { - return rvalue(sig, width, false); - } - - const char *rvalue_s(SigSpec sig, int width = -1, bool is_signed = true) - { - return rvalue(sig, width, is_signed); - } - - const char *lvalue(SigSpec sig) - { - sigmap.apply(sig); - - if (sig.is_wire()) - return rvalue(sig); - - const char *temp_id = cid(); -// f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig)); - - int offset = 0; - for (auto bit : sig) { - log_assert(bit.wire != nullptr); - partial_assignment_wires.insert(bit.wire); - partial_assignment_bits[bit] = std::pair(temp_id, offset++); - } - - return temp_id; - } - - void run() - { - f << stringf("MODULE %s\n", cid(module->name)); - - for (auto wire : module->wires()) - { - if (SigSpec(wire) != sigmap(wire)) - partial_assignment_wires.insert(wire); - - if (wire->port_input) - inputvars.push_back(stringf("%s : unsigned word[%d]; -- %s", cid(wire->name), wire->width, log_id(wire))); - - if (wire->attributes.count("\\init")) - assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at("\\init")))); - } - - for (auto cell : module->cells()) - { - // FIXME: $slice, $concat, $mem - - if (cell->type.in("$assert")) - { - SigSpec sig_a = cell->getPort("\\A"); - SigSpec sig_en = cell->getPort("\\EN"); - - invarspecs.push_back(stringf("!bool(%s) | bool(%s);", rvalue(sig_en), rvalue(sig_a))); - - continue; - } - - if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) - { - SigSpec sig_a = cell->getPort("\\A"); - SigSpec sig_b = cell->getPort("\\B"); - - int width_y = GetSize(cell->getPort("\\Y")); - int shift_b_width = GetSize(sig_b); - int width_ay = max(GetSize(sig_a), width_y); - int width = width_ay; - - for (int i = 1, j = 0;; i <<= 1, j++) - if (width_ay < i) { - width = i-1; - shift_b_width = min(shift_b_width, j); - break; - } - - bool signed_a = cell->getParam("\\A_SIGNED").as_bool(); - bool signed_b = cell->getParam("\\B_SIGNED").as_bool(); - string op = cell->type.in("$shl", "$sshl") ? "<<" : ">>"; - string expr, expr_a; - - if (cell->type == "$sshr" && signed_a) - { - expr_a = rvalue_s(sig_a, width); - expr = stringf("resize(unsigned(%s %s %s), %d)", expr_a.c_str(), op.c_str(), rvalue(sig_b.extract(0, shift_b_width)), width_y); - if (shift_b_width < GetSize(sig_b)) - expr = stringf("%s != 0ud%d_0 ? (bool(%s) ? !0ud%d_0 : 0ud%d_0) : %s", - rvalue(sig_b.extract(shift_b_width, GetSize(sig_b) - shift_b_width)), GetSize(sig_b) - shift_b_width, - rvalue(sig_a[GetSize(sig_a)-1]), width_y, width_y, expr.c_str()); - } - else if (cell->type.in("$shift", "$shiftx") && signed_b) - { - expr_a = rvalue_u(sig_a, width); - - const char *b_shr = rvalue_u(sig_b); - const char *b_shl = cid(); - -// f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b)); - definitions.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b))); - - string expr_shl = stringf("resize(%s << %s[%d:0], %d)", expr_a.c_str(), b_shl, shift_b_width-1, width_y); - string expr_shr = stringf("resize(%s >> %s[%d:0], %d)", expr_a.c_str(), b_shr, shift_b_width-1, width_y); - - if (shift_b_width < GetSize(sig_b)) { - expr_shl = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", b_shl, GetSize(sig_b)-1, shift_b_width, - GetSize(sig_b)-shift_b_width, width_y, expr_shl.c_str()); - expr_shr = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", b_shr, GetSize(sig_b)-1, shift_b_width, - GetSize(sig_b)-shift_b_width, width_y, expr_shr.c_str()); - } - - expr = stringf("bool(%s) ? %s : %s", rvalue(sig_b[GetSize(sig_b)-1]), expr_shl.c_str(), expr_shr.c_str()); - } - else - { - if (cell->type.in("$shift", "$shiftx") || !signed_a) - expr_a = rvalue_u(sig_a, width); - else - expr_a = stringf("resize(unsigned(%s), %d)", rvalue_s(sig_a, width_ay), width); - - expr = stringf("resize(%s %s %s[%d:0], %d)", expr_a.c_str(), op.c_str(), rvalue_u(sig_b), shift_b_width-1, width_y); - if (shift_b_width < GetSize(sig_b)) - expr = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", rvalue_u(sig_b), GetSize(sig_b)-1, shift_b_width, - GetSize(sig_b)-shift_b_width, width_y, expr.c_str()); - } - - definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str())); - - continue; - } - - if (cell->type.in("$not", "$pos", "$neg")) - { - int width = GetSize(cell->getPort("\\Y")); - string expr_a, op; - - if (cell->type == "$not") op = "!"; - if (cell->type == "$pos") op = ""; - if (cell->type == "$neg") op = "-"; - - if (cell->getParam("\\A_SIGNED").as_bool()) - { - definitions.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")), - op.c_str(), rvalue_s(cell->getPort("\\A"), width))); - } - else - { - definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), - op.c_str(), rvalue_u(cell->getPort("\\A"), width))); - } - - continue; - } - - if (cell->type.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor")) - { - int width = GetSize(cell->getPort("\\Y")); - string expr_a, expr_b, op; - - if (cell->type == "$add") op = "+"; - if (cell->type == "$sub") op = "-"; - if (cell->type == "$mul") op = "*"; - if (cell->type == "$and") op = "&"; - if (cell->type == "$or") op = "|"; - if (cell->type == "$xor") op = "xor"; - if (cell->type == "$xnor") op = "xnor"; - - if (cell->getParam("\\A_SIGNED").as_bool()) - { - definitions.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")), - rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width))); - } - else - { - definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")), - rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width))); - } - - continue; - } - - if (cell->type.in("$div", "$mod")) - { - int width_y = GetSize(cell->getPort("\\Y")); - int width = max(width_y, GetSize(cell->getPort("\\A"))); - width = max(width, GetSize(cell->getPort("\\B"))); - string expr_a, expr_b, op; - - if (cell->type == "$div") op = "/"; - if (cell->type == "$mod") op = "mod"; - - if (cell->getParam("\\A_SIGNED").as_bool()) - { - definitions.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")), - rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width), width_y)); - } - else - { - definitions.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")), - rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width), width_y)); - } - - continue; - } - - if (cell->type.in("$eq", "$ne", "$eqx", "$nex", "$lt", "$le", "$ge", "$gt")) - { - int width = max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B"))); - string expr_a, expr_b, op; - - if (cell->type == "$eq") op = "="; - if (cell->type == "$ne") op = "!="; - if (cell->type == "$eqx") op = "="; - if (cell->type == "$nex") op = "!="; - if (cell->type == "$lt") op = "<"; - if (cell->type == "$le") op = "<="; - if (cell->type == "$ge") op = ">="; - if (cell->type == "$gt") op = ">"; - - if (cell->getParam("\\A_SIGNED").as_bool()) - { - expr_a = stringf("resize(signed(%s), %d)", rvalue(cell->getPort("\\A")), width); - expr_b = stringf("resize(signed(%s), %d)", rvalue(cell->getPort("\\B")), width); - } - else - { - expr_a = stringf("resize(%s, %d)", rvalue(cell->getPort("\\A")), width); - expr_b = stringf("resize(%s, %d)", rvalue(cell->getPort("\\B")), width); - } - - definitions.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")), - expr_a.c_str(), op.c_str(), expr_b.c_str(), GetSize(cell->getPort("\\Y")))); - - continue; - } - - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool")) - { - int width_a = GetSize(cell->getPort("\\A")); - int width_y = GetSize(cell->getPort("\\Y")); - const char *expr_a = rvalue(cell->getPort("\\A")); - const char *expr_y = lvalue(cell->getPort("\\Y")); - string expr; - - if (cell->type == "$reduce_and") expr = stringf("%s = !0ub%d_0", expr_a, width_a); - if (cell->type == "$reduce_or") expr = stringf("%s != 0ub%d_0", expr_a, width_a); - if (cell->type == "$reduce_bool") expr = stringf("%s != 0ub%d_0", expr_a, width_a); - - definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y)); - continue; - } - - if (cell->type.in("$reduce_xor", "$reduce_xnor")) - { - int width_y = GetSize(cell->getPort("\\Y")); - const char *expr_y = lvalue(cell->getPort("\\Y")); - string expr; - - for (auto bit : cell->getPort("\\A")) { - if (!expr.empty()) - expr += " xor "; - expr += rvalue(bit); - } - - if (cell->type == "$reduce_xnor") - expr = "!(" + expr + ")"; - - definitions.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y)); - continue; - } - - if (cell->type.in("$logic_and", "$logic_or")) - { - int width_a = GetSize(cell->getPort("\\A")); - int width_b = GetSize(cell->getPort("\\B")); - int width_y = GetSize(cell->getPort("\\Y")); - - string expr_a = stringf("(%s != 0ub%d_0)", rvalue(cell->getPort("\\A")), width_a); - string expr_b = stringf("(%s != 0ub%d_0)", rvalue(cell->getPort("\\B")), width_b); - const char *expr_y = lvalue(cell->getPort("\\Y")); - - string expr; - if (cell->type == "$logic_and") expr = expr_a + " & " + expr_b; - if (cell->type == "$logic_or") expr = expr_a + " | " + expr_b; - - definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y)); - continue; - } - - if (cell->type.in("$logic_not")) - { - int width_a = GetSize(cell->getPort("\\A")); - int width_y = GetSize(cell->getPort("\\Y")); - - string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort("\\A")), width_a); - const char *expr_y = lvalue(cell->getPort("\\Y")); - - definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y)); - continue; - } - - if (cell->type.in("$mux", "$pmux")) - { - int width = GetSize(cell->getPort("\\Y")); - SigSpec sig_a = cell->getPort("\\A"); - SigSpec sig_b = cell->getPort("\\B"); - SigSpec sig_s = cell->getPort("\\S"); - - string expr; - for (int i = 0; i < GetSize(sig_s); i++) - expr += stringf("bool(%s) ? %s : ", rvalue(sig_s[i]), rvalue(sig_b.extract(i*width, width))); - expr += rvalue(sig_a); - - definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str())); - continue; - } - - if (cell->type == "$dff") - { - vars.push_back(stringf("%s : unsigned word[%d]; -- %s", lvalue(cell->getPort("\\Q")), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q")))); - assignments.push_back(stringf("next(%s) := %s;", lvalue(cell->getPort("\\Q")), rvalue(cell->getPort("\\D")))); - continue; - } - - if (cell->type.in("$_BUF_", "$_NOT_")) - { - string op = cell->type == "$_NOT_" ? "!" : ""; - definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A")))); - continue; - } - - if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) - { - string op; - - if (cell->type.in("$_AND_", "$_NAND_", "$_ANDNOT_")) op = "&"; - if (cell->type.in("$_OR_", "$_NOR_", "$_ORNOT_")) op = "|"; - if (cell->type.in("$_XOR_")) op = "xor"; - if (cell->type.in("$_XNOR_")) op = "xnor"; - - if (cell->type.in("$_ANDNOT_", "$_ORNOT_")) - definitions.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")), - rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B")))); - else - if (cell->type.in("$_NAND_", "$_NOR_")) - definitions.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")), - rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B")))); - else - definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")), - rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B")))); - continue; - } - - if (cell->type == "$_MUX_") - { - definitions.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")), - rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A")))); - continue; - } - - if (cell->type == "$_AOI3_") - { - definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")), - rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")))); - continue; - } - - if (cell->type == "$_OAI3_") - { - definitions.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")), - rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")))); - continue; - } - - if (cell->type == "$_AOI4_") - { - definitions.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")), - rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D")))); - continue; - } - - if (cell->type == "$_OAI4_") - { - definitions.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")), - rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D")))); - continue; - } - - if (cell->type[0] == '$') - log_error("Found currently unsupported cell type %s (%s.%s).\n", log_id(cell->type), log_id(module), log_id(cell)); - -// f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type)); - - for (auto &conn : cell->connections()) - if (cell->output(conn.first)) - definitions.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first))); - else - definitions.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second))); - } - - for (Wire *wire : partial_assignment_wires) - { - string expr; - - for (int i = 0; i < wire->width; i++) - { - if (!expr.empty()) - expr = " :: " + expr; - - if (partial_assignment_bits.count(sigmap(SigBit(wire, i)))) - { - int width = 1; - const auto &bit_a = partial_assignment_bits.at(sigmap(SigBit(wire, i))); - - while (i+1 < wire->width) - { - SigBit next_bit = sigmap(SigBit(wire, i+1)); - - if (!partial_assignment_bits.count(next_bit)) - break; - - const auto &bit_b = partial_assignment_bits.at(next_bit); - if (strcmp(bit_a.first, bit_b.first)) - break; - if (bit_a.second+width != bit_b.second) - break; - - width++, i++; - } - - expr = stringf("%s[%d:%d]", bit_a.first, bit_a.second+width-1, bit_a.second) + expr; - } - else if (sigmap(SigBit(wire, i)).wire == nullptr) - { - string bits; - SigSpec sig = sigmap(SigSpec(wire, i)); - - while (i+1 < wire->width) { - SigBit next_bit = sigmap(SigBit(wire, i+1)); - if (next_bit.wire != nullptr) - break; - sig.append(next_bit); - i++; - } - - for (int k = GetSize(sig)-1; k >= 0; k--) - bits += sig[k] == State::S1 ? '1' : '0'; - - expr = stringf("0ub%d_%s", GetSize(bits), bits.c_str()) + expr; - } - else if (sigmap(SigBit(wire, i)) == SigBit(wire, i)) - { - int length = 1; - - while (i+1 < wire->width) { - if (partial_assignment_bits.count(sigmap(SigBit(wire, i+1)))) - break; - if (sigmap(SigBit(wire, i+1)) != SigBit(wire, i+1)) - break; - i++, length++; - } - - expr = stringf("0ub%d_0", length) + expr; - } - else - { - string bits; - SigSpec sig = sigmap(SigSpec(wire, i)); - - while (i+1 < wire->width) { - SigBit next_bit = sigmap(SigBit(wire, i+1)); - if (next_bit.wire == nullptr || partial_assignment_bits.count(next_bit)) - break; - sig.append(next_bit); - i++; - } - - expr = rvalue(sig) + expr; - } - } - - definitions.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str())); - } - - if (!inputvars.empty()) { - f << stringf(" IVAR\n"); - for (const string &line : inputvars) - f << stringf(" %s\n", line.c_str()); - } - - if (!vars.empty()) { - f << stringf(" VAR\n"); - for (const string &line : vars) - f << stringf(" %s\n", line.c_str()); - } - - if (!definitions.empty()) { - f << stringf(" DEFINE\n"); - for (const string &line : definitions) - f << stringf(" %s\n", line.c_str()); - } - - if (!assignments.empty()) { - f << stringf(" ASSIGN\n"); - for (const string &line : assignments) - f << stringf(" %s\n", line.c_str()); - } - - if (!invarspecs.empty()) { - for (const string &line : invarspecs) - f << stringf(" INVARSPEC %s\n", line.c_str()); - } - } -}; - -struct SmvBackend : public Backend { - SmvBackend() : Backend("smv", "write design to SMV file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_smv [options] [filename]\n"); - log("\n"); - log("Write an SMV description of the current design.\n"); - log("\n"); - log(" -verbose\n"); - log(" this will print the recursive walk used to export the modules.\n"); - log("\n"); - log(" -tpl \n"); - log(" use the given template file. the line containing only the token '%%%%'\n"); - log(" is replaced with the regular output of this command.\n"); - log("\n"); - log("THIS COMMAND IS UNDER CONSTRUCTION\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - std::ifstream template_f; - bool verbose = false; - - log_header(design, "Executing SMV backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-tpl" && argidx+1 < args.size()) { - template_f.open(args[++argidx]); - if (template_f.fail()) - log_error("Can't open template file `%s'.\n", args[argidx].c_str()); - continue; - } - if (args[argidx] == "-verbose") { - verbose = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - pool modules; - - for (auto module : design->modules()) - if (!module->get_blackbox_attribute() && !module->has_memories_warn() && !module->has_processes_warn()) - modules.insert(module); - - if (template_f.is_open()) - { - std::string line; - while (std::getline(template_f, line)) - { - int indent = 0; - while (indent < GetSize(line) && (line[indent] == ' ' || line[indent] == '\t')) - indent++; - - if (line[indent] == '%') - { - vector stmt = split_tokens(line); - - if (GetSize(stmt) == 1 && stmt[0] == "%%") - break; - - if (GetSize(stmt) == 2 && stmt[0] == "%module") - { - Module *module = design->module(RTLIL::escape_id(stmt[1])); - modules.erase(module); - - if (module == nullptr) - log_error("Module '%s' not found.\n", stmt[1].c_str()); - - *f << stringf("-- SMV description generated by %s\n", yosys_version_str); - - log("Creating SMV representation of module %s.\n", log_id(module)); - SmvWorker worker(module, verbose, *f); - worker.run(); - - *f << stringf("-- end of yosys output\n"); - continue; - } - - log_error("Unknown template statement: '%s'", line.c_str() + indent); - } - - *f << line << std::endl; - } - } - - if (!modules.empty()) - { - *f << stringf("-- SMV description generated by %s\n", yosys_version_str); - - for (auto module : modules) { - log("Creating SMV representation of module %s.\n", log_id(module)); - SmvWorker worker(module, verbose, *f); - worker.run(); - } - - *f << stringf("-- end of yosys output\n"); - } - - if (template_f.is_open()) { - std::string line; - while (std::getline(template_f, line)) - *f << line << std::endl; - } - } -} SmvBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/smv/test_cells.sh b/yosys/backends/smv/test_cells.sh deleted file mode 100644 index 63de465c0..000000000 --- a/yosys/backends/smv/test_cells.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -set -ex - -rm -rf test_cells.tmp -mkdir -p test_cells.tmp -cd test_cells.tmp - -# don't test $mul to reduce runtime -# don't test $div and $mod to reduce runtime and avoid "div by zero" message -../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod' - -cat > template.txt << "EOT" -%module main - INVARSPEC ! bool(_trigger); -EOT - -for fn in test_*.il; do - ../../../yosys -p " - read_ilang $fn - rename gold gate - synth - - read_ilang $fn - miter -equiv -flatten gold gate main - hierarchy -top main - write_smv -tpl template.txt ${fn#.il}.smv - " - nuXmv -dynamic ${fn#.il}.smv > ${fn#.il}.out -done - -grep '^-- invariant .* is false' *.out || echo 'All OK.' - diff --git a/yosys/backends/spice/Makefile.inc b/yosys/backends/spice/Makefile.inc deleted file mode 100644 index 9c8530cb2..000000000 --- a/yosys/backends/spice/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/spice/spice.o - diff --git a/yosys/backends/spice/spice.cc b/yosys/backends/spice/spice.cc deleted file mode 100644 index 6738a4bbd..000000000 --- a/yosys/backends/spice/spice.cc +++ /dev/null @@ -1,266 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -static string spice_id2str(IdString id) -{ - static const char *escape_chars = "$\\[]()<>="; - string s = RTLIL::unescape_id(id); - - for (auto &ch : s) - if (strchr(escape_chars, ch) != nullptr) ch = '_'; - - return s; -} - -static string spice_id2str(IdString id, bool use_inames, idict &inums) -{ - if (!use_inames && *id.c_str() == '$') - return stringf("%d", inums(id)); - return spice_id2str(id); -} - -static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter, bool use_inames, idict &inums) -{ - if (s.wire) { - if (s.wire->port_id) - use_inames = true; - if (s.wire->width > 1) - f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset); - else - f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str()); - } else { - if (s == RTLIL::State::S0) - f << stringf(" %s", neg.c_str()); - else if (s == RTLIL::State::S1) - f << stringf(" %s", pos.c_str()); - else - f << stringf(" %s%d", ncpf.c_str(), nc_counter++); - } -} - -static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian, bool use_inames) -{ - SigMap sigmap(module); - idict inums; - int cell_counter = 0, conn_counter = 0, nc_counter = 0; - - for (auto &cell_it : module->cells_) - { - RTLIL::Cell *cell = cell_it.second; - f << stringf("X%d", cell_counter++); - - std::vector port_sigs; - - if (design->modules_.count(cell->type) == 0) - { - log_warning("no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n", - log_id(cell->type), log_id(module), log_id(cell)); - for (auto &conn : cell->connections()) { - RTLIL::SigSpec sig = sigmap(conn.second); - port_sigs.push_back(sig); - } - } - else - { - RTLIL::Module *mod = design->modules_.at(cell->type); - - std::vector ports; - for (auto wire_it : mod->wires_) { - RTLIL::Wire *wire = wire_it.second; - if (wire->port_id == 0) - continue; - while (int(ports.size()) < wire->port_id) - ports.push_back(NULL); - ports.at(wire->port_id-1) = wire; - } - - for (RTLIL::Wire *wire : ports) { - log_assert(wire != NULL); - RTLIL::SigSpec sig(RTLIL::State::Sz, wire->width); - if (cell->hasPort(wire->name)) { - sig = sigmap(cell->getPort(wire->name)); - sig.extend_u0(wire->width, false); - } - port_sigs.push_back(sig); - } - } - - for (auto &sig : port_sigs) { - for (int i = 0; i < sig.size(); i++) { - RTLIL::SigSpec s = sig.extract(big_endian ? sig.size() - 1 - i : i, 1); - print_spice_net(f, s, neg, pos, ncpf, nc_counter, use_inames, inums); - } - } - - f << stringf(" %s\n", spice_id2str(cell->type).c_str()); - } - - for (auto &conn : module->connections()) - for (int i = 0; i < conn.first.size(); i++) { - f << stringf("V%d", conn_counter++); - print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); - print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); - f << stringf(" DC 0\n"); - } -} - -struct SpiceBackend : public Backend { - SpiceBackend() : Backend("spice", "write design to SPICE netlist file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_spice [options] [filename]\n"); - log("\n"); - log("Write the current design to an SPICE netlist file.\n"); - log("\n"); - log(" -big_endian\n"); - log(" generate multi-bit ports in MSB first order\n"); - log(" (default is LSB first)\n"); - log("\n"); - log(" -neg net_name\n"); - log(" set the net name for constant 0 (default: Vss)\n"); - log("\n"); - log(" -pos net_name\n"); - log(" set the net name for constant 1 (default: Vdd)\n"); - log("\n"); - log(" -nc_prefix\n"); - log(" prefix for not-connected nets (default: _NC)\n"); - log("\n"); - log(" -inames\n"); - log(" include names of internal ($-prefixed) nets in outputs\n"); - log(" (default is to use net numbers instead)\n"); - log("\n"); - log(" -top top_module\n"); - log(" set the specified module as design top module\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - std::string top_module_name; - RTLIL::Module *top_module = NULL; - bool big_endian = false, use_inames = false; - std::string neg = "Vss", pos = "Vdd", ncpf = "_NC"; - - log_header(design, "Executing SPICE backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-big_endian") { - big_endian = true; - continue; - } - if (args[argidx] == "-inames") { - use_inames = true; - continue; - } - if (args[argidx] == "-neg" && argidx+1 < args.size()) { - neg = args[++argidx]; - continue; - } - if (args[argidx] == "-pos" && argidx+1 < args.size()) { - pos = args[++argidx]; - continue; - } - if (args[argidx] == "-nc_prefix" && argidx+1 < args.size()) { - ncpf = args[++argidx]; - continue; - } - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_module_name = args[++argidx]; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - if (top_module_name.empty()) - for (auto & mod_it:design->modules_) - if (mod_it.second->get_bool_attribute("\\top")) - top_module_name = mod_it.first.str(); - - *f << stringf("* SPICE netlist generated by %s\n", yosys_version_str); - *f << stringf("\n"); - - for (auto module_it : design->modules_) - { - RTLIL::Module *module = module_it.second; - if (module->get_blackbox_attribute()) - continue; - - if (module->processes.size() != 0) - log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", log_id(module)); - if (module->memories.size() != 0) - log_error("Found unmapped memories in module %s: unmapped memories are not supported in SPICE backend!\n", log_id(module)); - - if (module->name == RTLIL::escape_id(top_module_name)) { - top_module = module; - continue; - } - - std::vector ports; - for (auto wire_it : module->wires_) { - RTLIL::Wire *wire = wire_it.second; - if (wire->port_id == 0) - continue; - while (int(ports.size()) < wire->port_id) - ports.push_back(NULL); - ports.at(wire->port_id-1) = wire; - } - - *f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str()); - for (RTLIL::Wire *wire : ports) { - log_assert(wire != NULL); - if (wire->width > 1) { - for (int i = 0; i < wire->width; i++) - *f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i); - } else - *f << stringf(" %s", spice_id2str(wire->name).c_str()); - } - *f << stringf("\n"); - print_spice_module(*f, module, design, neg, pos, ncpf, big_endian, use_inames); - *f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str()); - } - - if (!top_module_name.empty()) { - if (top_module == NULL) - log_error("Can't find top module `%s'!\n", top_module_name.c_str()); - print_spice_module(*f, top_module, design, neg, pos, ncpf, big_endian, use_inames); - *f << stringf("\n"); - } - - *f << stringf("************************\n"); - *f << stringf("* end of SPICE netlist *\n"); - *f << stringf("************************\n"); - *f << stringf("\n"); - } -} SpiceBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/table/Makefile.inc b/yosys/backends/table/Makefile.inc deleted file mode 100644 index 8cd1dc619..000000000 --- a/yosys/backends/table/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/table/table.o - diff --git a/yosys/backends/table/table.cc b/yosys/backends/table/table.cc deleted file mode 100644 index 796f18059..000000000 --- a/yosys/backends/table/table.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct TableBackend : public Backend { - TableBackend() : Backend("table", "write design as connectivity table") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_table [options] [filename]\n"); - log("\n"); - log("Write the current design as connectivity table. The output is a tab-separated\n"); - log("ASCII table with the following columns:\n"); - log("\n"); - log(" module name\n"); - log(" cell name\n"); - log(" cell type\n"); - log(" cell port\n"); - log(" direction\n"); - log(" signal\n"); - log("\n"); - log("module inputs and outputs are output using cell type and port '-' and with\n"); - log("'pi' (primary input) or 'po' (primary output) or 'pio' as direction.\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing TABLE backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - // if (args[argidx] == "-top" && argidx+1 < args.size()) { - // top_module_name = args[++argidx]; - // continue; - // } - break; - } - extra_args(f, filename, args, argidx); - - design->sort(); - - for (auto module : design->modules()) - { - if (module->get_blackbox_attribute()) - continue; - - SigMap sigmap(module); - - for (auto wire : module->wires()) - { - if (wire->port_id == 0) - continue; - - *f << log_id(module) << "\t"; - *f << log_id(wire) << "\t"; - *f << "-" << "\t"; - *f << "-" << "\t"; - - if (wire->port_input && wire->port_output) - *f << "pio" << "\t"; - else if (wire->port_input) - *f << "pi" << "\t"; - else if (wire->port_output) - *f << "po" << "\t"; - else - log_abort(); - - *f << log_signal(sigmap(wire)) << "\n"; - } - - for (auto cell : module->cells()) - for (auto conn : cell->connections()) - { - *f << log_id(module) << "\t"; - *f << log_id(cell) << "\t"; - *f << log_id(cell->type) << "\t"; - *f << log_id(conn.first) << "\t"; - - if (cell->input(conn.first) && cell->output(conn.first)) - *f << "inout" << "\t"; - else if (cell->input(conn.first)) - *f << "in" << "\t"; - else if (cell->output(conn.first)) - *f << "out" << "\t"; - else - *f << "unknown" << "\t"; - - *f << log_signal(sigmap(conn.second)) << "\n"; - } - } - } -} TableBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/verilog/Makefile.inc b/yosys/backends/verilog/Makefile.inc deleted file mode 100644 index c2dffef7a..000000000 --- a/yosys/backends/verilog/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/verilog/verilog_backend.o - diff --git a/yosys/backends/verilog/verilog_backend.cc b/yosys/backends/verilog/verilog_backend.cc deleted file mode 100644 index 087c6fec6..000000000 --- a/yosys/backends/verilog/verilog_backend.cc +++ /dev/null @@ -1,1916 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A simple and straightforward Verilog backend. - * - */ - -#include "kernel/register.h" -#include "kernel/celltypes.h" -#include "kernel/log.h" -#include "kernel/sigtools.h" -#include -#include -#include -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit; -int auto_name_counter, auto_name_offset, auto_name_digits; -std::map auto_name_map; -std::set reg_wires, reg_ct; -std::string auto_prefix; - -RTLIL::Module *active_module; -dict active_initdata; -SigMap active_sigmap; - -void reset_auto_counter_id(RTLIL::IdString id, bool may_rename) -{ - const char *str = id.c_str(); - - if (*str == '$' && may_rename && !norename) - auto_name_map[id] = auto_name_counter++; - - if (str[0] != '\\' || str[1] != '_' || str[2] == 0) - return; - - for (int i = 2; str[i] != 0; i++) { - if (str[i] == '_' && str[i+1] == 0) - continue; - if (str[i] < '0' || str[i] > '9') - return; - } - - int num = atoi(str+2); - if (num >= auto_name_offset) - auto_name_offset = num + 1; -} - -void reset_auto_counter(RTLIL::Module *module) -{ - auto_name_map.clear(); - auto_name_counter = 0; - auto_name_offset = 0; - - reset_auto_counter_id(module->name, false); - - for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) - reset_auto_counter_id(it->second->name, true); - - for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) { - reset_auto_counter_id(it->second->name, true); - reset_auto_counter_id(it->second->type, false); - } - - for (auto it = module->processes.begin(); it != module->processes.end(); ++it) - reset_auto_counter_id(it->second->name, false); - - auto_name_digits = 1; - for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10) - auto_name_digits++; - - if (verbose) - for (auto it = auto_name_map.begin(); it != auto_name_map.end(); ++it) - log(" renaming `%s' to `%s_%0*d_'.\n", it->first.c_str(), auto_prefix.c_str(), auto_name_digits, auto_name_offset + it->second); -} - -std::string next_auto_id() -{ - return stringf("%s_%0*d_", auto_prefix.c_str(), auto_name_digits, auto_name_offset + auto_name_counter++); -} - -std::string id(RTLIL::IdString internal_id, bool may_rename = true) -{ - const char *str = internal_id.c_str(); - bool do_escape = false; - - if (may_rename && auto_name_map.count(internal_id) != 0) - return stringf("%s_%0*d_", auto_prefix.c_str(), auto_name_digits, auto_name_offset + auto_name_map[internal_id]); - - if (*str == '\\') - str++; - - if ('0' <= *str && *str <= '9') - do_escape = true; - - for (int i = 0; str[i]; i++) - { - if ('0' <= str[i] && str[i] <= '9') - continue; - if ('a' <= str[i] && str[i] <= 'z') - continue; - if ('A' <= str[i] && str[i] <= 'Z') - continue; - if (str[i] == '_') - continue; - do_escape = true; - break; - } - - const pool keywords = { - // IEEE 1800-2017 Annex B - "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before", - "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle", - "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint", - "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker", - "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage", - "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually", - "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function", - "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies", - "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface", - "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint", - "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor", - "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive", - "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent", - "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat", - "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until", - "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify", - "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on", - "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1", - "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with", - "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while", - "wildcard", "wire", "with", "within", "wor", "xnor", "xor", - }; - if (keywords.count(str)) - do_escape = true; - - if (do_escape) - return "\\" + std::string(str) + " "; - return std::string(str); -} - -bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) -{ - if (!sig.is_chunk() || sig.as_chunk().wire == NULL) - return false; - - RTLIL::SigChunk chunk = sig.as_chunk(); - - if (reg_wires.count(chunk.wire->name) == 0) - return false; - - reg_name = id(chunk.wire->name); - if (sig.size() != chunk.wire->width) { - if (sig.size() == 1) - reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset); - else if (chunk.wire->upto) - reg_name += stringf("[%d:%d]", (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset, - (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset); - else - reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1, - chunk.wire->start_offset + chunk.offset); - } - - return true; -} - -void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false) -{ - bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0; - if (width < 0) - width = data.bits.size() - offset; - if (width == 0) { - f << "\"\""; - return; - } - if (nostr) - goto dump_hex; - if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { - if (width == 32 && !no_decimal && !nodec) { - int32_t val = 0; - for (int i = offset+width-1; i >= offset; i--) { - log_assert(i < (int)data.bits.size()); - if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1) - goto dump_hex; - if (data.bits[i] == RTLIL::S1) - val |= 1 << (i - offset); - } - if (decimal) - f << stringf("%d", val); - else if (set_signed && val < 0) - f << stringf("-32'sd%u", -val); - else - f << stringf("32'%sd%u", set_signed ? "s" : "", val); - } else { - dump_hex: - if (nohex) - goto dump_bin; - vector bin_digits, hex_digits; - for (int i = offset; i < offset+width; i++) { - log_assert(i < (int)data.bits.size()); - switch (data.bits[i]) { - case RTLIL::S0: bin_digits.push_back('0'); break; - case RTLIL::S1: bin_digits.push_back('1'); break; - case RTLIL::Sx: bin_digits.push_back('x'); break; - case RTLIL::Sz: bin_digits.push_back('z'); break; - case RTLIL::Sa: bin_digits.push_back('z'); break; - case RTLIL::Sm: log_error("Found marker state in final netlist."); - } - } - if (GetSize(bin_digits) == 0) - goto dump_bin; - while (GetSize(bin_digits) % 4 != 0) - if (bin_digits.back() == '1') - bin_digits.push_back('0'); - else - bin_digits.push_back(bin_digits.back()); - for (int i = 0; i < GetSize(bin_digits); i += 4) - { - char bit_3 = bin_digits[i+3]; - char bit_2 = bin_digits[i+2]; - char bit_1 = bin_digits[i+1]; - char bit_0 = bin_digits[i+0]; - if (bit_3 == 'x' || bit_2 == 'x' || bit_1 == 'x' || bit_0 == 'x') { - if (bit_3 != 'x' || bit_2 != 'x' || bit_1 != 'x' || bit_0 != 'x') - goto dump_bin; - hex_digits.push_back('x'); - continue; - } - if (bit_3 == 'z' || bit_2 == 'z' || bit_1 == 'z' || bit_0 == 'z') { - if (bit_3 != 'z' || bit_2 != 'z' || bit_1 != 'z' || bit_0 != 'z') - goto dump_bin; - hex_digits.push_back('z'); - continue; - } - int val = 8*(bit_3 - '0') + 4*(bit_2 - '0') + 2*(bit_1 - '0') + (bit_0 - '0'); - hex_digits.push_back(val < 10 ? '0' + val : 'a' + val - 10); - } - f << stringf("%d'%sh", width, set_signed ? "s" : ""); - for (int i = GetSize(hex_digits)-1; i >= 0; i--) - f << hex_digits[i]; - } - if (0) { - dump_bin: - f << stringf("%d'%sb", width, set_signed ? "s" : ""); - if (width == 0) - f << stringf("0"); - for (int i = offset+width-1; i >= offset; i--) { - log_assert(i < (int)data.bits.size()); - switch (data.bits[i]) { - case RTLIL::S0: f << stringf("0"); break; - case RTLIL::S1: f << stringf("1"); break; - case RTLIL::Sx: f << stringf("x"); break; - case RTLIL::Sz: f << stringf("z"); break; - case RTLIL::Sa: f << stringf("z"); break; - case RTLIL::Sm: log_error("Found marker state in final netlist."); - } - } - } - } else { - if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0) - f << stringf("\""); - std::string str = data.decode_string(); - for (size_t i = 0; i < str.size(); i++) { - if (str[i] == '\n') - f << stringf("\\n"); - else if (str[i] == '\t') - f << stringf("\\t"); - else if (str[i] < 32) - f << stringf("\\%03o", str[i]); - else if (str[i] == '"') - f << stringf("\\\""); - else if (str[i] == '\\') - f << stringf("\\\\"); - else if (str[i] == '/' && escape_comment && i > 0 && str[i-1] == '*') - f << stringf("\\/"); - else - f << str[i]; - } - if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0) - f << stringf("\""); - } -} - -void dump_reg_init(std::ostream &f, SigSpec sig) -{ - Const initval; - bool gotinit = false; - - for (auto bit : active_sigmap(sig)) { - if (active_initdata.count(bit)) { - initval.bits.push_back(active_initdata.at(bit)); - gotinit = true; - } else { - initval.bits.push_back(State::Sx); - } - } - - if (gotinit) { - f << " = "; - dump_const(f, initval); - } -} - -void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false) -{ - if (chunk.wire == NULL) { - dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal); - } else { - if (chunk.width == chunk.wire->width && chunk.offset == 0) { - f << stringf("%s", id(chunk.wire->name).c_str()); - } else if (chunk.width == 1) { - if (chunk.wire->upto) - f << stringf("%s[%d]", id(chunk.wire->name).c_str(), (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset); - else - f << stringf("%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset); - } else { - if (chunk.wire->upto) - f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(), - (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset, - (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset); - else - f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(), - (chunk.offset + chunk.width - 1) + chunk.wire->start_offset, - chunk.offset + chunk.wire->start_offset); - } - } -} - -void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) -{ - if (GetSize(sig) == 0) { - f << "\"\""; - return; - } - if (sig.is_chunk()) { - dump_sigchunk(f, sig.as_chunk()); - } else { - f << stringf("{ "); - for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) { - if (it != sig.chunks().rbegin()) - f << stringf(", "); - dump_sigchunk(f, *it, true); - } - f << stringf(" }"); - } -} - -void dump_attributes(std::ostream &f, std::string indent, dict &attributes, char term = '\n', bool modattr = false, bool as_comment = false) -{ - if (noattr) - return; - if (attr2comment) - as_comment = true; - for (auto it = attributes.begin(); it != attributes.end(); ++it) { - f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str()); - f << stringf(" = "); - if (modattr && (it->second == Const(0, 1) || it->second == Const(0))) - f << stringf(" 0 "); - else if (modattr && (it->second == Const(1, 1) || it->second == Const(1))) - f << stringf(" 1 "); - else - dump_const(f, it->second, -1, 0, false, as_comment); - f << stringf(" %s%c", as_comment ? "*/" : "*)", term); - } -} - -void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire) -{ - dump_attributes(f, indent, wire->attributes); -#if 0 - if (wire->port_input && !wire->port_output) - f << stringf("%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : ""); - else if (!wire->port_input && wire->port_output) - f << stringf("%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : ""); - else if (wire->port_input && wire->port_output) - f << stringf("%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : ""); - else - f << stringf("%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire"); - if (wire->width != 1) - f << stringf("[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset); - f << stringf("%s;\n", id(wire->name).c_str()); -#else - // do not use Verilog-2k "output reg" syntax in Verilog export - std::string range = ""; - if (wire->width != 1) { - if (wire->upto) - range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset); - else - range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset); - } - if (wire->port_input && !wire->port_output) - f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str()); - if (!wire->port_input && wire->port_output) - f << stringf("%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str()); - if (wire->port_input && wire->port_output) - f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str()); - if (reg_wires.count(wire->name)) { - f << stringf("%s" "reg%s %s", indent.c_str(), range.c_str(), id(wire->name).c_str()); - if (wire->attributes.count("\\init")) { - f << stringf(" = "); - dump_const(f, wire->attributes.at("\\init")); - } - f << stringf(";\n"); - } else if (!wire->port_input && !wire->port_output) - f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str()); -#endif -} - -void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory) -{ - dump_attributes(f, indent, memory->attributes); - f << stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size+memory->start_offset-1, memory->start_offset); -} - -void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true) -{ - if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) { - f << stringf("$signed("); - dump_sigspec(f, cell->getPort("\\" + port)); - f << stringf(")"); - } else - dump_sigspec(f, cell->getPort("\\" + port)); -} - -std::string cellname(RTLIL::Cell *cell) -{ - if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q")) - { - RTLIL::SigSpec sig = cell->getPort("\\Q"); - if (GetSize(sig) != 1 || sig.is_fully_const()) - goto no_special_reg_name; - - RTLIL::Wire *wire = sig[0].wire; - - if (wire->name[0] != '\\') - goto no_special_reg_name; - - std::string cell_name = wire->name.str(); - - size_t pos = cell_name.find('['); - if (pos != std::string::npos) - cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos); - else - cell_name = cell_name + "_reg"; - - if (wire->width != 1) - cell_name += stringf("[%d]", wire->start_offset + sig[0].offset); - - if (active_module && active_module->count_id(cell_name) > 0) - goto no_special_reg_name; - - return id(cell_name); - } - else - { -no_special_reg_name: - return id(cell->name).c_str(); - } -} - -void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op) -{ - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = %s ", op.c_str()); - dump_attributes(f, "", cell->attributes, ' '); - dump_cell_expr_port(f, cell, "A", true); - f << stringf(";\n"); -} - -void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op) -{ - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - dump_cell_expr_port(f, cell, "A", true); - f << stringf(" %s ", op.c_str()); - dump_attributes(f, "", cell->attributes, ' '); - dump_cell_expr_port(f, cell, "B", true); - f << stringf(";\n"); -} - -bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) -{ - if (cell->type == "$_NOT_") { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - f << stringf("~"); - dump_attributes(f, "", cell->attributes, ' '); - dump_cell_expr_port(f, cell, "A", false); - f << stringf(";\n"); - return true; - } - - if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_")) - f << stringf("~("); - dump_cell_expr_port(f, cell, "A", false); - f << stringf(" "); - if (cell->type.in("$_AND_", "$_NAND_", "$_ANDNOT_")) - f << stringf("&"); - if (cell->type.in("$_OR_", "$_NOR_", "$_ORNOT_")) - f << stringf("|"); - if (cell->type.in("$_XOR_", "$_XNOR_")) - f << stringf("^"); - dump_attributes(f, "", cell->attributes, ' '); - f << stringf(" "); - if (cell->type.in("$_ANDNOT_", "$_ORNOT_")) - f << stringf("~("); - dump_cell_expr_port(f, cell, "B", false); - if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) - f << stringf(")"); - f << stringf(";\n"); - return true; - } - - if (cell->type == "$_MUX_") { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - dump_cell_expr_port(f, cell, "S", false); - f << stringf(" ? "); - dump_attributes(f, "", cell->attributes, ' '); - dump_cell_expr_port(f, cell, "B", false); - f << stringf(" : "); - dump_cell_expr_port(f, cell, "A", false); - f << stringf(";\n"); - return true; - } - - if (cell->type.in("$_AOI3_", "$_OAI3_")) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = ~(("); - dump_cell_expr_port(f, cell, "A", false); - f << stringf(cell->type == "$_AOI3_" ? " & " : " | "); - dump_cell_expr_port(f, cell, "B", false); - f << stringf(cell->type == "$_AOI3_" ? ") |" : ") &"); - dump_attributes(f, "", cell->attributes, ' '); - f << stringf(" "); - dump_cell_expr_port(f, cell, "C", false); - f << stringf(");\n"); - return true; - } - - if (cell->type.in("$_AOI4_", "$_OAI4_")) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = ~(("); - dump_cell_expr_port(f, cell, "A", false); - f << stringf(cell->type == "$_AOI4_" ? " & " : " | "); - dump_cell_expr_port(f, cell, "B", false); - f << stringf(cell->type == "$_AOI4_" ? ") |" : ") &"); - dump_attributes(f, "", cell->attributes, ' '); - f << stringf(" ("); - dump_cell_expr_port(f, cell, "C", false); - f << stringf(cell->type == "$_AOI4_" ? " & " : " | "); - dump_cell_expr_port(f, cell, "D", false); - f << stringf("));\n"); - return true; - } - - if (cell->type.substr(0, 6) == "$_DFF_") - { - std::string reg_name = cellname(cell); - bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name); - - if (!out_is_reg_wire) { - f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str()); - dump_reg_init(f, cell->getPort("\\Q")); - f << ";\n"; - } - - dump_attributes(f, indent, cell->attributes); - f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg"); - dump_sigspec(f, cell->getPort("\\C")); - if (cell->type[7] != '_') { - f << stringf(" or %sedge ", cell->type[7] == 'P' ? "pos" : "neg"); - dump_sigspec(f, cell->getPort("\\R")); - } - f << stringf(")\n"); - - if (cell->type[7] != '_') { - f << stringf("%s" " if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!"); - dump_sigspec(f, cell->getPort("\\R")); - f << stringf(")\n"); - f << stringf("%s" " %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]); - f << stringf("%s" " else\n", indent.c_str()); - } - - f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str()); - dump_cell_expr_port(f, cell, "D", false); - f << stringf(";\n"); - - if (!out_is_reg_wire) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Q")); - f << stringf(" = %s;\n", reg_name.c_str()); - } - - return true; - } - - if (cell->type.substr(0, 8) == "$_DFFSR_") - { - char pol_c = cell->type[8], pol_s = cell->type[9], pol_r = cell->type[10]; - - std::string reg_name = cellname(cell); - bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name); - - if (!out_is_reg_wire) { - f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str()); - dump_reg_init(f, cell->getPort("\\Q")); - f << ";\n"; - } - - dump_attributes(f, indent, cell->attributes); - f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg"); - dump_sigspec(f, cell->getPort("\\C")); - f << stringf(" or %sedge ", pol_s == 'P' ? "pos" : "neg"); - dump_sigspec(f, cell->getPort("\\S")); - f << stringf(" or %sedge ", pol_r == 'P' ? "pos" : "neg"); - dump_sigspec(f, cell->getPort("\\R")); - f << stringf(")\n"); - - f << stringf("%s" " if (%s", indent.c_str(), pol_r == 'P' ? "" : "!"); - dump_sigspec(f, cell->getPort("\\R")); - f << stringf(")\n"); - f << stringf("%s" " %s <= 0;\n", indent.c_str(), reg_name.c_str()); - - f << stringf("%s" " else if (%s", indent.c_str(), pol_s == 'P' ? "" : "!"); - dump_sigspec(f, cell->getPort("\\S")); - f << stringf(")\n"); - f << stringf("%s" " %s <= 1;\n", indent.c_str(), reg_name.c_str()); - - f << stringf("%s" " else\n", indent.c_str()); - f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str()); - dump_cell_expr_port(f, cell, "D", false); - f << stringf(";\n"); - - if (!out_is_reg_wire) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Q")); - f << stringf(" = %s;\n", reg_name.c_str()); - } - - return true; - } - -#define HANDLE_UNIOP(_type, _operator) \ - if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; } -#define HANDLE_BINOP(_type, _operator) \ - if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; } - - HANDLE_UNIOP("$not", "~") - HANDLE_UNIOP("$pos", "+") - HANDLE_UNIOP("$neg", "-") - - HANDLE_BINOP("$and", "&") - HANDLE_BINOP("$or", "|") - HANDLE_BINOP("$xor", "^") - HANDLE_BINOP("$xnor", "~^") - - HANDLE_UNIOP("$reduce_and", "&") - HANDLE_UNIOP("$reduce_or", "|") - HANDLE_UNIOP("$reduce_xor", "^") - HANDLE_UNIOP("$reduce_xnor", "~^") - HANDLE_UNIOP("$reduce_bool", "|") - - HANDLE_BINOP("$shl", "<<") - HANDLE_BINOP("$shr", ">>") - HANDLE_BINOP("$sshl", "<<<") - HANDLE_BINOP("$sshr", ">>>") - - HANDLE_BINOP("$lt", "<") - HANDLE_BINOP("$le", "<=") - HANDLE_BINOP("$eq", "==") - HANDLE_BINOP("$ne", "!=") - HANDLE_BINOP("$eqx", "===") - HANDLE_BINOP("$nex", "!==") - HANDLE_BINOP("$ge", ">=") - HANDLE_BINOP("$gt", ">") - - HANDLE_BINOP("$add", "+") - HANDLE_BINOP("$sub", "-") - HANDLE_BINOP("$mul", "*") - HANDLE_BINOP("$div", "/") - HANDLE_BINOP("$mod", "%") - HANDLE_BINOP("$pow", "**") - - HANDLE_UNIOP("$logic_not", "!") - HANDLE_BINOP("$logic_and", "&&") - HANDLE_BINOP("$logic_or", "||") - -#undef HANDLE_UNIOP -#undef HANDLE_BINOP - - if (cell->type == "$shift") - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - if (cell->getParam("\\B_SIGNED").as_bool()) - { - f << stringf("$signed("); - dump_sigspec(f, cell->getPort("\\B")); - f << stringf(")"); - f << stringf(" < 0 ? "); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(" << - "); - dump_sigspec(f, cell->getPort("\\B")); - f << stringf(" : "); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(" >> "); - dump_sigspec(f, cell->getPort("\\B")); - } - else - { - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(" >> "); - dump_sigspec(f, cell->getPort("\\B")); - } - f << stringf(";\n"); - return true; - } - - if (cell->type == "$shiftx") - { - std::string temp_id = next_auto_id(); - f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort("\\A"))-1, temp_id.c_str()); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(";\n"); - - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = %s[", temp_id.c_str()); - if (cell->getParam("\\B_SIGNED").as_bool()) - f << stringf("$signed("); - dump_sigspec(f, cell->getPort("\\B")); - if (cell->getParam("\\B_SIGNED").as_bool()) - f << stringf(")"); - f << stringf(" +: %d", cell->getParam("\\Y_WIDTH").as_int()); - f << stringf("];\n"); - return true; - } - - if (cell->type == "$mux") - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - dump_sigspec(f, cell->getPort("\\S")); - f << stringf(" ? "); - dump_attributes(f, "", cell->attributes, ' '); - dump_sigspec(f, cell->getPort("\\B")); - f << stringf(" : "); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(";\n"); - return true; - } - - if (cell->type == "$pmux" || cell->type == "$pmux_safe") - { - int width = cell->parameters["\\WIDTH"].as_int(); - int s_width = cell->getPort("\\S").size(); - std::string func_name = cellname(cell); - - f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str()); - f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1); - f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1); - f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1); - - dump_attributes(f, indent + " ", cell->attributes); - if (cell->type != "$pmux_safe" && !noattr) - f << stringf("%s" " (* parallel_case *)\n", indent.c_str()); - f << stringf("%s" " casez (s)", indent.c_str()); - if (cell->type != "$pmux_safe") - f << stringf(noattr ? " // synopsys parallel_case\n" : "\n"); - - for (int i = 0; i < s_width; i++) - { - f << stringf("%s" " %d'b", indent.c_str(), s_width); - - for (int j = s_width-1; j >= 0; j--) - f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?'); - - f << stringf(":\n"); - f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width); - } - - f << stringf("%s" " default:\n", indent.c_str()); - f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str()); - - f << stringf("%s" " endcase\n", indent.c_str()); - f << stringf("%s" "endfunction\n", indent.c_str()); - - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = %s(", func_name.c_str()); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(", "); - dump_sigspec(f, cell->getPort("\\B")); - f << stringf(", "); - dump_sigspec(f, cell->getPort("\\S")); - f << stringf(");\n"); - return true; - } - - if (cell->type == "$tribuf") - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - dump_sigspec(f, cell->getPort("\\EN")); - f << stringf(" ? "); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(" : %d'bz;\n", cell->parameters.at("\\WIDTH").as_int()); - return true; - } - - if (cell->type == "$slice") - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(" >> %d;\n", cell->parameters.at("\\OFFSET").as_int()); - return true; - } - - if (cell->type == "$concat") - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = { "); - dump_sigspec(f, cell->getPort("\\B")); - f << stringf(" , "); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(" };\n"); - return true; - } - - if (cell->type == "$lut") - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); - f << stringf(" = "); - dump_const(f, cell->parameters.at("\\LUT")); - f << stringf(" >> "); - dump_attributes(f, "", cell->attributes, ' '); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(";\n"); - return true; - } - - if (cell->type == "$dffsr") - { - SigSpec sig_clk = cell->getPort("\\CLK"); - SigSpec sig_set = cell->getPort("\\SET"); - SigSpec sig_clr = cell->getPort("\\CLR"); - SigSpec sig_d = cell->getPort("\\D"); - SigSpec sig_q = cell->getPort("\\Q"); - - int width = cell->parameters["\\WIDTH"].as_int(); - bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool(); - bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool(); - bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool(); - - std::string reg_name = cellname(cell); - bool out_is_reg_wire = is_reg_wire(sig_q, reg_name); - - if (!out_is_reg_wire) { - f << stringf("%s" "reg [%d:0] %s", indent.c_str(), width-1, reg_name.c_str()); - dump_reg_init(f, sig_q); - f << ";\n"; - } - - for (int i = 0; i < width; i++) { - f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg"); - dump_sigspec(f, sig_clk); - f << stringf(", %sedge ", pol_set ? "pos" : "neg"); - dump_sigspec(f, sig_set); - f << stringf(", %sedge ", pol_clr ? "pos" : "neg"); - dump_sigspec(f, sig_clr); - f << stringf(")\n"); - - f << stringf("%s" " if (%s", indent.c_str(), pol_clr ? "" : "!"); - dump_sigspec(f, sig_clr); - f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i); - - f << stringf("%s" " else if (%s", indent.c_str(), pol_set ? "" : "!"); - dump_sigspec(f, sig_set); - f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i); - - f << stringf("%s" " else %s[%d] <= ", indent.c_str(), reg_name.c_str(), i); - dump_sigspec(f, sig_d[i]); - f << stringf(";\n"); - } - - if (!out_is_reg_wire) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, sig_q); - f << stringf(" = %s;\n", reg_name.c_str()); - } - - return true; - } - - if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe") - { - RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst; - bool pol_clk, pol_arst = false, pol_en = false; - - sig_clk = cell->getPort("\\CLK"); - pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool(); - - if (cell->type == "$adff") { - sig_arst = cell->getPort("\\ARST"); - pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool(); - val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]); - } - - if (cell->type == "$dffe") { - sig_en = cell->getPort("\\EN"); - pol_en = cell->parameters["\\EN_POLARITY"].as_bool(); - } - - std::string reg_name = cellname(cell); - bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name); - - if (!out_is_reg_wire) { - f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str()); - dump_reg_init(f, cell->getPort("\\Q")); - f << ";\n"; - } - - f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg"); - dump_sigspec(f, sig_clk); - if (cell->type == "$adff") { - f << stringf(" or %sedge ", pol_arst ? "pos" : "neg"); - dump_sigspec(f, sig_arst); - } - f << stringf(")\n"); - - if (cell->type == "$adff") { - f << stringf("%s" " if (%s", indent.c_str(), pol_arst ? "" : "!"); - dump_sigspec(f, sig_arst); - f << stringf(")\n"); - f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str()); - dump_sigspec(f, val_arst); - f << stringf(";\n"); - f << stringf("%s" " else\n", indent.c_str()); - } - - if (cell->type == "$dffe") { - f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!"); - dump_sigspec(f, sig_en); - f << stringf(")\n"); - } - - f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str()); - dump_cell_expr_port(f, cell, "D", false); - f << stringf(";\n"); - - if (!out_is_reg_wire) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Q")); - f << stringf(" = %s;\n", reg_name.c_str()); - } - - return true; - } - - if (cell->type == "$dlatch") - { - RTLIL::SigSpec sig_en; - bool pol_en = false; - - sig_en = cell->getPort("\\EN"); - pol_en = cell->parameters["\\EN_POLARITY"].as_bool(); - - std::string reg_name = cellname(cell); - bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name); - - if (!out_is_reg_wire) { - f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str()); - dump_reg_init(f, cell->getPort("\\Q")); - f << ";\n"; - } - - f << stringf("%s" "always @*\n", indent.c_str()); - - f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!"); - dump_sigspec(f, sig_en); - f << stringf(")\n"); - - f << stringf("%s" " %s = ", indent.c_str(), reg_name.c_str()); - dump_cell_expr_port(f, cell, "D", false); - f << stringf(";\n"); - - if (!out_is_reg_wire) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Q")); - f << stringf(" = %s;\n", reg_name.c_str()); - } - - return true; - } - - if (cell->type == "$mem") - { - RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string(); - std::string mem_id = id(cell->parameters["\\MEMID"].decode_string()); - int abits = cell->parameters["\\ABITS"].as_int(); - int size = cell->parameters["\\SIZE"].as_int(); - int offset = cell->parameters["\\OFFSET"].as_int(); - int width = cell->parameters["\\WIDTH"].as_int(); - bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef()); - - // for memory block make something like: - // reg [7:0] memid [3:0]; - // initial begin - // memid[0] = ... - // end - f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size+offset-1, offset); - if (use_init) - { - f << stringf("%s" "initial begin\n", indent.c_str()); - for (int i=0; i expressions within that clock domain - dict> clk_to_lof_body; - clk_to_lof_body[""] = std::vector(); - std::string clk_domain_str; - // create a list of reg declarations - std::vector lof_reg_declarations; - - int nread_ports = cell->parameters["\\RD_PORTS"].as_int(); - RTLIL::SigSpec sig_rd_clk, sig_rd_en, sig_rd_data, sig_rd_addr; - bool use_rd_clk, rd_clk_posedge, rd_transparent; - // read ports - for (int i=0; i < nread_ports; i++) - { - sig_rd_clk = cell->getPort("\\RD_CLK").extract(i); - sig_rd_en = cell->getPort("\\RD_EN").extract(i); - sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width); - sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits); - use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool(); - rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool(); - rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool(); - if (use_rd_clk) - { - { - std::ostringstream os; - dump_sigspec(os, sig_rd_clk); - clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str()); - if( clk_to_lof_body.count(clk_domain_str) == 0 ) - clk_to_lof_body[clk_domain_str] = std::vector(); - } - if (!rd_transparent) - { - // for clocked read ports make something like: - // reg [..] temp_id; - // always @(posedge clk) - // if (rd_en) temp_id <= array_reg[r_addr]; - // assign r_data = temp_id; - std::string temp_id = next_auto_id(); - lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) ); - { - std::ostringstream os; - if (sig_rd_en != RTLIL::SigBit(true)) - { - os << stringf("if ("); - dump_sigspec(os, sig_rd_en); - os << stringf(") "); - } - os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str()); - dump_sigspec(os, sig_rd_addr); - os << stringf("];\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); - } - { - std::ostringstream os; - dump_sigspec(os, sig_rd_data); - std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str()); - clk_to_lof_body[""].push_back(line); - } - } - else - { - // for rd-transparent read-ports make something like: - // reg [..] temp_id; - // always @(posedge clk) - // temp_id <= r_addr; - // assign r_data = array_reg[temp_id]; - std::string temp_id = next_auto_id(); - lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr.size() - 1, temp_id.c_str()) ); - { - std::ostringstream os; - dump_sigspec(os, sig_rd_addr); - std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str()); - clk_to_lof_body[clk_domain_str].push_back(line); - } - { - std::ostringstream os; - dump_sigspec(os, sig_rd_data); - std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str()); - clk_to_lof_body[""].push_back(line); - } - } - } else { - // for non-clocked read-ports make something like: - // assign r_data = array_reg[r_addr]; - std::ostringstream os, os2; - dump_sigspec(os, sig_rd_data); - dump_sigspec(os2, sig_rd_addr); - std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str()); - clk_to_lof_body[""].push_back(line); - } - } - - int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int(); - RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en; - bool wr_clk_posedge; - - // write ports - for (int i=0; i < nwrite_ports; i++) - { - sig_wr_clk = cell->getPort("\\WR_CLK").extract(i); - sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width); - sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits); - sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width); - wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool(); - { - std::ostringstream os; - dump_sigspec(os, sig_wr_clk); - clk_domain_str = stringf("%sedge %s", wr_clk_posedge ? "pos" : "neg", os.str().c_str()); - if( clk_to_lof_body.count(clk_domain_str) == 0 ) - clk_to_lof_body[clk_domain_str] = std::vector(); - } - // make something like: - // always @(posedge clk) - // if (wr_en_bit) memid[w_addr][??] <= w_data[??]; - // ... - for (int i = 0; i < GetSize(sig_wr_en); i++) - { - int start_i = i, width = 1; - SigBit wen_bit = sig_wr_en[i]; - - while (i+1 < GetSize(sig_wr_en) && active_sigmap(sig_wr_en[i+1]) == active_sigmap(wen_bit)) - i++, width++; - - if (wen_bit == State::S0) - continue; - - std::ostringstream os; - if (wen_bit != State::S1) - { - os << stringf("if ("); - dump_sigspec(os, wen_bit); - os << stringf(") "); - } - os << stringf("%s[", mem_id.c_str()); - dump_sigspec(os, sig_wr_addr); - if (width == GetSize(sig_wr_en)) - os << stringf("] <= "); - else - os << stringf("][%d:%d] <= ", i, start_i); - dump_sigspec(os, sig_wr_data.extract(start_i, width)); - os << stringf(";\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); - } - } - // Output Verilog that looks something like this: - // reg [..] _3_; - // always @(posedge CLK2) begin - // _3_ <= memory[D1ADDR]; - // if (A1EN) - // memory[A1ADDR] <= A1DATA; - // if (A2EN) - // memory[A2ADDR] <= A2DATA; - // ... - // end - // always @(negedge CLK1) begin - // if (C1EN) - // memory[C1ADDR] <= C1DATA; - // end - // ... - // assign D1DATA = _3_; - // assign D2DATA <= memory[D2ADDR]; - - // the reg ... definitions - for(auto ® : lof_reg_declarations) - { - f << stringf("%s" "%s", indent.c_str(), reg.c_str()); - } - // the block of expressions by clock domain - for(auto &pair : clk_to_lof_body) - { - std::string clk_domain = pair.first; - std::vector lof_lines = pair.second; - if( clk_domain != "") - { - f << stringf("%s" "always @(%s) begin\n", indent.c_str(), clk_domain.c_str()); - for(auto &line : lof_lines) - f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str()); - f << stringf("%s" "end\n", indent.c_str()); - } - else - { - // the non-clocked assignments - for(auto &line : lof_lines) - f << stringf("%s" "%s", indent.c_str(), line.c_str()); - } - } - - return true; - } - - if (cell->type.in("$assert", "$assume", "$cover")) - { - f << stringf("%s" "always @* if (", indent.c_str()); - dump_sigspec(f, cell->getPort("\\EN")); - f << stringf(") %s(", cell->type.c_str()+1); - dump_sigspec(f, cell->getPort("\\A")); - f << stringf(");\n"); - return true; - } - - if (cell->type.in("$specify2", "$specify3")) - { - f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str()); - - SigSpec en = cell->getPort("\\EN"); - if (en != State::S1) { - f << stringf("if ("); - dump_sigspec(f, cell->getPort("\\EN")); - f << stringf(") "); - } - - f << "("; - if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool()) - f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge "); - - dump_sigspec(f, cell->getPort("\\SRC")); - - f << " "; - if (cell->getParam("\\SRC_DST_PEN").as_bool()) - f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-"); - f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> "); - - if (cell->type == "$specify3") { - f << "("; - dump_sigspec(f, cell->getPort("\\DST")); - f << " "; - if (cell->getParam("\\DAT_DST_PEN").as_bool()) - f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-"); - f << ": "; - dump_sigspec(f, cell->getPort("\\DAT")); - f << ")"; - } else { - dump_sigspec(f, cell->getPort("\\DST")); - } - - bool bak_decimal = decimal; - decimal = 1; - - f << ") = ("; - dump_const(f, cell->getParam("\\T_RISE_MIN")); - f << ":"; - dump_const(f, cell->getParam("\\T_RISE_TYP")); - f << ":"; - dump_const(f, cell->getParam("\\T_RISE_MAX")); - f << ", "; - dump_const(f, cell->getParam("\\T_FALL_MIN")); - f << ":"; - dump_const(f, cell->getParam("\\T_FALL_TYP")); - f << ":"; - dump_const(f, cell->getParam("\\T_FALL_MAX")); - f << ");\n"; - - decimal = bak_decimal; - - f << stringf("%s" "endspecify\n", indent.c_str()); - return true; - } - - if (cell->type == "$specrule") - { - f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str()); - - string spec_type = cell->getParam("\\TYPE").decode_string(); - f << stringf("%s(", spec_type.c_str()); - - if (cell->getParam("\\SRC_PEN").as_bool()) - f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge "); - dump_sigspec(f, cell->getPort("\\SRC")); - - if (cell->getPort("\\SRC_EN") != State::S1) { - f << " &&& "; - dump_sigspec(f, cell->getPort("\\SRC_EN")); - } - - f << ", "; - if (cell->getParam("\\DST_PEN").as_bool()) - f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge "); - dump_sigspec(f, cell->getPort("\\DST")); - - if (cell->getPort("\\DST_EN") != State::S1) { - f << " &&& "; - dump_sigspec(f, cell->getPort("\\DST_EN")); - } - - bool bak_decimal = decimal; - decimal = 1; - - f << ", "; - dump_const(f, cell->getParam("\\T_LIMIT")); - - if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") { - f << ", "; - dump_const(f, cell->getParam("\\T_LIMIT2")); - } - - f << ");\n"; - decimal = bak_decimal; - - f << stringf("%s" "endspecify\n", indent.c_str()); - return true; - } - - // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_ - // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm - - return false; -} - -void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) -{ - if (cell->type[0] == '$' && !noexpr) { - if (dump_cell_expr(f, indent, cell)) - return; - } - - dump_attributes(f, indent, cell->attributes); - f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str()); - - if (!defparam && cell->parameters.size() > 0) { - f << stringf(" #("); - for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { - if (it != cell->parameters.begin()) - f << stringf(","); - f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str()); - dump_const(f, it->second); - f << stringf(")"); - } - f << stringf("\n%s" ")", indent.c_str()); - } - - std::string cell_name = cellname(cell); - if (cell_name != id(cell->name)) - f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str()); - else - f << stringf(" %s (", cell_name.c_str()); - - bool first_arg = true; - std::set numbered_ports; - for (int i = 1; true; i++) { - char str[16]; - snprintf(str, 16, "$%d", i); - for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { - if (it->first != str) - continue; - if (!first_arg) - f << stringf(","); - first_arg = false; - f << stringf("\n%s ", indent.c_str()); - dump_sigspec(f, it->second); - numbered_ports.insert(it->first); - goto found_numbered_port; - } - break; - found_numbered_port:; - } - for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { - if (numbered_ports.count(it->first)) - continue; - if (!first_arg) - f << stringf(","); - first_arg = false; - f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str()); - if (it->second.size() > 0) - dump_sigspec(f, it->second); - f << stringf(")"); - } - f << stringf("\n%s" ");\n", indent.c_str()); - - if (defparam && cell->parameters.size() > 0) { - for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { - f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); - dump_const(f, it->second); - f << stringf(";\n"); - } - } - - if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) { - std::stringstream ss; - dump_reg_init(ss, cell->getPort("\\Q")); - if (!ss.str().empty()) { - f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str()); - f << ss.str(); - f << ";\n"; - } - } -} - -void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) -{ - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, left); - f << stringf(" = "); - dump_sigspec(f, right); - f << stringf(";\n"); -} - -void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw); - -void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false) -{ - int number_of_stmts = cs->switches.size() + cs->actions.size(); - - if (!omit_trailing_begin && number_of_stmts >= 2) - f << stringf("%s" "begin\n", indent.c_str()); - - for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) { - if (it->first.size() == 0) - continue; - f << stringf("%s ", indent.c_str()); - dump_sigspec(f, it->first); - f << stringf(" = "); - dump_sigspec(f, it->second); - f << stringf(";\n"); - } - - for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it) - dump_proc_switch(f, indent + " ", *it); - - if (!omit_trailing_begin && number_of_stmts == 0) - f << stringf("%s /* empty */;\n", indent.c_str()); - - if (omit_trailing_begin || number_of_stmts >= 2) - f << stringf("%s" "end\n", indent.c_str()); -} - -void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw) -{ - if (sw->signal.size() == 0) { - f << stringf("%s" "begin\n", indent.c_str()); - for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { - if ((*it)->compare.size() == 0) - dump_case_body(f, indent + " ", *it); - } - f << stringf("%s" "end\n", indent.c_str()); - return; - } - - dump_attributes(f, indent, sw->attributes); - f << stringf("%s" "casez (", indent.c_str()); - dump_sigspec(f, sw->signal); - f << stringf(")\n"); - - bool got_default = false; - for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) { - dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*as_comment=*/true); - if ((*it)->compare.size() == 0) { - if (got_default) - continue; - f << stringf("%s default", indent.c_str()); - got_default = true; - } else { - f << stringf("%s ", indent.c_str()); - for (size_t i = 0; i < (*it)->compare.size(); i++) { - if (i > 0) - f << stringf(", "); - dump_sigspec(f, (*it)->compare[i]); - } - } - f << stringf(":\n"); - dump_case_body(f, indent + " ", *it); - } - - f << stringf("%s" "endcase\n", indent.c_str()); -} - -void case_body_find_regs(RTLIL::CaseRule *cs) -{ - for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it) - for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++) - case_body_find_regs(*it2); - - for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) { - for (auto &c : it->first.chunks()) - if (c.wire != NULL) - reg_wires.insert(c.wire->name); - } -} - -void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false) -{ - if (find_regs) { - case_body_find_regs(&proc->root_case); - for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it) - for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) { - for (auto &c : it2->first.chunks()) - if (c.wire != NULL) - reg_wires.insert(c.wire->name); - } - return; - } - - f << stringf("%s" "always @* begin\n", indent.c_str()); - dump_case_body(f, indent, &proc->root_case, true); - - std::string backup_indent = indent; - - for (size_t i = 0; i < proc->syncs.size(); i++) - { - RTLIL::SyncRule *sync = proc->syncs[i]; - indent = backup_indent; - - if (sync->type == RTLIL::STa) { - f << stringf("%s" "always @* begin\n", indent.c_str()); - } else if (sync->type == RTLIL::STi) { - f << stringf("%s" "initial begin\n", indent.c_str()); - } else { - f << stringf("%s" "always @(", indent.c_str()); - if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1) - f << stringf("posedge "); - if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0) - f << stringf("negedge "); - dump_sigspec(f, sync->signal); - f << stringf(") begin\n"); - } - std::string ends = indent + "end\n"; - indent += " "; - - if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) { - f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : ""); - dump_sigspec(f, sync->signal); - f << stringf(") begin\n"); - ends = indent + "end\n" + ends; - indent += " "; - } - - if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) { - for (size_t j = 0; j < proc->syncs.size(); j++) { - RTLIL::SyncRule *sync2 = proc->syncs[j]; - if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) { - f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : ""); - dump_sigspec(f, sync2->signal); - f << stringf(") begin\n"); - ends = indent + "end\n" + ends; - indent += " "; - } - } - } - - for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) { - if (it->first.size() == 0) - continue; - f << stringf("%s ", indent.c_str()); - dump_sigspec(f, it->first); - f << stringf(" <= "); - dump_sigspec(f, it->second); - f << stringf(";\n"); - } - - f << stringf("%s", ends.c_str()); - } -} - -void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) -{ - reg_wires.clear(); - reset_auto_counter(module); - active_module = module; - active_sigmap.set(module); - active_initdata.clear(); - - for (auto wire : module->wires()) - if (wire->attributes.count("\\init")) { - SigSpec sig = active_sigmap(wire); - Const val = wire->attributes.at("\\init"); - for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++) - if (val[i] == State::S0 || val[i] == State::S1) - active_initdata[sig[i]] = val[i]; - } - - if (!module->processes.empty()) - log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n" - "can't always be mapped directly to Verilog always blocks. Unintended\n" - "changes in simulation behavior are possible! Use \"proc\" to convert\n" - "processes to logic networks and registers.\n", log_id(module)); - - f << stringf("\n"); - for (auto it = module->processes.begin(); it != module->processes.end(); ++it) - dump_process(f, indent + " ", it->second, true); - - if (!noexpr) - { - std::set> reg_bits; - for (auto &it : module->cells_) - { - RTLIL::Cell *cell = it.second; - if (!reg_ct.count(cell->type) || !cell->hasPort("\\Q")) - continue; - - RTLIL::SigSpec sig = cell->getPort("\\Q"); - - if (sig.is_chunk()) { - RTLIL::SigChunk chunk = sig.as_chunk(); - if (chunk.wire != NULL) - for (int i = 0; i < chunk.width; i++) - reg_bits.insert(std::pair(chunk.wire, chunk.offset+i)); - } - } - for (auto &it : module->wires_) - { - RTLIL::Wire *wire = it.second; - for (int i = 0; i < wire->width; i++) - if (reg_bits.count(std::pair(wire, i)) == 0) - goto this_wire_aint_reg; - if (wire->width) - reg_wires.insert(wire->name); - this_wire_aint_reg:; - } - } - - dump_attributes(f, indent, module->attributes, '\n', /*attr2comment=*/true); - f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str()); - bool keep_running = true; - for (int port_id = 1; keep_running; port_id++) { - keep_running = false; - for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) { - RTLIL::Wire *wire = it->second; - if (wire->port_id == port_id) { - if (port_id != 1) - f << stringf(", "); - f << stringf("%s", id(wire->name).c_str()); - keep_running = true; - continue; - } - } - } - f << stringf(");\n"); - - for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) - dump_wire(f, indent + " ", it->second); - - for (auto it = module->memories.begin(); it != module->memories.end(); ++it) - dump_memory(f, indent + " ", it->second); - - for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) - dump_cell(f, indent + " ", it->second); - - for (auto it = module->processes.begin(); it != module->processes.end(); ++it) - dump_process(f, indent + " ", it->second); - - for (auto it = module->connections().begin(); it != module->connections().end(); ++it) - dump_conn(f, indent + " ", it->first, it->second); - - f << stringf("%s" "endmodule\n", indent.c_str()); - active_module = NULL; - active_sigmap.clear(); - active_initdata.clear(); -} - -struct VerilogBackend : public Backend { - VerilogBackend() : Backend("verilog", "write design to Verilog file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_verilog [options] [filename]\n"); - log("\n"); - log("Write the current design to a Verilog file.\n"); - log("\n"); - log(" -norename\n"); - log(" without this option all internal object names (the ones with a dollar\n"); - log(" instead of a backslash prefix) are changed to short names in the\n"); - log(" format '__'.\n"); - log("\n"); - log(" -renameprefix \n"); - log(" insert this prefix in front of auto-generated instance names\n"); - log("\n"); - log(" -noattr\n"); - log(" with this option no attributes are included in the output\n"); - log("\n"); - log(" -attr2comment\n"); - log(" with this option attributes are included as comments in the output\n"); - log("\n"); - log(" -noexpr\n"); - log(" without this option all internal cells are converted to Verilog\n"); - log(" expressions.\n"); - log("\n"); - log(" -siminit\n"); - log(" add initial statements with hierarchical refs to initialize FFs when\n"); - log(" in -noexpr mode.\n"); - log("\n"); - log(" -nodec\n"); - log(" 32-bit constant values are by default dumped as decimal numbers,\n"); - log(" not bit pattern. This option deactivates this feature and instead\n"); - log(" will write out all constants in binary.\n"); - log("\n"); - log(" -decimal\n"); - log(" dump 32-bit constants in decimal and without size and radix\n"); - log("\n"); - log(" -nohex\n"); - log(" constant values that are compatible with hex output are usually\n"); - log(" dumped as hex values. This option deactivates this feature and\n"); - log(" instead will write out all constants in binary.\n"); - log("\n"); - log(" -nostr\n"); - log(" Parameters and attributes that are specified as strings in the\n"); - log(" original input will be output as strings by this back-end. This\n"); - log(" deactivates this feature and instead will write string constants\n"); - log(" as binary numbers.\n"); - log("\n"); - log(" -defparam\n"); - log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n"); - log(" cell parameters.\n"); - log("\n"); - log(" -blackboxes\n"); - log(" usually modules with the 'blackbox' attribute are ignored. with\n"); - log(" this option set only the modules with the 'blackbox' attribute\n"); - log(" are written to the output file.\n"); - log("\n"); - log(" -selected\n"); - log(" only write selected modules. modules must be selected entirely or\n"); - log(" not at all.\n"); - log("\n"); - log(" -v\n"); - log(" verbose output (print new names of all renamed wires and cells)\n"); - log("\n"); - log("Note that RTLIL processes can't always be mapped directly to Verilog\n"); - log("always blocks. This frontend should only be used to export an RTLIL\n"); - log("netlist, i.e. after the \"proc\" pass has been used to convert all\n"); - log("processes to logic networks and registers. A warning is generated when\n"); - log("this command is called on a design with RTLIL processes.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing Verilog backend.\n"); - - verbose = false; - norename = false; - noattr = false; - attr2comment = false; - noexpr = false; - nodec = false; - nohex = false; - nostr = false; - defparam = false; - decimal = false; - siminit = false; - auto_prefix = ""; - - bool blackboxes = false; - bool selected = false; - - auto_name_map.clear(); - reg_wires.clear(); - reg_ct.clear(); - - reg_ct.insert("$dff"); - reg_ct.insert("$adff"); - reg_ct.insert("$dffe"); - reg_ct.insert("$dlatch"); - - reg_ct.insert("$_DFF_N_"); - reg_ct.insert("$_DFF_P_"); - - reg_ct.insert("$_DFF_NN0_"); - reg_ct.insert("$_DFF_NN1_"); - reg_ct.insert("$_DFF_NP0_"); - reg_ct.insert("$_DFF_NP1_"); - reg_ct.insert("$_DFF_PN0_"); - reg_ct.insert("$_DFF_PN1_"); - reg_ct.insert("$_DFF_PP0_"); - reg_ct.insert("$_DFF_PP1_"); - - reg_ct.insert("$_DFFSR_NNN_"); - reg_ct.insert("$_DFFSR_NNP_"); - reg_ct.insert("$_DFFSR_NPN_"); - reg_ct.insert("$_DFFSR_NPP_"); - reg_ct.insert("$_DFFSR_PNN_"); - reg_ct.insert("$_DFFSR_PNP_"); - reg_ct.insert("$_DFFSR_PPN_"); - reg_ct.insert("$_DFFSR_PPP_"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-norename") { - norename = true; - continue; - } - if (arg == "-renameprefix" && argidx+1 < args.size()) { - auto_prefix = args[++argidx]; - continue; - } - if (arg == "-noattr") { - noattr = true; - continue; - } - if (arg == "-attr2comment") { - attr2comment = true; - continue; - } - if (arg == "-noexpr") { - noexpr = true; - continue; - } - if (arg == "-nodec") { - nodec = true; - continue; - } - if (arg == "-nohex") { - nohex = true; - continue; - } - if (arg == "-nostr") { - nostr = true; - continue; - } - if (arg == "-defparam") { - defparam = true; - continue; - } - if (arg == "-decimal") { - decimal = true; - continue; - } - if (arg == "-siminit") { - siminit = true; - continue; - } - if (arg == "-blackboxes") { - blackboxes = true; - continue; - } - if (arg == "-selected") { - selected = true; - continue; - } - if (arg == "-v") { - verbose = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - design->sort(); - - *f << stringf("/* Generated by %s */\n", yosys_version_str); - for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) { - if (it->second->get_blackbox_attribute() != blackboxes) - continue; - if (selected && !design->selected_whole_module(it->first)) { - if (design->selected_module(it->first)) - log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it->first)); - continue; - } - log("Dumping module `%s'.\n", it->first.c_str()); - dump_module(*f, "", it->second); - } - - auto_name_map.clear(); - reg_wires.clear(); - reg_ct.clear(); - } -} VerilogBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/examples/aiger/.gitignore b/yosys/examples/aiger/.gitignore deleted file mode 100644 index 3524e9362..000000000 --- a/yosys/examples/aiger/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -demo.aig -demo.aim -demo.aiw -demo.smt2 -demo.vcd diff --git a/yosys/examples/aiger/README b/yosys/examples/aiger/README deleted file mode 100644 index 4e7694e95..000000000 --- a/yosys/examples/aiger/README +++ /dev/null @@ -1,22 +0,0 @@ -AIGER is a format for And-Inverter Graphs (AIGs). -See http://fmv.jku.at/aiger/ for details. - -AIGER is used in the Hardware Model Checking Competition (HWMCC), -therefore all solvers competing in the competition have to support -the format. - -The example in this directory is using super_prove as solver. Check -http://downloads.bvsrc.org/super_prove/ for the lates release. (See -https://bitbucket.org/sterin/super_prove_build for sources.) - -The "demo.sh" script in this directory expects a "super_prove" executable -in the PATH. E.g. extract the release to /usr/local/libexec/super_prove -and then create a /usr/local/bin/super_prove file with the following -contents (and "chmod +x" that file): - - #!/bin/bash - exec /usr/local/libexec/super_prove/bin/super_prove.sh "$@" - -The "demo.sh" script also expects the "z3" SMT2 solver in the PATH for -converting the witness file generated by super_prove to VCD using -yosys-smtbmc. See https://github.com/Z3Prover/z3 for install notes. diff --git a/yosys/examples/aiger/demo.sh b/yosys/examples/aiger/demo.sh deleted file mode 100644 index 8728b6722..000000000 --- a/yosys/examples/aiger/demo.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -set -ex -yosys -p ' - read_verilog -formal demo.v - prep -flatten -nordff -top demo - write_smt2 -wires demo.smt2 - flatten demo; delete -output - memory_map; opt -full - techmap; opt -fast - abc -fast -g AND; opt_clean - write_aiger -map demo.aim demo.aig -' -super_prove demo.aig > demo.aiw -yosys-smtbmc --dump-vcd demo.vcd --aig demo demo.smt2 diff --git a/yosys/examples/aiger/demo.v b/yosys/examples/aiger/demo.v deleted file mode 100644 index b98287424..000000000 --- a/yosys/examples/aiger/demo.v +++ /dev/null @@ -1,12 +0,0 @@ -module demo(input clk, reset, ctrl); - localparam NBITS = 10; - reg [NBITS-1:0] counter; - initial counter[NBITS-2] = 0; - initial counter[0] = 1; - always @(posedge clk) begin - counter <= reset ? 1 : ctrl ? counter + 1 : counter - 1; - assume(counter != 0); - assume(counter != 1 << (NBITS-1)); - assert(counter != (1 << NBITS)-1); - end -endmodule diff --git a/yosys/examples/anlogic/.gitignore b/yosys/examples/anlogic/.gitignore deleted file mode 100644 index 97c978a15..000000000 --- a/yosys/examples/anlogic/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -demo.bit -demo_phy.area -full.v -*.log -*.h -*.tde -*.svf diff --git a/yosys/examples/anlogic/README b/yosys/examples/anlogic/README deleted file mode 100644 index 35d8e9cb1..000000000 --- a/yosys/examples/anlogic/README +++ /dev/null @@ -1,12 +0,0 @@ -LED Blink project for Anlogic Lichee Tang board. - -Follow the install instructions for the Tang Dynasty IDE from given link below. - -https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/ - - -set TD_HOME env variable to the full path to the TD as follow. - -export TD_HOME= - -then run "bash build.sh" in this directory. diff --git a/yosys/examples/anlogic/build.sh b/yosys/examples/anlogic/build.sh deleted file mode 100755 index e0f6b4cfe..000000000 --- a/yosys/examples/anlogic/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -ex -yosys demo.ys -$TD_HOME/bin/td build.tcl diff --git a/yosys/examples/anlogic/build.tcl b/yosys/examples/anlogic/build.tcl deleted file mode 100644 index 06db525c9..000000000 --- a/yosys/examples/anlogic/build.tcl +++ /dev/null @@ -1,11 +0,0 @@ -import_device eagle_s20.db -package BG256 -read_verilog full.v -top demo -read_adc demo.adc -optimize_rtl -map_macro -map -pack -place -route -report_area -io_info -file demo_phy.area -bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000 diff --git a/yosys/examples/anlogic/demo.adc b/yosys/examples/anlogic/demo.adc deleted file mode 100644 index ec802502e..000000000 --- a/yosys/examples/anlogic/demo.adc +++ /dev/null @@ -1,2 +0,0 @@ -set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ -set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED diff --git a/yosys/examples/anlogic/demo.v b/yosys/examples/anlogic/demo.v deleted file mode 100644 index e17db771e..000000000 --- a/yosys/examples/anlogic/demo.v +++ /dev/null @@ -1,18 +0,0 @@ -module demo ( - input wire CLK_IN, - output wire R_LED -); - parameter time1 = 30'd12_000_000; - reg led_state; - reg [29:0] count; - - always @(posedge CLK_IN)begin - if(count == time1)begin - count<= 30'd0; - led_state <= ~led_state; - end - else - count <= count + 1'b1; - end - assign R_LED = led_state; -endmodule diff --git a/yosys/examples/anlogic/demo.ys b/yosys/examples/anlogic/demo.ys deleted file mode 100644 index cb396cc2b..000000000 --- a/yosys/examples/anlogic/demo.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog demo.v -synth_anlogic -top demo -write_verilog full.v diff --git a/yosys/examples/basys3/README b/yosys/examples/basys3/README deleted file mode 100644 index 0ce717294..000000000 --- a/yosys/examples/basys3/README +++ /dev/null @@ -1,19 +0,0 @@ - -A simple example design, based on the Digilent BASYS3 board -=========================================================== - -This example uses Yosys for synthesis and Xilinx Vivado -for place&route and bit-stream creation. - -Running Yosys: - yosys run_yosys.ys - -Running Vivado: - vivado -nolog -nojournal -mode batch -source run_vivado.tcl - -Programming board: - vivado -nolog -nojournal -mode batch -source run_prog.tcl - -All of the above: - bash run.sh - diff --git a/yosys/examples/basys3/example.v b/yosys/examples/basys3/example.v deleted file mode 100644 index 2b01a22a8..000000000 --- a/yosys/examples/basys3/example.v +++ /dev/null @@ -1,21 +0,0 @@ -module example(CLK, LD); - input CLK; - output [15:0] LD; - - wire clock; - reg [15:0] leds; - - BUFG CLK_BUF (.I(CLK), .O(clock)); - OBUF LD_BUF[15:0] (.I(leds), .O(LD)); - - parameter COUNTBITS = 26; - reg [COUNTBITS-1:0] counter; - - always @(posedge CLK) begin - counter <= counter + 1; - if (counter[COUNTBITS-1]) - leds <= 16'h8000 >> counter[COUNTBITS-2:COUNTBITS-5]; - else - leds <= 16'h0001 << counter[COUNTBITS-2:COUNTBITS-5]; - end -endmodule diff --git a/yosys/examples/basys3/example.xdc b/yosys/examples/basys3/example.xdc deleted file mode 100644 index 8cdaa1996..000000000 --- a/yosys/examples/basys3/example.xdc +++ /dev/null @@ -1,24 +0,0 @@ - -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W5 } [get_ports CLK] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U16 } [get_ports {LD[0]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN E19 } [get_ports {LD[1]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U19 } [get_ports {LD[2]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V19 } [get_ports {LD[3]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W18 } [get_ports {LD[4]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U15 } [get_ports {LD[5]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U14 } [get_ports {LD[6]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V14 } [get_ports {LD[7]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V13 } [get_ports {LD[8]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V3 } [get_ports {LD[9]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W3 } [get_ports {LD[10]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U3 } [get_ports {LD[11]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN P3 } [get_ports {LD[12]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN N3 } [get_ports {LD[13]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN P1 } [get_ports {LD[14]}] -set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN L1 } [get_ports {LD[15]}] - -create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports CLK] - -set_property CONFIG_VOLTAGE 3.3 [current_design] -set_property CFGBVS VCCO [current_design] - diff --git a/yosys/examples/basys3/run.sh b/yosys/examples/basys3/run.sh deleted file mode 100644 index 10f059103..000000000 --- a/yosys/examples/basys3/run.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -yosys run_yosys.ys -vivado -nolog -nojournal -mode batch -source run_vivado.tcl -vivado -nolog -nojournal -mode batch -source run_prog.tcl diff --git a/yosys/examples/basys3/run_prog.tcl b/yosys/examples/basys3/run_prog.tcl deleted file mode 100644 index b078ad511..000000000 --- a/yosys/examples/basys3/run_prog.tcl +++ /dev/null @@ -1,5 +0,0 @@ -open_hw -connect_hw_server -open_hw_target [lindex [get_hw_targets] 0] -set_property PROGRAM.FILE example.bit [lindex [get_hw_devices] 0] -program_hw_devices [lindex [get_hw_devices] 0] diff --git a/yosys/examples/basys3/run_vivado.tcl b/yosys/examples/basys3/run_vivado.tcl deleted file mode 100644 index c3b6a610e..000000000 --- a/yosys/examples/basys3/run_vivado.tcl +++ /dev/null @@ -1,9 +0,0 @@ -read_xdc example.xdc -read_edif example.edif -link_design -part xc7a35tcpg236-1 -top example -opt_design -place_design -route_design -report_utilization -report_timing -write_bitstream -force example.bit diff --git a/yosys/examples/basys3/run_yosys.ys b/yosys/examples/basys3/run_yosys.ys deleted file mode 100644 index 4541826d3..000000000 --- a/yosys/examples/basys3/run_yosys.ys +++ /dev/null @@ -1,2 +0,0 @@ -read_verilog example.v -synth_xilinx -edif example.edif -top example diff --git a/yosys/examples/cmos/.gitignore b/yosys/examples/cmos/.gitignore deleted file mode 100644 index f58d95018..000000000 --- a/yosys/examples/cmos/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -counter_tb -counter_tb.vcd -synth.sp -synth.v diff --git a/yosys/examples/cmos/README b/yosys/examples/cmos/README deleted file mode 100644 index c459b4b54..000000000 --- a/yosys/examples/cmos/README +++ /dev/null @@ -1,13 +0,0 @@ - -In this directory contains an example for generating a spice output using two -different spice modes, normal analog transient simulation and event-driven -digital simulation as supported by ngspice xspice sub-module. - -Each test bench can be run separately by either running: - -- testbench.sh, to start analog simulation or -- testbench_digital.sh for mixed-signal digital simulation. - -The later case also includes pure verilog simulation using the iverilog -and gtkwave for comparison. - diff --git a/yosys/examples/cmos/cmos_cells.lib b/yosys/examples/cmos/cmos_cells.lib deleted file mode 100644 index 1b0bf8457..000000000 --- a/yosys/examples/cmos/cmos_cells.lib +++ /dev/null @@ -1,55 +0,0 @@ -// test comment -/* test comment */ -library(demo) { - cell(BUF) { - area: 6; - pin(A) { direction: input; } - pin(Y) { direction: output; - function: "A"; } - } - cell(NOT) { - area: 3; - pin(A) { direction: input; } - pin(Y) { direction: output; - function: "A'"; } - } - cell(NAND) { - area: 4; - pin(A) { direction: input; } - pin(B) { direction: input; } - pin(Y) { direction: output; - function: "(A*B)'"; } - } - cell(NOR) { - area: 4; - pin(A) { direction: input; } - pin(B) { direction: input; } - pin(Y) { direction: output; - function: "(A+B)'"; } - } - cell(DFF) { - area: 18; - ff(IQ, IQN) { clocked_on: C; - next_state: D; } - pin(C) { direction: input; - clock: true; } - pin(D) { direction: input; } - pin(Q) { direction: output; - function: "IQ"; } - } - cell(DFFSR) { - area: 18; - ff("IQ", "IQN") { clocked_on: C; - next_state: D; - preset: S; - clear: R; } - pin(C) { direction: input; - clock: true; } - pin(D) { direction: input; } - pin(Q) { direction: output; - function: "IQ"; } - pin(S) { direction: input; } - pin(R) { direction: input; } - ; // empty statement - } -} diff --git a/yosys/examples/cmos/cmos_cells.sp b/yosys/examples/cmos/cmos_cells.sp deleted file mode 100644 index 673b20d08..000000000 --- a/yosys/examples/cmos/cmos_cells.sp +++ /dev/null @@ -1,39 +0,0 @@ - -.SUBCKT BUF A Y -X1 A B NOT -X2 B Y NOT -.ENDS NOT - -.SUBCKT NOT A Y -M1 Y A Vdd Vdd cmosp L=1u W=10u -M2 Y A Vss Vss cmosn L=1u W=10u -.ENDS NOT - -.SUBCKT NAND A B Y -M1 Y A Vdd Vdd cmosp L=1u W=10u -M2 Y B Vdd Vdd cmosp L=1u W=10u -M3 Y A M34 Vss cmosn L=1u W=10u -M4 M34 B Vss Vss cmosn L=1u W=10u -.ENDS NAND - -.SUBCKT NOR A B Y -M1 Y A M12 Vdd cmosp L=1u W=10u -M2 M12 B Vdd Vdd cmosp L=1u W=10u -M3 Y A Vss Vss cmosn L=1u W=10u -M4 Y B Vss Vss cmosn L=1u W=10u -.ENDS NOR - -.SUBCKT DLATCH E D Q -X1 D E S NAND -X2 nD E R NAND -X3 S nQ Q NAND -X4 Q R nQ NAND -X5 D nD NOT -.ENDS DLATCH - -.SUBCKT DFF C D Q -X1 nC D t DLATCH -X2 C t Q DLATCH -X3 C nC NOT -.ENDS DFF - diff --git a/yosys/examples/cmos/cmos_cells.v b/yosys/examples/cmos/cmos_cells.v deleted file mode 100644 index 27278facb..000000000 --- a/yosys/examples/cmos/cmos_cells.v +++ /dev/null @@ -1,44 +0,0 @@ - -module BUF(A, Y); -input A; -output Y; -assign Y = A; -endmodule - -module NOT(A, Y); -input A; -output Y; -assign Y = ~A; -endmodule - -module NAND(A, B, Y); -input A, B; -output Y; -assign Y = ~(A & B); -endmodule - -module NOR(A, B, Y); -input A, B; -output Y; -assign Y = ~(A | B); -endmodule - -module DFF(C, D, Q); -input C, D; -output reg Q; -always @(posedge C) - Q <= D; -endmodule - -module DFFSR(C, D, Q, S, R); -input C, D, S, R; -output reg Q; -always @(posedge C, posedge S, posedge R) - if (S) - Q <= 1'b1; - else if (R) - Q <= 1'b0; - else - Q <= D; -endmodule - diff --git a/yosys/examples/cmos/cmos_cells_digital.sp b/yosys/examples/cmos/cmos_cells_digital.sp deleted file mode 100644 index e1cb82a2f..000000000 --- a/yosys/examples/cmos/cmos_cells_digital.sp +++ /dev/null @@ -1,31 +0,0 @@ - -.SUBCKT BUF A Y -.model buffer1 d_buffer -Abuf A Y buffer1 -.ENDS NOT - -.SUBCKT NOT A Y -.model not1 d_inverter -Anot A Y not1 -.ENDS NOT - -.SUBCKT NAND A B Y -.model nand1 d_nand -Anand [A B] Y nand1 -.ENDS NAND - -.SUBCKT NOR A B Y -.model nor1 d_nor -Anand [A B] Y nor1 -.ENDS NOR - -.SUBCKT DLATCH E D Q -.model latch1 d_latch -Alatch D E null null Q nQ latch1 -.ENDS DLATCH - -.SUBCKT DFF C D Q -.model dff1 d_dff -Adff D C null null Q nQ dff1 -.ENDS DFF - diff --git a/yosys/examples/cmos/counter.v b/yosys/examples/cmos/counter.v deleted file mode 100644 index f21658724..000000000 --- a/yosys/examples/cmos/counter.v +++ /dev/null @@ -1,12 +0,0 @@ -module counter (clk, rst, en, count); - - input clk, rst, en; - output reg [2:0] count; - - always @(posedge clk) - if (rst) - count <= 3'd0; - else if (en) - count <= count + 3'd1; - -endmodule diff --git a/yosys/examples/cmos/counter.ys b/yosys/examples/cmos/counter.ys deleted file mode 100644 index d0b093667..000000000 --- a/yosys/examples/cmos/counter.ys +++ /dev/null @@ -1,16 +0,0 @@ -read_verilog counter.v -read_verilog -lib cmos_cells.v - -synth -dfflibmap -liberty cmos_cells.lib -abc -liberty cmos_cells.lib -opt_clean - -stat -liberty cmos_cells.lib - -# http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib -# dfflibmap -liberty osu025_stdcells.lib -# abc -liberty osu025_stdcells.lib;; - -write_verilog synth.v -write_spice synth.sp diff --git a/yosys/examples/cmos/counter_digital.ys b/yosys/examples/cmos/counter_digital.ys deleted file mode 100644 index a5e728e02..000000000 --- a/yosys/examples/cmos/counter_digital.ys +++ /dev/null @@ -1,16 +0,0 @@ - -read_verilog counter.v -read_verilog -lib cmos_cells.v - -proc;; memory;; techmap;; - -dfflibmap -liberty cmos_cells.lib -abc -liberty cmos_cells.lib;; - -# http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib -# dfflibmap -liberty osu025_stdcells.lib -# abc -liberty osu025_stdcells.lib;; - -write_verilog synth.v -write_spice -neg 0s -pos 1s synth.sp - diff --git a/yosys/examples/cmos/counter_tb.gtkw b/yosys/examples/cmos/counter_tb.gtkw deleted file mode 100644 index 4a2eac400..000000000 --- a/yosys/examples/cmos/counter_tb.gtkw +++ /dev/null @@ -1,5 +0,0 @@ -[dumpfile] "counter_tb.vcd" -counter_tb.clk -counter_tb.count[2:0] -counter_tb.en -counter_tb.reset diff --git a/yosys/examples/cmos/counter_tb.v b/yosys/examples/cmos/counter_tb.v deleted file mode 100644 index 11e82507e..000000000 --- a/yosys/examples/cmos/counter_tb.v +++ /dev/null @@ -1,33 +0,0 @@ -module counter_tb; - - /* Make a reset pulse and specify dump file */ - reg reset = 0; - initial begin - $dumpfile("counter_tb.vcd"); - $dumpvars(0,counter_tb); - - # 0 reset = 1; - # 4 reset = 0; - # 36 reset = 1; - # 4 reset = 0; - # 6 $finish; - end - - /* Make enable with period of 8 and 6,7 low */ - reg en = 1; - always begin - en = 1; - #6; - en = 0; - #2; - end - - /* Make a regular pulsing clock. */ - reg clk = 0; - always #1 clk = !clk; - - /* UUT */ - wire [2:0] count; - counter c1 (clk, reset, en, count); - -endmodule diff --git a/yosys/examples/cmos/testbench.sh b/yosys/examples/cmos/testbench.sh deleted file mode 100644 index 061704b64..000000000 --- a/yosys/examples/cmos/testbench.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -ex - -../../yosys counter.ys -ngspice testbench.sp - diff --git a/yosys/examples/cmos/testbench.sp b/yosys/examples/cmos/testbench.sp deleted file mode 100644 index e571d2815..000000000 --- a/yosys/examples/cmos/testbench.sp +++ /dev/null @@ -1,29 +0,0 @@ - -* supply voltages -.global Vss Vdd -Vss Vss 0 DC 0 -Vdd Vdd 0 DC 3 - -* simple transistor model -.MODEL cmosn NMOS LEVEL=1 VT0=0.7 KP=110U GAMMA=0.4 LAMBDA=0.04 PHI=0.7 -.MODEL cmosp PMOS LEVEL=1 VT0=-0.7 KP=50U GAMMA=0.57 LAMBDA=0.05 PHI=0.8 - -* load design and library -.include cmos_cells.sp -.include synth.sp - -* input signals -Vclk clk 0 PULSE(0 3 1 0.1 0.1 0.8 2) -Vrst rst 0 PULSE(0 3 0.5 0.1 0.1 2.9 40) -Ven en 0 PULSE(0 3 0.5 0.1 0.1 5.9 8) - -Xuut clk rst en out0 out1 out2 COUNTER - -.tran 0.01 50 - -.control -run -plot v(clk) v(rst)+5 v(en)+10 v(out0)+20 v(out1)+25 v(out2)+30 -.endc - -.end diff --git a/yosys/examples/cmos/testbench_digital.sh b/yosys/examples/cmos/testbench_digital.sh deleted file mode 100644 index d7ab0fe1f..000000000 --- a/yosys/examples/cmos/testbench_digital.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -ex - -# iverlog simulation -echo "Doing Verilog simulation with iverilog" -iverilog -o counter_tb counter.v counter_tb.v -./counter_tb; gtkwave counter_tb.gtkw & - -# yosys synthesis -../../yosys counter_digital.ys - -# requires ngspice with xspice support enabled: -ngspice testbench_digital.sp - diff --git a/yosys/examples/cmos/testbench_digital.sp b/yosys/examples/cmos/testbench_digital.sp deleted file mode 100644 index c5f9d5987..000000000 --- a/yosys/examples/cmos/testbench_digital.sp +++ /dev/null @@ -1,26 +0,0 @@ - -* load design and library -.include cmos_cells_digital.sp -.include synth.sp - -* input signals -Vclk clk 0 PULSE(0 3 1 0.1 0.1 0.8 2) -Vrst rst 0 PULSE(0 3 0.5 0.1 0.1 2.9 40) -Ven en 0 PULSE(0 3 0.5 0.1 0.1 5.9 8) - -Xuut dclk drst den dout0 dout1 dout2 counter -* Bridge to digital -.model adc_buff adc_bridge(in_low = 0.8 in_high=2) -.model dac_buff dac_bridge(out_high = 3.5) -Aad [clk rst en] [dclk drst den] adc_buff -Ada [dout0 dout1 dout2] [out0 out1 out2] dac_buff - - -.tran 0.01 50 - -.control -run -plot v(clk) v(rst)+5 v(en)+10 v(out0)+20 v(out1)+25 v(out2)+30 -.endc - -.end diff --git a/yosys/examples/cxx-api/demomain.cc b/yosys/examples/cxx-api/demomain.cc deleted file mode 100644 index a64593306..000000000 --- a/yosys/examples/cxx-api/demomain.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Note: Set ENABLE_LIBYOSYS=1 in Makefile or Makefile.conf to build libyosys.so -// yosys-config --exec --cxx -o demomain --cxxflags --ldflags demomain.cc -lyosys -lstdc++ - -#include - -int main() -{ - Yosys::log_streams.push_back(&std::cout); - Yosys::log_error_stderr = true; - - Yosys::yosys_setup(); - Yosys::yosys_banner(); - - Yosys::run_pass("read_verilog example.v"); - Yosys::run_pass("synth -noabc"); - Yosys::run_pass("clean -purge"); - Yosys::run_pass("write_blif example.blif"); - - Yosys::yosys_shutdown(); - return 0; -} - diff --git a/yosys/examples/cxx-api/evaldemo.cc b/yosys/examples/cxx-api/evaldemo.cc deleted file mode 100644 index 34373487d..000000000 --- a/yosys/examples/cxx-api/evaldemo.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* A simple Yosys plugin. (Copy&paste from http://stackoverflow.com/questions/32093541/how-does-the-yosys-consteval-api-work) - -Usage example: - -$ cat > evaldemo.v <, Design *design) YS_OVERRIDE - { - Module *module = design->top_module(); - - if (module == nullptr) - log_error("No top module found!\n"); - - Wire *wire_a = module->wire("\\A"); - Wire *wire_y = module->wire("\\Y"); - - if (wire_a == nullptr) - log_error("No wire A found!\n"); - - if (wire_y == nullptr) - log_error("No wire Y found!\n"); - - ConstEval ce(module); - for (int v = 0; v < 4; v++) { - ce.push(); - ce.set(wire_a, Const(v, GetSize(wire_a))); - SigSpec sig_y = wire_y, sig_undef; - if (ce.eval(sig_y, sig_undef)) - log("Eval results for A=%d: Y=%s\n", v, log_signal(sig_y)); - else - log("Eval failed for A=%d: Missing value for %s\n", v, log_signal(sig_undef)); - ce.pop(); - } - } -} EvalDemoPass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/examples/gowin/.gitignore b/yosys/examples/gowin/.gitignore deleted file mode 100644 index 71030bdb8..000000000 --- a/yosys/examples/gowin/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -demo.bit -demo.out -demo.rpt -demo_syn.v -demo_out.v -demo_tr.html -testbench -testbench.vcd diff --git a/yosys/examples/gowin/README b/yosys/examples/gowin/README deleted file mode 100644 index 0194e9f09..000000000 --- a/yosys/examples/gowin/README +++ /dev/null @@ -1,17 +0,0 @@ -Simple test project for Gowinsemi GW2A-55K Eval Board Mini. - -Follow the install instructions for the Gowinsemi tools below, -then run "bash run.sh" in this directory. - - -Install instructions for gowinTool_linux ----------------------------------------- - -1.) extract gowinTool_linux.zip - -2.) set GOWIN_HOME env variable to the full path to the -gowinTool_linux directory - -3.) edit gowinTool_linux/bin/gwlicense.ini. Set lic="..." to -the full path to the license file. - diff --git a/yosys/examples/gowin/demo.cst b/yosys/examples/gowin/demo.cst deleted file mode 100644 index 22d7eb668..000000000 --- a/yosys/examples/gowin/demo.cst +++ /dev/null @@ -1,41 +0,0 @@ -// 50 MHz Clock -IO_LOC "clk" D11; - -// LEDs -IO_LOC "leds[0]" D22; -IO_LOC "leds[1]" E22; -IO_LOC "leds[2]" G22; -IO_LOC "leds[3]" J22; -IO_LOC "leds[4]" L22; -IO_LOC "leds[5]" L19; -IO_LOC "leds[6]" L20; -IO_LOC "leds[7]" M21; -IO_LOC "leds[8]" N19; -IO_LOC "leds[9]" R19; -IO_LOC "leds[10]" T18; -IO_LOC "leds[11]" AA22; -IO_LOC "leds[12]" U18; -IO_LOC "leds[13]" V20; -IO_LOC "leds[14]" AA21; -IO_LOC "leds[15]" AB21; - - -// 7-Segment Display -IO_LOC "seg7dig[0]" E20; -IO_LOC "seg7dig[1]" G18; -IO_LOC "seg7dig[2]" G20; -IO_LOC "seg7dig[3]" F21; -IO_LOC "seg7dig[4]" J20; -IO_LOC "seg7dig[5]" H21; -IO_LOC "seg7dig[6]" H18; -IO_LOC "seg7dig[7]" D20; -IO_LOC "seg7sel[0]" C19; -IO_LOC "seg7sel[1]" B22; -IO_LOC "seg7sel[2]" C20; -IO_LOC "seg7sel[3]" C21; - -// Switches -IO_LOC "sw[0]" AB20; -IO_LOC "sw[1]" AB19; -IO_LOC "sw[2]" AB18; -IO_LOC "sw[3]" AB17; diff --git a/yosys/examples/gowin/demo.sdc b/yosys/examples/gowin/demo.sdc deleted file mode 100644 index 6c90325fa..000000000 --- a/yosys/examples/gowin/demo.sdc +++ /dev/null @@ -1 +0,0 @@ -create_clock -name clk -period 20 -waveform {0 10} [get_ports {clk}] diff --git a/yosys/examples/gowin/demo.v b/yosys/examples/gowin/demo.v deleted file mode 100644 index 6ea108384..000000000 --- a/yosys/examples/gowin/demo.v +++ /dev/null @@ -1,12 +0,0 @@ -module demo ( - input clk, - input [3:0] sw, - output [15:0] leds, - output [7:0] seg7dig, - output [3:0] seg7sel -); - localparam PRESCALE = 20; - reg [PRESCALE+3:0] counter = 0; - always @(posedge clk) counter <= counter + 1; - assign leds = 1 << counter[PRESCALE +: 4]; -endmodule diff --git a/yosys/examples/gowin/run.sh b/yosys/examples/gowin/run.sh deleted file mode 100644 index 33a7b5c37..000000000 --- a/yosys/examples/gowin/run.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -ex -yosys -p "synth_gowin -top demo -vout demo_syn.v" demo.v -$GOWIN_HOME/bin/gowin -d demo_syn.v -cst demo.cst -sdc demo.sdc -p GW2A55-PBGA484-6 \ - -warning_all -out demo_out.v -rpt demo.rpt -tr demo_tr.html -bit demo.bit - -# post place&route simulation (icarus verilog) -if false; then - iverilog -D POST_IMPL -o testbench -s testbench testbench.v \ - demo_out.v $(yosys-config --datdir/gowin/cells_sim.v) - vvp -N testbench -fi diff --git a/yosys/examples/gowin/testbench.v b/yosys/examples/gowin/testbench.v deleted file mode 100644 index 6d206381e..000000000 --- a/yosys/examples/gowin/testbench.v +++ /dev/null @@ -1,40 +0,0 @@ -module testbench; - reg clk; - - initial begin - #5 clk = 0; - forever #5 clk = ~clk; - end - - wire [15:0] leds; - - initial begin - // $dumpfile("testbench.vcd"); - // $dumpvars(0, testbench); - $monitor("%b", leds); - end - - demo uut ( - .clk (clk ), -`ifdef POST_IMPL - .\leds[0] (leds[0]), - .\leds[1] (leds[1]), - .\leds[2] (leds[2]), - .\leds[3] (leds[3]), - .\leds[4] (leds[4]), - .\leds[5] (leds[5]), - .\leds[6] (leds[6]), - .\leds[7] (leds[7]), - .\leds[8] (leds[8]), - .\leds[9] (leds[9]), - .\leds[10] (leds[10]), - .\leds[11] (leds[11]), - .\leds[12] (leds[12]), - .\leds[13] (leds[13]), - .\leds[14] (leds[14]), - .\leds[15] (leds[15]) -`else - .leds(leds) -`endif - ); -endmodule diff --git a/yosys/examples/igloo2/.gitignore b/yosys/examples/igloo2/.gitignore deleted file mode 100644 index 33b7182d3..000000000 --- a/yosys/examples/igloo2/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/netlist.edn -/netlist.vm -/example.stp -/proj diff --git a/yosys/examples/igloo2/example.pdc b/yosys/examples/igloo2/example.pdc deleted file mode 100644 index 298d9e934..000000000 --- a/yosys/examples/igloo2/example.pdc +++ /dev/null @@ -1,20 +0,0 @@ -# Add placement constraints here - -set_io clk -pinname H16 -fixed yes -DIRECTION INPUT - -set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT -set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT - -set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT -set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT -set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT -set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT - -set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT -set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT -set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT -set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT -set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT -set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT -set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT -set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT diff --git a/yosys/examples/igloo2/example.sdc b/yosys/examples/igloo2/example.sdc deleted file mode 100644 index f8b487316..000000000 --- a/yosys/examples/igloo2/example.sdc +++ /dev/null @@ -1,2 +0,0 @@ -# Add timing constraints here -create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}] diff --git a/yosys/examples/igloo2/example.v b/yosys/examples/igloo2/example.v deleted file mode 100644 index 4a9486e50..000000000 --- a/yosys/examples/igloo2/example.v +++ /dev/null @@ -1,64 +0,0 @@ -module example ( - input clk, - input SW1, - input SW2, - output LED1, - output LED2, - output LED3, - output LED4, - - output AA, AB, AC, AD, - output AE, AF, AG, CA -); - - localparam BITS = 8; - localparam LOG2DELAY = 22; - - reg [BITS+LOG2DELAY-1:0] counter = 0; - reg [BITS-1:0] outcnt; - - always @(posedge clk) begin - counter <= counter + SW1 + SW2 + 1; - outcnt <= counter >> LOG2DELAY; - end - - assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1); - - // assign CA = counter[10]; - // seg7enc seg7encinst ( - // .seg({AA, AB, AC, AD, AE, AF, AG}), - // .dat(CA ? outcnt[3:0] : outcnt[7:4]) - // ); - - assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]); - assign CA = outcnt[7]; -endmodule - -module seg7enc ( - input [3:0] dat, - output [6:0] seg -); - reg [6:0] seg_inv; - always @* begin - seg_inv = 0; - case (dat) - 4'h0: seg_inv = 7'b 0111111; - 4'h1: seg_inv = 7'b 0000110; - 4'h2: seg_inv = 7'b 1011011; - 4'h3: seg_inv = 7'b 1001111; - 4'h4: seg_inv = 7'b 1100110; - 4'h5: seg_inv = 7'b 1101101; - 4'h6: seg_inv = 7'b 1111101; - 4'h7: seg_inv = 7'b 0000111; - 4'h8: seg_inv = 7'b 1111111; - 4'h9: seg_inv = 7'b 1101111; - 4'hA: seg_inv = 7'b 1110111; - 4'hB: seg_inv = 7'b 1111100; - 4'hC: seg_inv = 7'b 0111001; - 4'hD: seg_inv = 7'b 1011110; - 4'hE: seg_inv = 7'b 1111001; - 4'hF: seg_inv = 7'b 1110001; - endcase - end - assign seg = ~seg_inv; -endmodule diff --git a/yosys/examples/igloo2/libero.tcl b/yosys/examples/igloo2/libero.tcl deleted file mode 100644 index abc94e479..000000000 --- a/yosys/examples/igloo2/libero.tcl +++ /dev/null @@ -1,57 +0,0 @@ -# Run with "libero SCRIPT:libero.tcl" - -file delete -force proj - -new_project \ - -name example \ - -location proj \ - -block_mode 0 \ - -hdl "VERILOG" \ - -family IGLOO2 \ - -die PA4MGL2500 \ - -package vf256 \ - -speed -1 - -import_files -hdl_source {netlist.vm} -import_files -sdc {example.sdc} -import_files -io_pdc {example.pdc} -build_design_hierarchy -set_option -synth 0 - -organize_tool_files -tool PLACEROUTE \ - -file {proj/constraint/example.sdc} \ - -file {proj/constraint/io/example.pdc} \ - -input_type constraint - -organize_tool_files -tool VERIFYTIMING \ - -file {proj/constraint/example.sdc} \ - -input_type constraint - -configure_tool -name PLACEROUTE \ - -params TDPR:true \ - -params PDPR:false \ - -params EFFORT_LEVEL:false \ - -params REPAIR_MIN_DELAY:false - -puts "" -puts "**> COMPILE" -run_tool -name {COMPILE} -puts "<** COMPILE" - -puts "" -puts "**> PLACEROUTE" -run_tool -name {PLACEROUTE} -puts "<** PLACEROUTE" - -puts "" -puts "**> VERIFYTIMING" -run_tool -name {VERIFYTIMING} -puts "<** VERIFYTIMING" - -puts "" -puts "**> BITSTREAM" -export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC} -puts "<** BITSTREAM" - -puts "" -exit 0 diff --git a/yosys/examples/igloo2/runme.sh b/yosys/examples/igloo2/runme.sh deleted file mode 100644 index a08894e0a..000000000 --- a/yosys/examples/igloo2/runme.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -set -ex -yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v -export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost} -/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl -cp proj/designer/example/export/example.stp . diff --git a/yosys/examples/intel/DE2i-150/quartus_compile/de2i.qpf b/yosys/examples/intel/DE2i-150/quartus_compile/de2i.qpf deleted file mode 100644 index 9fc734eb3..000000000 --- a/yosys/examples/intel/DE2i-150/quartus_compile/de2i.qpf +++ /dev/null @@ -1,4 +0,0 @@ -QUARTUS_VERSION = "16.1" -# Revisions - -PROJECT_REVISION = "de2i" diff --git a/yosys/examples/intel/DE2i-150/quartus_compile/de2i.qsf b/yosys/examples/intel/DE2i-150/quartus_compile/de2i.qsf deleted file mode 100644 index 5a230155f..000000000 --- a/yosys/examples/intel/DE2i-150/quartus_compile/de2i.qsf +++ /dev/null @@ -1,1099 +0,0 @@ -set_global_assignment -name FAMILY "Cyclone IV GX" -set_global_assignment -name DEVICE EP4CGX150DF31C7 -set_global_assignment -name TOP_LEVEL_ENTITY "top" -set_global_assignment -name DEVICE_FILTER_PACKAGE FBGA - - -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLOCK2_50 -set_instance_assignment -name IO_STANDARD "2.5 V" -to CLOCK3_50 -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLOCK_50 - -#============================================================ -# DRAM -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[8] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[9] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[10] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[11] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_ADDR[12] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_BA[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_BA[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_CAS_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_CKE -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_CLK -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_CS_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[8] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[9] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[10] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[11] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[12] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[13] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[14] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[15] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[16] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[17] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[18] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[19] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[20] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[21] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[22] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[23] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[24] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[25] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[26] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[27] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[28] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[29] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[30] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQ[31] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQM[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQM[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQM[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_DQM[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_RAS_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DRAM_WE_N - -#============================================================ -# EEP -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to EEP_I2C_SCLK -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to EEP_I2C_SDAT - -#============================================================ -# ENET -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_GTX_CLK -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_INT_N -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_LINK100 -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_MDC -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_MDIO -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RST_N -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_CLK -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_COL -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_CRS -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DATA[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DATA[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DATA[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DATA[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_DV -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_RX_ER -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_CLK -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_DATA[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_DATA[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_DATA[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_DATA[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_EN -set_instance_assignment -name IO_STANDARD "2.5 V" -to ENET_TX_ER - -#============================================================ -# FAN -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to FAN_CTRL - -#============================================================ -# FLASH -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_RESET_N - -#============================================================ -# FS -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[8] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[9] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[10] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[11] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[12] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[13] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[14] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[15] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[16] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[17] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[18] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[19] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[20] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[21] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[22] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[23] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[24] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[25] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_ADDR[26] - -#============================================================ -# FL -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_CE_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_OE_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_RY -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_WE_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FL_WP_N - -#============================================================ -# FS -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[8] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[9] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[10] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[11] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[12] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[13] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[14] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[15] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[16] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[17] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[18] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[19] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[20] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[21] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[22] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[23] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[24] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[25] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[26] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[27] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[28] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[29] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[30] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to FS_DQ[31] - -#============================================================ -# GPIO -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[8] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[9] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[10] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[11] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[12] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[13] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[14] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[15] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[16] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[17] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[18] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[19] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[20] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[21] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[22] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[23] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[24] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[25] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[26] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[27] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[28] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[29] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[30] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[31] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[32] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[33] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[34] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO[35] - -#============================================================ -# G -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to G_SENSOR_INT1 -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to G_SENSOR_SCLK -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to G_SENSOR_SDAT - -#============================================================ -# HEX0 -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX0[6] - -#============================================================ -# HEX1 -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX1[6] - -#============================================================ -# HEX2 -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX2[6] - -#============================================================ -# HEX3 -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX3[6] - -#============================================================ -# HEX4 -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX4[6] - -#============================================================ -# HEX5 -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX5[6] - -#============================================================ -# HEX6 -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX6[6] - -#============================================================ -# HEX7 -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HEX7[6] - -#============================================================ -# HSMC -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN0 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN_N1 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN_N2 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN_P1 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKIN_P2 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT0 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT_N1 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT_N2 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT_P1 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_CLKOUT_P2 -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_D[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_D[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_D[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_D[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_I2C_SCLK -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_I2C_SDAT -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[8] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[9] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[10] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[11] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[12] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[13] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[14] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[15] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_N[16] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[8] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[9] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[10] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[11] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[12] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[13] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[14] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[15] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_RX_D_P[16] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[8] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[9] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[10] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[11] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[12] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[13] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[14] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[15] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_N[16] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[8] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[9] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[10] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[11] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[12] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[13] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[14] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[15] -set_instance_assignment -name IO_STANDARD "2.5 V" -to HSMC_TX_D_P[16] - -#============================================================ -# I2C -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to I2C_SCLK -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to I2C_SDAT - -#============================================================ -# IRDA -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to IRDA_RXD - -#============================================================ -# KEY -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to KEY[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to KEY[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to KEY[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to KEY[3] - -#============================================================ -# LCD -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_DATA[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_EN -set_instance_assignment -name IO_STANDARD "2.5 V" -to LCD_ON -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_RS -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LCD_RW - -#============================================================ -# LEDG -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDG[8] - -#============================================================ -# LEDR -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[8] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[9] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[10] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[11] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[12] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[13] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[14] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[15] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[16] -set_instance_assignment -name IO_STANDARD "2.5 V" -to LEDR[17] - -#============================================================ -# PCIE -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to PCIE_PERST_N -set_instance_assignment -name IO_STANDARD HCSL -to PCIE_REFCLK_P -set_instance_assignment -name IO_STANDARD "1.5-V PCML" -to PCIE_RX_P[0] -set_instance_assignment -name IO_STANDARD "1.5-V PCML" -to PCIE_RX_P[1] -set_instance_assignment -name IO_STANDARD "1.5-V PCML" -to PCIE_TX_P[0] -set_instance_assignment -name IO_STANDARD "1.5-V PCML" -to PCIE_TX_P[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to PCIE_WAKE_N - -#============================================================ -# SD -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_CLK -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_CMD -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_DAT[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_DAT[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_DAT[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_DAT[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_WP_N - -#============================================================ -# SMA -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SMA_CLKIN -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SMA_CLKOUT - -#============================================================ -# SSRAM0 -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM0_CE_N - -#============================================================ -# SSRAM1 -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM1_CE_N - -#============================================================ -# SSRAM -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_ADSC_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_ADSP_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_ADV_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_BE[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_BE[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_BE[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_BE[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_CLK -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_GW_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_OE_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SSRAM_WE_N - -#============================================================ -# SW -#============================================================ -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[0] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[1] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[2] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[3] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[4] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[5] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[6] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[7] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[8] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[9] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[10] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[11] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[12] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[13] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[14] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[15] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[16] -set_instance_assignment -name IO_STANDARD "2.5 V" -to SW[17] - -#============================================================ -# TD -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_CLK27 -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_DATA[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_HS -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_RESET_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TD_VS - -#============================================================ -# UART -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_CTS -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_RTS -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_RXD -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_TXD - -#============================================================ -# VGA -#============================================================ -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_B[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_BLANK_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_CLK -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_G[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_HS -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[0] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[1] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[2] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[3] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[4] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[5] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[6] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_R[7] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_SYNC_N -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_VS - -#============================================================ -# End of pin assignments by Terasic System Builder -#============================================================ - - - -set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" -set_location_assignment PIN_A15 -to CLOCK2_50 -set_location_assignment PIN_V11 -to CLOCK3_50 -set_location_assignment PIN_AJ16 -to CLOCK_50 -set_location_assignment PIN_AG7 -to DRAM_ADDR[0] -set_location_assignment PIN_AJ7 -to DRAM_ADDR[1] -set_location_assignment PIN_AG8 -to DRAM_ADDR[2] -set_location_assignment PIN_AH8 -to DRAM_ADDR[3] -set_location_assignment PIN_AE16 -to DRAM_ADDR[4] -set_location_assignment PIN_AF16 -to DRAM_ADDR[5] -set_location_assignment PIN_AE14 -to DRAM_ADDR[6] -set_location_assignment PIN_AE15 -to DRAM_ADDR[7] -set_location_assignment PIN_AE13 -to DRAM_ADDR[8] -set_location_assignment PIN_AE12 -to DRAM_ADDR[9] -set_location_assignment PIN_AH6 -to DRAM_ADDR[10] -set_location_assignment PIN_AE11 -to DRAM_ADDR[11] -set_location_assignment PIN_AE10 -to DRAM_ADDR[12] -set_location_assignment PIN_AH5 -to DRAM_BA[0] -set_location_assignment PIN_AG6 -to DRAM_BA[1] -set_location_assignment PIN_AJ4 -to DRAM_CAS_N -set_location_assignment PIN_AD6 -to DRAM_CKE -set_location_assignment PIN_AE6 -to DRAM_CLK -set_location_assignment PIN_AG5 -to DRAM_CS_N -set_location_assignment PIN_AD10 -to DRAM_DQ[0] -set_location_assignment PIN_AD9 -to DRAM_DQ[1] -set_location_assignment PIN_AE9 -to DRAM_DQ[2] -set_location_assignment PIN_AE8 -to DRAM_DQ[3] -set_location_assignment PIN_AE7 -to DRAM_DQ[4] -set_location_assignment PIN_AF7 -to DRAM_DQ[5] -set_location_assignment PIN_AF6 -to DRAM_DQ[6] -set_location_assignment PIN_AF9 -to DRAM_DQ[7] -set_location_assignment PIN_AB13 -to DRAM_DQ[8] -set_location_assignment PIN_AF13 -to DRAM_DQ[9] -set_location_assignment PIN_AF12 -to DRAM_DQ[10] -set_location_assignment PIN_AG9 -to DRAM_DQ[11] -set_location_assignment PIN_AA13 -to DRAM_DQ[12] -set_location_assignment PIN_AB11 -to DRAM_DQ[13] -set_location_assignment PIN_AA12 -to DRAM_DQ[14] -set_location_assignment PIN_AA15 -to DRAM_DQ[15] -set_location_assignment PIN_AH11 -to DRAM_DQ[16] -set_location_assignment PIN_AG11 -to DRAM_DQ[17] -set_location_assignment PIN_AH12 -to DRAM_DQ[18] -set_location_assignment PIN_AG12 -to DRAM_DQ[19] -set_location_assignment PIN_AH13 -to DRAM_DQ[20] -set_location_assignment PIN_AG13 -to DRAM_DQ[21] -set_location_assignment PIN_AG14 -to DRAM_DQ[22] -set_location_assignment PIN_AH14 -to DRAM_DQ[23] -set_location_assignment PIN_AH9 -to DRAM_DQ[24] -set_location_assignment PIN_AK8 -to DRAM_DQ[25] -set_location_assignment PIN_AG10 -to DRAM_DQ[26] -set_location_assignment PIN_AK7 -to DRAM_DQ[27] -set_location_assignment PIN_AH7 -to DRAM_DQ[28] -set_location_assignment PIN_AK6 -to DRAM_DQ[29] -set_location_assignment PIN_AJ6 -to DRAM_DQ[30] -set_location_assignment PIN_AK5 -to DRAM_DQ[31] -set_location_assignment PIN_AF10 -to DRAM_DQM[0] -set_location_assignment PIN_AB14 -to DRAM_DQM[1] -set_location_assignment PIN_AH15 -to DRAM_DQM[2] -set_location_assignment PIN_AH10 -to DRAM_DQM[3] -set_location_assignment PIN_AK4 -to DRAM_RAS_N -set_location_assignment PIN_AK3 -to DRAM_WE_N -set_location_assignment PIN_AG27 -to EEP_I2C_SCLK -set_location_assignment PIN_AG25 -to EEP_I2C_SDAT -set_location_assignment PIN_A12 -to ENET_GTX_CLK -set_location_assignment PIN_E16 -to ENET_INT_N -set_location_assignment PIN_F5 -to ENET_LINK100 -set_location_assignment PIN_C16 -to ENET_MDC -set_location_assignment PIN_C15 -to ENET_MDIO -set_location_assignment PIN_C14 -to ENET_RST_N -set_location_assignment PIN_L15 -to ENET_RX_CLK -set_location_assignment PIN_G15 -to ENET_RX_COL -set_location_assignment PIN_D6 -to ENET_RX_CRS -set_location_assignment PIN_F15 -to ENET_RX_DATA[0] -set_location_assignment PIN_E13 -to ENET_RX_DATA[1] -set_location_assignment PIN_A5 -to ENET_RX_DATA[2] -set_location_assignment PIN_B7 -to ENET_RX_DATA[3] -set_location_assignment PIN_A8 -to ENET_RX_DV -set_location_assignment PIN_D11 -to ENET_RX_ER -set_location_assignment PIN_F13 -to ENET_TX_CLK -set_location_assignment PIN_B12 -to ENET_TX_DATA[0] -set_location_assignment PIN_E7 -to ENET_TX_DATA[1] -set_location_assignment PIN_C13 -to ENET_TX_DATA[2] -set_location_assignment PIN_D15 -to ENET_TX_DATA[3] -set_location_assignment PIN_D14 -to ENET_TX_EN -set_location_assignment PIN_D13 -to ENET_TX_ER -set_location_assignment PIN_AF28 -to FAN_CTRL -set_location_assignment PIN_AG18 -to FL_RESET_N -set_location_assignment PIN_AB22 -to FS_ADDR[1] -set_location_assignment PIN_AH19 -to FS_ADDR[2] -set_location_assignment PIN_AK19 -to FS_ADDR[3] -set_location_assignment PIN_AJ18 -to FS_ADDR[4] -set_location_assignment PIN_AA18 -to FS_ADDR[5] -set_location_assignment PIN_AH18 -to FS_ADDR[6] -set_location_assignment PIN_AK17 -to FS_ADDR[7] -set_location_assignment PIN_Y20 -to FS_ADDR[8] -set_location_assignment PIN_AK21 -to FS_ADDR[9] -set_location_assignment PIN_AH21 -to FS_ADDR[10] -set_location_assignment PIN_AG21 -to FS_ADDR[11] -set_location_assignment PIN_AG22 -to FS_ADDR[12] -set_location_assignment PIN_AD22 -to FS_ADDR[13] -set_location_assignment PIN_AE24 -to FS_ADDR[14] -set_location_assignment PIN_AD23 -to FS_ADDR[15] -set_location_assignment PIN_AB21 -to FS_ADDR[16] -set_location_assignment PIN_AH17 -to FS_ADDR[17] -set_location_assignment PIN_AE17 -to FS_ADDR[18] -set_location_assignment PIN_AG20 -to FS_ADDR[19] -set_location_assignment PIN_AK20 -to FS_ADDR[20] -set_location_assignment PIN_AE19 -to FS_ADDR[21] -set_location_assignment PIN_AA16 -to FS_ADDR[22] -set_location_assignment PIN_AF15 -to FS_ADDR[23] -set_location_assignment PIN_AG15 -to FS_ADDR[24] -set_location_assignment PIN_Y17 -to FS_ADDR[25] -set_location_assignment PIN_AB16 -to FS_ADDR[26] -set_location_assignment PIN_AG19 -to FL_CE_N -set_location_assignment PIN_AJ19 -to FL_OE_N -set_location_assignment PIN_AF19 -to FL_RY -set_location_assignment PIN_AG17 -to FL_WE_N -set_location_assignment PIN_AK18 -to FL_WP_N -set_location_assignment PIN_AK29 -to FS_DQ[0] -set_location_assignment PIN_AE23 -to FS_DQ[1] -set_location_assignment PIN_AH24 -to FS_DQ[2] -set_location_assignment PIN_AH23 -to FS_DQ[3] -set_location_assignment PIN_AA21 -to FS_DQ[4] -set_location_assignment PIN_AE20 -to FS_DQ[5] -set_location_assignment PIN_Y19 -to FS_DQ[6] -set_location_assignment PIN_AA17 -to FS_DQ[7] -set_location_assignment PIN_AB17 -to FS_DQ[8] -set_location_assignment PIN_Y18 -to FS_DQ[9] -set_location_assignment PIN_AA20 -to FS_DQ[10] -set_location_assignment PIN_AE21 -to FS_DQ[11] -set_location_assignment PIN_AH22 -to FS_DQ[12] -set_location_assignment PIN_AJ24 -to FS_DQ[13] -set_location_assignment PIN_AE22 -to FS_DQ[14] -set_location_assignment PIN_AK28 -to FS_DQ[15] -set_location_assignment PIN_AK9 -to FS_DQ[16] -set_location_assignment PIN_AJ10 -to FS_DQ[17] -set_location_assignment PIN_AK11 -to FS_DQ[18] -set_location_assignment PIN_AK12 -to FS_DQ[19] -set_location_assignment PIN_AJ13 -to FS_DQ[20] -set_location_assignment PIN_AK15 -to FS_DQ[21] -set_location_assignment PIN_AC16 -to FS_DQ[22] -set_location_assignment PIN_AH16 -to FS_DQ[23] -set_location_assignment PIN_AG16 -to FS_DQ[24] -set_location_assignment PIN_AD16 -to FS_DQ[25] -set_location_assignment PIN_AJ15 -to FS_DQ[26] -set_location_assignment PIN_AK14 -to FS_DQ[27] -set_location_assignment PIN_AK13 -to FS_DQ[28] -set_location_assignment PIN_AJ12 -to FS_DQ[29] -set_location_assignment PIN_AK10 -to FS_DQ[30] -set_location_assignment PIN_AJ9 -to FS_DQ[31] -set_location_assignment PIN_G16 -to GPIO[0] -set_location_assignment PIN_F17 -to GPIO[1] -set_location_assignment PIN_D18 -to GPIO[2] -set_location_assignment PIN_F18 -to GPIO[3] -set_location_assignment PIN_D19 -to GPIO[4] -set_location_assignment PIN_K21 -to GPIO[5] -set_location_assignment PIN_F19 -to GPIO[6] -set_location_assignment PIN_K22 -to GPIO[7] -set_location_assignment PIN_B21 -to GPIO[8] -set_location_assignment PIN_C21 -to GPIO[9] -set_location_assignment PIN_D22 -to GPIO[10] -set_location_assignment PIN_D21 -to GPIO[11] -set_location_assignment PIN_D23 -to GPIO[12] -set_location_assignment PIN_D24 -to GPIO[13] -set_location_assignment PIN_B28 -to GPIO[14] -set_location_assignment PIN_C25 -to GPIO[15] -set_location_assignment PIN_C26 -to GPIO[16] -set_location_assignment PIN_D28 -to GPIO[17] -set_location_assignment PIN_D25 -to GPIO[18] -set_location_assignment PIN_F20 -to GPIO[19] -set_location_assignment PIN_E21 -to GPIO[20] -set_location_assignment PIN_F23 -to GPIO[21] -set_location_assignment PIN_G20 -to GPIO[22] -set_location_assignment PIN_F22 -to GPIO[23] -set_location_assignment PIN_G22 -to GPIO[24] -set_location_assignment PIN_G24 -to GPIO[25] -set_location_assignment PIN_G23 -to GPIO[26] -set_location_assignment PIN_A25 -to GPIO[27] -set_location_assignment PIN_A26 -to GPIO[28] -set_location_assignment PIN_A19 -to GPIO[29] -set_location_assignment PIN_A28 -to GPIO[30] -set_location_assignment PIN_A27 -to GPIO[31] -set_location_assignment PIN_B30 -to GPIO[32] -set_location_assignment PIN_AG28 -to GPIO[33] -set_location_assignment PIN_AG26 -to GPIO[34] -set_location_assignment PIN_Y21 -to GPIO[35] -set_location_assignment PIN_AC30 -to G_SENSOR_INT1 -set_location_assignment PIN_AK27 -to G_SENSOR_SCLK -set_location_assignment PIN_AK26 -to G_SENSOR_SDAT -set_location_assignment PIN_E15 -to HEX0[0] -set_location_assignment PIN_E12 -to HEX0[1] -set_location_assignment PIN_G11 -to HEX0[2] -set_location_assignment PIN_F11 -to HEX0[3] -set_location_assignment PIN_F16 -to HEX0[4] -set_location_assignment PIN_D16 -to HEX0[5] -set_location_assignment PIN_F14 -to HEX0[6] -set_location_assignment PIN_G14 -to HEX1[0] -set_location_assignment PIN_B13 -to HEX1[1] -set_location_assignment PIN_G13 -to HEX1[2] -set_location_assignment PIN_F12 -to HEX1[3] -set_location_assignment PIN_G12 -to HEX1[4] -set_location_assignment PIN_J9 -to HEX1[5] -set_location_assignment PIN_G10 -to HEX1[6] -set_location_assignment PIN_G8 -to HEX2[0] -set_location_assignment PIN_G7 -to HEX2[1] -set_location_assignment PIN_F7 -to HEX2[2] -set_location_assignment PIN_AG30 -to HEX2[3] -set_location_assignment PIN_F6 -to HEX2[4] -set_location_assignment PIN_F4 -to HEX2[5] -set_location_assignment PIN_F10 -to HEX2[6] -set_location_assignment PIN_D10 -to HEX3[0] -set_location_assignment PIN_D7 -to HEX3[1] -set_location_assignment PIN_E6 -to HEX3[2] -set_location_assignment PIN_E4 -to HEX3[3] -set_location_assignment PIN_E3 -to HEX3[4] -set_location_assignment PIN_D5 -to HEX3[5] -set_location_assignment PIN_D4 -to HEX3[6] -set_location_assignment PIN_A14 -to HEX4[0] -set_location_assignment PIN_A13 -to HEX4[1] -set_location_assignment PIN_C7 -to HEX4[2] -set_location_assignment PIN_C6 -to HEX4[3] -set_location_assignment PIN_C5 -to HEX4[4] -set_location_assignment PIN_C4 -to HEX4[5] -set_location_assignment PIN_C3 -to HEX4[6] -set_location_assignment PIN_D3 -to HEX5[0] -set_location_assignment PIN_A10 -to HEX5[1] -set_location_assignment PIN_A9 -to HEX5[2] -set_location_assignment PIN_A7 -to HEX5[3] -set_location_assignment PIN_A6 -to HEX5[4] -set_location_assignment PIN_A11 -to HEX5[5] -set_location_assignment PIN_B6 -to HEX5[6] -set_location_assignment PIN_B9 -to HEX6[0] -set_location_assignment PIN_B10 -to HEX6[1] -set_location_assignment PIN_C8 -to HEX6[2] -set_location_assignment PIN_C9 -to HEX6[3] -set_location_assignment PIN_D8 -to HEX6[4] -set_location_assignment PIN_D9 -to HEX6[5] -set_location_assignment PIN_E9 -to HEX6[6] -set_location_assignment PIN_E10 -to HEX7[0] -set_location_assignment PIN_F8 -to HEX7[1] -set_location_assignment PIN_F9 -to HEX7[2] -set_location_assignment PIN_C10 -to HEX7[3] -set_location_assignment PIN_C11 -to HEX7[4] -set_location_assignment PIN_C12 -to HEX7[5] -set_location_assignment PIN_D12 -to HEX7[6] -set_location_assignment PIN_K15 -to HSMC_CLKIN0 -set_location_assignment PIN_V30 -to HSMC_CLKIN_N1 -set_location_assignment PIN_T30 -to HSMC_CLKIN_N2 -set_location_assignment PIN_V29 -to HSMC_CLKIN_P1 -set_location_assignment PIN_T29 -to HSMC_CLKIN_P2 -set_location_assignment PIN_G6 -to HSMC_CLKOUT0 -set_location_assignment PIN_AB28 -to HSMC_CLKOUT_N1 -set_location_assignment PIN_Y28 -to HSMC_CLKOUT_N2 -set_location_assignment PIN_AB27 -to HSMC_CLKOUT_P1 -set_location_assignment PIN_AA28 -to HSMC_CLKOUT_P2 -set_location_assignment PIN_AC25 -to HSMC_D[0] -set_location_assignment PIN_E27 -to HSMC_D[1] -set_location_assignment PIN_AB26 -to HSMC_D[2] -set_location_assignment PIN_E28 -to HSMC_D[3] -set_location_assignment PIN_AD26 -to HSMC_I2C_SCLK -set_location_assignment PIN_AD25 -to HSMC_I2C_SDAT -set_location_assignment PIN_G27 -to HSMC_RX_D_N[0] -set_location_assignment PIN_G29 -to HSMC_RX_D_N[1] -set_location_assignment PIN_H27 -to HSMC_RX_D_N[2] -set_location_assignment PIN_K29 -to HSMC_RX_D_N[3] -set_location_assignment PIN_L28 -to HSMC_RX_D_N[4] -set_location_assignment PIN_M28 -to HSMC_RX_D_N[5] -set_location_assignment PIN_N30 -to HSMC_RX_D_N[6] -set_location_assignment PIN_P28 -to HSMC_RX_D_N[7] -set_location_assignment PIN_R28 -to HSMC_RX_D_N[8] -set_location_assignment PIN_U28 -to HSMC_RX_D_N[9] -set_location_assignment PIN_W28 -to HSMC_RX_D_N[10] -set_location_assignment PIN_W30 -to HSMC_RX_D_N[11] -set_location_assignment PIN_M30 -to HSMC_RX_D_N[12] -set_location_assignment PIN_Y27 -to HSMC_RX_D_N[13] -set_location_assignment PIN_AA29 -to HSMC_RX_D_N[14] -set_location_assignment PIN_AD28 -to HSMC_RX_D_N[15] -set_location_assignment PIN_AE28 -to HSMC_RX_D_N[16] -set_location_assignment PIN_G26 -to HSMC_RX_D_P[0] -set_location_assignment PIN_G28 -to HSMC_RX_D_P[1] -set_location_assignment PIN_J27 -to HSMC_RX_D_P[2] -set_location_assignment PIN_K28 -to HSMC_RX_D_P[3] -set_location_assignment PIN_L27 -to HSMC_RX_D_P[4] -set_location_assignment PIN_M27 -to HSMC_RX_D_P[5] -set_location_assignment PIN_N29 -to HSMC_RX_D_P[6] -set_location_assignment PIN_P27 -to HSMC_RX_D_P[7] -set_location_assignment PIN_R27 -to HSMC_RX_D_P[8] -set_location_assignment PIN_U27 -to HSMC_RX_D_P[9] -set_location_assignment PIN_W27 -to HSMC_RX_D_P[10] -set_location_assignment PIN_W29 -to HSMC_RX_D_P[11] -set_location_assignment PIN_M29 -to HSMC_RX_D_P[12] -set_location_assignment PIN_AA27 -to HSMC_RX_D_P[13] -set_location_assignment PIN_AB29 -to HSMC_RX_D_P[14] -set_location_assignment PIN_AD27 -to HSMC_RX_D_P[15] -set_location_assignment PIN_AE27 -to HSMC_RX_D_P[16] -set_location_assignment PIN_H28 -to HSMC_TX_D_N[0] -set_location_assignment PIN_F29 -to HSMC_TX_D_N[1] -set_location_assignment PIN_D30 -to HSMC_TX_D_N[2] -set_location_assignment PIN_E30 -to HSMC_TX_D_N[3] -set_location_assignment PIN_G30 -to HSMC_TX_D_N[4] -set_location_assignment PIN_J30 -to HSMC_TX_D_N[5] -set_location_assignment PIN_K27 -to HSMC_TX_D_N[6] -set_location_assignment PIN_K30 -to HSMC_TX_D_N[7] -set_location_assignment PIN_T25 -to HSMC_TX_D_N[8] -set_location_assignment PIN_N28 -to HSMC_TX_D_N[9] -set_location_assignment PIN_V26 -to HSMC_TX_D_N[10] -set_location_assignment PIN_Y30 -to HSMC_TX_D_N[11] -set_location_assignment PIN_AC28 -to HSMC_TX_D_N[12] -set_location_assignment PIN_AD30 -to HSMC_TX_D_N[13] -set_location_assignment PIN_AE30 -to HSMC_TX_D_N[14] -set_location_assignment PIN_AH30 -to HSMC_TX_D_N[15] -set_location_assignment PIN_AG29 -to HSMC_TX_D_N[16] -set_location_assignment PIN_J28 -to HSMC_TX_D_P[0] -set_location_assignment PIN_F28 -to HSMC_TX_D_P[1] -set_location_assignment PIN_D29 -to HSMC_TX_D_P[2] -set_location_assignment PIN_F30 -to HSMC_TX_D_P[3] -set_location_assignment PIN_H30 -to HSMC_TX_D_P[4] -set_location_assignment PIN_J29 -to HSMC_TX_D_P[5] -set_location_assignment PIN_K26 -to HSMC_TX_D_P[6] -set_location_assignment PIN_L30 -to HSMC_TX_D_P[7] -set_location_assignment PIN_U25 -to HSMC_TX_D_P[8] -set_location_assignment PIN_N27 -to HSMC_TX_D_P[9] -set_location_assignment PIN_V25 -to HSMC_TX_D_P[10] -set_location_assignment PIN_AA30 -to HSMC_TX_D_P[11] -set_location_assignment PIN_AC27 -to HSMC_TX_D_P[12] -set_location_assignment PIN_AD29 -to HSMC_TX_D_P[13] -set_location_assignment PIN_AE29 -to HSMC_TX_D_P[14] -set_location_assignment PIN_AJ30 -to HSMC_TX_D_P[15] -set_location_assignment PIN_AH29 -to HSMC_TX_D_P[16] -set_location_assignment PIN_C27 -to I2C_SCLK -set_location_assignment PIN_G21 -to I2C_SDAT -set_location_assignment PIN_AH28 -to IRDA_RXD -set_location_assignment PIN_AA26 -to KEY[0] -set_location_assignment PIN_AE25 -to KEY[1] -set_location_assignment PIN_AF30 -to KEY[2] -set_location_assignment PIN_AE26 -to KEY[3] -set_location_assignment PIN_AG4 -to LCD_DATA[0] -set_location_assignment PIN_AF3 -to LCD_DATA[1] -set_location_assignment PIN_AH3 -to LCD_DATA[2] -set_location_assignment PIN_AE5 -to LCD_DATA[3] -set_location_assignment PIN_AH2 -to LCD_DATA[4] -set_location_assignment PIN_AE3 -to LCD_DATA[5] -set_location_assignment PIN_AH4 -to LCD_DATA[6] -set_location_assignment PIN_AE4 -to LCD_DATA[7] -set_location_assignment PIN_AF4 -to LCD_EN -set_location_assignment PIN_AF27 -to LCD_ON -set_location_assignment PIN_AG3 -to LCD_RS -set_location_assignment PIN_AJ3 -to LCD_RW -set_location_assignment PIN_AA25 -to LEDG[0] -set_location_assignment PIN_AB25 -to LEDG[1] -set_location_assignment PIN_F27 -to LEDG[2] -set_location_assignment PIN_F26 -to LEDG[3] -set_location_assignment PIN_W26 -to LEDG[4] -set_location_assignment PIN_Y22 -to LEDG[5] -set_location_assignment PIN_Y25 -to LEDG[6] -set_location_assignment PIN_AA22 -to LEDG[7] -set_location_assignment PIN_J25 -to LEDG[8] -set_location_assignment PIN_T23 -to LEDR[0] -set_location_assignment PIN_T24 -to LEDR[1] -set_location_assignment PIN_V27 -to LEDR[2] -set_location_assignment PIN_W25 -to LEDR[3] -set_location_assignment PIN_T21 -to LEDR[4] -set_location_assignment PIN_T26 -to LEDR[5] -set_location_assignment PIN_R25 -to LEDR[6] -set_location_assignment PIN_T27 -to LEDR[7] -set_location_assignment PIN_P25 -to LEDR[8] -set_location_assignment PIN_R24 -to LEDR[9] -set_location_assignment PIN_P21 -to LEDR[10] -set_location_assignment PIN_N24 -to LEDR[11] -set_location_assignment PIN_N21 -to LEDR[12] -set_location_assignment PIN_M25 -to LEDR[13] -set_location_assignment PIN_K24 -to LEDR[14] -set_location_assignment PIN_L25 -to LEDR[15] -set_location_assignment PIN_M21 -to LEDR[16] -set_location_assignment PIN_M22 -to LEDR[17] -set_location_assignment PIN_A4 -to PCIE_PERST_N -set_location_assignment PIN_V15 -to PCIE_REFCLK_P -set_location_assignment PIN_AC2 -to PCIE_RX_P[0] -set_location_assignment PIN_AA2 -to PCIE_RX_P[1] -set_location_assignment PIN_AB4 -to PCIE_TX_P[0] -set_location_assignment PIN_Y4 -to PCIE_TX_P[1] -set_location_assignment PIN_C29 -to PCIE_WAKE_N -set_location_assignment PIN_AH25 -to SD_CLK -set_location_assignment PIN_AF18 -to SD_CMD -set_location_assignment PIN_AH27 -to SD_DAT[0] -set_location_assignment PIN_AJ28 -to SD_DAT[1] -set_location_assignment PIN_AD24 -to SD_DAT[2] -set_location_assignment PIN_AE18 -to SD_DAT[3] -set_location_assignment PIN_AJ27 -to SD_WP_N -set_location_assignment PIN_AK16 -to SMA_CLKIN -set_location_assignment PIN_AF25 -to SMA_CLKOUT -set_location_assignment PIN_AJ21 -to SSRAM0_CE_N -set_location_assignment PIN_AG23 -to SSRAM1_CE_N -set_location_assignment PIN_AK25 -to SSRAM_ADSC_N -set_location_assignment PIN_AJ25 -to SSRAM_ADSP_N -set_location_assignment PIN_AH26 -to SSRAM_ADV_N -set_location_assignment PIN_AF22 -to SSRAM_BE[0] -set_location_assignment PIN_AK22 -to SSRAM_BE[1] -set_location_assignment PIN_AJ22 -to SSRAM_BE[2] -set_location_assignment PIN_AF21 -to SSRAM_BE[3] -set_location_assignment PIN_AF24 -to SSRAM_CLK -set_location_assignment PIN_AK23 -to SSRAM_GW_N -set_location_assignment PIN_AG24 -to SSRAM_OE_N -set_location_assignment PIN_AK24 -to SSRAM_WE_N -set_location_assignment PIN_V28 -to SW[0] -set_location_assignment PIN_U30 -to SW[1] -set_location_assignment PIN_V21 -to SW[2] -set_location_assignment PIN_C2 -to SW[3] -set_location_assignment PIN_AB30 -to SW[4] -set_location_assignment PIN_U21 -to SW[5] -set_location_assignment PIN_T28 -to SW[6] -set_location_assignment PIN_R30 -to SW[7] -set_location_assignment PIN_P30 -to SW[8] -set_location_assignment PIN_R29 -to SW[9] -set_location_assignment PIN_R26 -to SW[10] -set_location_assignment PIN_N26 -to SW[11] -set_location_assignment PIN_M26 -to SW[12] -set_location_assignment PIN_N25 -to SW[13] -set_location_assignment PIN_J26 -to SW[14] -set_location_assignment PIN_K25 -to SW[15] -set_location_assignment PIN_C30 -to SW[16] -set_location_assignment PIN_H25 -to SW[17] -set_location_assignment PIN_B15 -to TD_CLK27 -set_location_assignment PIN_C17 -to TD_DATA[0] -set_location_assignment PIN_D17 -to TD_DATA[1] -set_location_assignment PIN_A16 -to TD_DATA[2] -set_location_assignment PIN_B16 -to TD_DATA[3] -set_location_assignment PIN_G18 -to TD_DATA[4] -set_location_assignment PIN_G17 -to TD_DATA[5] -set_location_assignment PIN_K18 -to TD_DATA[6] -set_location_assignment PIN_K17 -to TD_DATA[7] -set_location_assignment PIN_C28 -to TD_HS -set_location_assignment PIN_E25 -to TD_RESET_N -set_location_assignment PIN_E22 -to TD_VS -set_location_assignment PIN_D26 -to UART_CTS -set_location_assignment PIN_A29 -to UART_RTS -set_location_assignment PIN_B27 -to UART_RXD -set_location_assignment PIN_H24 -to UART_TXD -set_location_assignment PIN_E24 -to VGA_B[0] -set_location_assignment PIN_C24 -to VGA_B[1] -set_location_assignment PIN_B25 -to VGA_B[2] -set_location_assignment PIN_C23 -to VGA_B[3] -set_location_assignment PIN_F24 -to VGA_B[4] -set_location_assignment PIN_A23 -to VGA_B[5] -set_location_assignment PIN_G25 -to VGA_B[6] -set_location_assignment PIN_C22 -to VGA_B[7] -set_location_assignment PIN_F25 -to VGA_BLANK_N -set_location_assignment PIN_D27 -to VGA_CLK -set_location_assignment PIN_D20 -to VGA_G[0] -set_location_assignment PIN_C20 -to VGA_G[1] -set_location_assignment PIN_A20 -to VGA_G[2] -set_location_assignment PIN_K19 -to VGA_G[3] -set_location_assignment PIN_A21 -to VGA_G[4] -set_location_assignment PIN_F21 -to VGA_G[5] -set_location_assignment PIN_A22 -to VGA_G[6] -set_location_assignment PIN_B22 -to VGA_G[7] -set_location_assignment PIN_B24 -to VGA_HS -set_location_assignment PIN_A17 -to VGA_R[0] -set_location_assignment PIN_C18 -to VGA_R[1] -set_location_assignment PIN_B18 -to VGA_R[2] -set_location_assignment PIN_A18 -to VGA_R[3] -set_location_assignment PIN_E18 -to VGA_R[4] -set_location_assignment PIN_E19 -to VGA_R[5] -set_location_assignment PIN_B19 -to VGA_R[6] -set_location_assignment PIN_C19 -to VGA_R[7] -set_location_assignment PIN_AH20 -to VGA_SYNC_N -set_location_assignment PIN_A24 -to VGA_VS -set_instance_assignment -name VIRTUAL_PIN ON -to FS_ADDR[0] -#============================================================ -set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top -set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top -set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top -set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V" -set_global_assignment -name VQM_FILE ../top.vqm -set_global_assignment -name SDC_FILE de2i_150_golden_top.sdc -set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 -set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 -set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" -set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" -set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/yosys/examples/intel/DE2i-150/quartus_compile/runme_quartus b/yosys/examples/intel/DE2i-150/quartus_compile/runme_quartus deleted file mode 100644 index 83aa3b609..000000000 --- a/yosys/examples/intel/DE2i-150/quartus_compile/runme_quartus +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -export REV="de2i" - -quartus_map -c $REV top && \ - quartus_fit -c $REV top && \ - quartus_asm -c $REV top diff --git a/yosys/examples/intel/DE2i-150/run_cycloneiv b/yosys/examples/intel/DE2i-150/run_cycloneiv deleted file mode 100644 index 518807b57..000000000 --- a/yosys/examples/intel/DE2i-150/run_cycloneiv +++ /dev/null @@ -1,2 +0,0 @@ -#/bin/env bash -yosys -p "synth_intel -family cycloneiv -top top -vqm top.vqm" top.v sevenseg.v diff --git a/yosys/examples/intel/DE2i-150/sevenseg.v b/yosys/examples/intel/DE2i-150/sevenseg.v deleted file mode 100644 index 06cf7c146..000000000 --- a/yosys/examples/intel/DE2i-150/sevenseg.v +++ /dev/null @@ -1,25 +0,0 @@ -module sevenseg ( output reg [6:0] HEX0, - input [3:0] SW ); - - always @(*) begin - case(SW) - 4'h1: HEX0 = 7'b1111001; - 4'h2: HEX0 = 7'b0100100; - 4'h3: HEX0 = 7'b0110000; - 4'h4: HEX0 = 7'b0011001; - 4'h5: HEX0 = 7'b0010010; - 4'h6: HEX0 = 7'b0000010; - 4'h7: HEX0 = 7'b1111000; - 4'h8: HEX0 = 7'b0000000; - 4'h9: HEX0 = 7'b0011000; - 4'ha: HEX0 = 7'b0001000; - 4'hb: HEX0 = 7'b0000011; - 4'hc: HEX0 = 7'b1000110; - 4'hd: HEX0 = 7'b0100001; - 4'he: HEX0 = 7'b0000110; - 4'hf: HEX0 = 7'b0001110; - 4'h0: HEX0 = 7'b1000000; - endcase // case (SW) - end - -endmodule diff --git a/yosys/examples/intel/DE2i-150/top.v b/yosys/examples/intel/DE2i-150/top.v deleted file mode 100644 index 2bada0e21..000000000 --- a/yosys/examples/intel/DE2i-150/top.v +++ /dev/null @@ -1,15 +0,0 @@ -`default_nettype none -module top ( output wire [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, HEX6, HEX7, - input wire [15:0] SW ); - - - sevenseg UUD0 (.HEX0(HEX0), .SW(4'h7)); - sevenseg UUD1 (.HEX0(HEX1), .SW(4'h1)); - sevenseg UUD2 (.HEX0(HEX2), .SW(4'h0)); - sevenseg UUD3 (.HEX0(HEX3), .SW(4'h2)); - sevenseg UUD4 (.HEX0(HEX4), .SW(SW[3:0])); - sevenseg UUD5 (.HEX0(HEX5), .SW(SW[7:4])); - sevenseg UUD6 (.HEX0(HEX6), .SW(SW[11:8])); - sevenseg UUD7 (.HEX0(HEX7), .SW(SW[15:12])); - -endmodule diff --git a/yosys/examples/intel/MAX10/run_max10 b/yosys/examples/intel/MAX10/run_max10 deleted file mode 100644 index 0378e4fa7..000000000 --- a/yosys/examples/intel/MAX10/run_max10 +++ /dev/null @@ -1 +0,0 @@ -yosys -p "synth_intel -family max10 -top top -vqm top.vqm" top.v sevenseg.v diff --git a/yosys/examples/intel/MAX10/runme_postsynth b/yosys/examples/intel/MAX10/runme_postsynth deleted file mode 100644 index f16210540..000000000 --- a/yosys/examples/intel/MAX10/runme_postsynth +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -iverilog -D POST_IMPL -o verif_post -s tb_top tb_top.v top.vqm $(yosys-config --datdir/altera_intel/max10/cells_comb_max10.v) -vvp -N verif_post - diff --git a/yosys/examples/intel/MAX10/sevenseg.v b/yosys/examples/intel/MAX10/sevenseg.v deleted file mode 100644 index 06cf7c146..000000000 --- a/yosys/examples/intel/MAX10/sevenseg.v +++ /dev/null @@ -1,25 +0,0 @@ -module sevenseg ( output reg [6:0] HEX0, - input [3:0] SW ); - - always @(*) begin - case(SW) - 4'h1: HEX0 = 7'b1111001; - 4'h2: HEX0 = 7'b0100100; - 4'h3: HEX0 = 7'b0110000; - 4'h4: HEX0 = 7'b0011001; - 4'h5: HEX0 = 7'b0010010; - 4'h6: HEX0 = 7'b0000010; - 4'h7: HEX0 = 7'b1111000; - 4'h8: HEX0 = 7'b0000000; - 4'h9: HEX0 = 7'b0011000; - 4'ha: HEX0 = 7'b0001000; - 4'hb: HEX0 = 7'b0000011; - 4'hc: HEX0 = 7'b1000110; - 4'hd: HEX0 = 7'b0100001; - 4'he: HEX0 = 7'b0000110; - 4'hf: HEX0 = 7'b0001110; - 4'h0: HEX0 = 7'b1000000; - endcase // case (SW) - end - -endmodule diff --git a/yosys/examples/intel/MAX10/top.v b/yosys/examples/intel/MAX10/top.v deleted file mode 100644 index 2bada0e21..000000000 --- a/yosys/examples/intel/MAX10/top.v +++ /dev/null @@ -1,15 +0,0 @@ -`default_nettype none -module top ( output wire [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, HEX6, HEX7, - input wire [15:0] SW ); - - - sevenseg UUD0 (.HEX0(HEX0), .SW(4'h7)); - sevenseg UUD1 (.HEX0(HEX1), .SW(4'h1)); - sevenseg UUD2 (.HEX0(HEX2), .SW(4'h0)); - sevenseg UUD3 (.HEX0(HEX3), .SW(4'h2)); - sevenseg UUD4 (.HEX0(HEX4), .SW(SW[3:0])); - sevenseg UUD5 (.HEX0(HEX5), .SW(SW[7:4])); - sevenseg UUD6 (.HEX0(HEX6), .SW(SW[11:8])); - sevenseg UUD7 (.HEX0(HEX7), .SW(SW[15:12])); - -endmodule diff --git a/yosys/examples/intel/asicworld_lfsr/README b/yosys/examples/intel/asicworld_lfsr/README deleted file mode 100644 index ba365fabf..000000000 --- a/yosys/examples/intel/asicworld_lfsr/README +++ /dev/null @@ -1,6 +0,0 @@ -Source of the files: -http://www.asic-world.com/examples/verilog/lfsr.html - -Run first: runme_presynth -Generate output netlist with run_max10 or run_cycloneiv -Then, check with: runme_postsynth diff --git a/yosys/examples/intel/asicworld_lfsr/lfsr_updown.v b/yosys/examples/intel/asicworld_lfsr/lfsr_updown.v deleted file mode 100644 index 43db1606a..000000000 --- a/yosys/examples/intel/asicworld_lfsr/lfsr_updown.v +++ /dev/null @@ -1,35 +0,0 @@ -`default_nettype none -module lfsr_updown ( -clk , // Clock input -reset , // Reset input -enable , // Enable input -up_down , // Up Down input -count , // Count output -overflow // Overflow output -); - - input clk; - input reset; - input enable; - input up_down; - - output [7 : 0] count; - output overflow; - - reg [7 : 0] count; - - assign overflow = (up_down) ? (count == {{7{1'b0}}, 1'b1}) : - (count == {1'b1, {7{1'b0}}}) ; - - always @(posedge clk) - if (reset) - count <= {7{1'b0}}; - else if (enable) begin - if (up_down) begin - count <= {~(^(count & 8'b01100011)),count[7:1]}; - end else begin - count <= {count[5:0],~(^(count & 8'b10110001))}; - end - end - -endmodule diff --git a/yosys/examples/intel/asicworld_lfsr/lfsr_updown_tb.v b/yosys/examples/intel/asicworld_lfsr/lfsr_updown_tb.v deleted file mode 100644 index db29e60f1..000000000 --- a/yosys/examples/intel/asicworld_lfsr/lfsr_updown_tb.v +++ /dev/null @@ -1,34 +0,0 @@ -module tb(); - reg clk; - reg reset; - reg enable; - reg up_down; - - wire [7 : 0] count; - wire overflow; - -initial begin - $monitor("rst %b en %b updown %b cnt %b overflow %b", - reset,enable,up_down,count, overflow); - clk = 0; - reset = 1; - enable = 0; - up_down = 0; - #10 reset = 0; - #1 enable = 1; - #20 up_down = 1; - #30 $finish; -end - -always #1 clk = ~clk; - -lfsr_updown U( -.clk ( clk ), -.reset ( reset ), -.enable ( enable ), -.up_down ( up_down ), -.count ( count ), -.overflow ( overflow ) -); - -endmodule diff --git a/yosys/examples/intel/asicworld_lfsr/run_cycloneiv b/yosys/examples/intel/asicworld_lfsr/run_cycloneiv deleted file mode 100755 index c7498bded..000000000 --- a/yosys/examples/intel/asicworld_lfsr/run_cycloneiv +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/env bash -yosys -p "synth_intel -family cycloneiv -top lfsr_updown -vqm top.vqm" lfsr_updown.v diff --git a/yosys/examples/intel/asicworld_lfsr/run_max10 b/yosys/examples/intel/asicworld_lfsr/run_max10 deleted file mode 100755 index b75d552bb..000000000 --- a/yosys/examples/intel/asicworld_lfsr/run_max10 +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/env bash -yosys -p "synth_intel -family max10 -top lfsr_updown -vqm top.vqm" lfsr_updown.v diff --git a/yosys/examples/intel/asicworld_lfsr/runme_postsynth b/yosys/examples/intel/asicworld_lfsr/runme_postsynth deleted file mode 100755 index c3b26b034..000000000 --- a/yosys/examples/intel/asicworld_lfsr/runme_postsynth +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -iverilog -D POST_IMPL -o verif_post -s tb lfsr_updown_tb.v top.vqm $(yosys-config --datdir/altera_intel/max10/cells_comb_max10.v) -vvp -N verif_post - diff --git a/yosys/examples/intel/asicworld_lfsr/runme_presynth b/yosys/examples/intel/asicworld_lfsr/runme_presynth deleted file mode 100755 index 51118bb4b..000000000 --- a/yosys/examples/intel/asicworld_lfsr/runme_presynth +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -iverilog -o presynth lfsr_updown_tb.v lfsr_updown.v &&\ - -vvp -N presynth \ No newline at end of file diff --git a/yosys/examples/osu035/.gitignore b/yosys/examples/osu035/.gitignore deleted file mode 100644 index 3abf340bb..000000000 --- a/yosys/examples/osu035/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -osu035_stdcells.lib -example.yslog -example.edif diff --git a/yosys/examples/osu035/Makefile b/yosys/examples/osu035/Makefile deleted file mode 100644 index 2bb8162b3..000000000 --- a/yosys/examples/osu035/Makefile +++ /dev/null @@ -1,13 +0,0 @@ - -example.edif: example.ys example.v example.constr osu035_stdcells.lib - yosys -l example.yslog -q example.ys - -osu035_stdcells.lib: - rm -f osu035_stdcells.lib.part osu035_stdcells.lib - wget -O osu035_stdcells.lib.part https://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/ami035/signalstorm/osu035_stdcells.lib - mv osu035_stdcells.lib.part osu035_stdcells.lib - -clean: - rm -f osu035_stdcells.lib - rm -f example.yslog example.edif - diff --git a/yosys/examples/osu035/example.constr b/yosys/examples/osu035/example.constr deleted file mode 100644 index eb2c6e8d5..000000000 --- a/yosys/examples/osu035/example.constr +++ /dev/null @@ -1,2 +0,0 @@ -set_driving_cell INVX1 -set_load 0.015 diff --git a/yosys/examples/osu035/example.v b/yosys/examples/osu035/example.v deleted file mode 100644 index 0f043e5fc..000000000 --- a/yosys/examples/osu035/example.v +++ /dev/null @@ -1,3 +0,0 @@ -module top (input clk, input [7:0] a, b, output reg [15:0] c); - always @(posedge clk) c <= a * b; -endmodule diff --git a/yosys/examples/osu035/example.ys b/yosys/examples/osu035/example.ys deleted file mode 100644 index 6821ef426..000000000 --- a/yosys/examples/osu035/example.ys +++ /dev/null @@ -1,11 +0,0 @@ -read_verilog example.v -read_liberty -lib osu035_stdcells.lib - -synth -top top - -dfflibmap -liberty osu035_stdcells.lib -abc -D 10000 -constr example.constr -liberty osu035_stdcells.lib -opt_clean - -stat -liberty osu035_stdcells.lib -write_edif example.edif diff --git a/yosys/examples/python-api/.gitignore b/yosys/examples/python-api/.gitignore deleted file mode 100644 index 758de1134..000000000 --- a/yosys/examples/python-api/.gitignore +++ /dev/null @@ -1 +0,0 @@ -out/** diff --git a/yosys/examples/python-api/pass.py b/yosys/examples/python-api/pass.py deleted file mode 100755 index d67cf4a23..000000000 --- a/yosys/examples/python-api/pass.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python3 - -from pyosys import libyosys as ys - -import matplotlib.pyplot as plt -import numpy as np - -class CellStatsPass(ys.Pass): - - def __init__(self): - super().__init__("cell_stats", "Shows cell stats as plot") - - def py_help(self): - ys.log("This pass uses the matplotlib library to display cell stats\n") - - def py_execute(self, args, design): - ys.log_header(design, "Plotting cell stats\n") - cell_stats = {} - for module in design.selected_whole_modules_warn(): - for cell in module.selected_cells(): - if cell.type.str() in cell_stats: - cell_stats[cell.type.str()] += 1 - else: - cell_stats[cell.type.str()] = 1 - plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center') - plt.xticks(range(len(cell_stats)), list(cell_stats.keys())) - plt.show() - - def py_clear_flags(self): - ys.log("Clear Flags - CellStatsPass\n") - -p = CellStatsPass() diff --git a/yosys/examples/python-api/script.py b/yosys/examples/python-api/script.py deleted file mode 100755 index f0fa5a0b8..000000000 --- a/yosys/examples/python-api/script.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/python3 - -from pyosys import libyosys as ys - -import matplotlib.pyplot as plt -import numpy as np - -design = ys.Design() -ys.run_pass("read_verilog ../../tests/simple/fiedler-cooley.v", design); -ys.run_pass("prep", design) -ys.run_pass("opt -full", design) - -cell_stats = {} -for module in design.selected_whole_modules_warn(): - for cell in module.selected_cells(): - if cell.type.str() in cell_stats: - cell_stats[cell.type.str()] += 1 - else: - cell_stats[cell.type.str()] = 1 -plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center') -plt.xticks(range(len(cell_stats)), list(cell_stats.keys())) -plt.show() diff --git a/yosys/examples/smtbmc/.gitignore b/yosys/examples/smtbmc/.gitignore deleted file mode 100644 index 278f5ebf7..000000000 --- a/yosys/examples/smtbmc/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -demo1.smt2 -demo1.yslog -demo2.smt2 -demo2.smtc -demo2.vcd -demo2.yslog -demo2_tb -demo2_tb.v -demo2_tb.vcd -demo3.smt2 -demo3.vcd -demo3.yslog -demo4.smt2 -demo4.vcd -demo4.yslog -demo5.smt2 -demo5.vcd -demo5.yslog -demo6.smt2 -demo6.yslog -demo7.smt2 -demo7.yslog -demo8.smt2 -demo8.yslog diff --git a/yosys/examples/smtbmc/Makefile b/yosys/examples/smtbmc/Makefile deleted file mode 100644 index 96fa058d6..000000000 --- a/yosys/examples/smtbmc/Makefile +++ /dev/null @@ -1,66 +0,0 @@ - -all: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 - -demo1: demo1.smt2 - yosys-smtbmc --dump-vcd demo1.vcd demo1.smt2 - yosys-smtbmc -i --dump-vcd demo1.vcd demo1.smt2 - -demo2: demo2.smt2 - yosys-smtbmc -g --dump-vcd demo2.vcd --dump-smtc demo2.smtc --dump-vlogtb demo2_tb.v demo2.smt2 - iverilog -g2012 -o demo2_tb demo2_tb.v demo2.v - vvp demo2_tb +vcd=demo2_tb.vcd - -demo3: demo3.smt2 - yosys-smtbmc --dump-vcd demo3.vcd --smtc demo3.smtc demo3.smt2 - -demo4: demo4.smt2 - yosys-smtbmc -s yices --dump-vcd demo4.vcd --smtc demo4.smtc demo4.smt2 - -demo5: demo5.smt2 - yosys-smtbmc -g -t 50 --dump-vcd demo5.vcd demo5.smt2 - -demo6: demo6.smt2 - yosys-smtbmc -t 1 demo6.smt2 - -demo7: demo7.smt2 - yosys-smtbmc -t 10 demo7.smt2 - -demo8: demo8.smt2 - yosys-smtbmc -s z3 -t 1 -g demo8.smt2 - -demo1.smt2: demo1.v - yosys -ql demo1.yslog -p 'read_verilog -formal demo1.v; prep -top demo1 -nordff; write_smt2 -wires demo1.smt2' - -demo2.smt2: demo2.v - yosys -ql demo2.yslog -p 'read_verilog -formal demo2.v; prep -top demo2 -nordff; write_smt2 -wires demo2.smt2' - -demo3.smt2: demo3.v - yosys -ql demo3.yslog -p 'read_verilog -formal demo3.v; prep -top demo3 -nordff; write_smt2 -wires demo3.smt2' - -demo4.smt2: demo4.v - yosys -ql demo4.yslog -p 'read_verilog -formal demo4.v; prep -top demo4 -nordff; write_smt2 -wires demo4.smt2' - -demo5.smt2: demo5.v - yosys -ql demo5.yslog -p 'read_verilog -formal demo5.v; prep -top demo5 -nordff; write_smt2 -wires demo5.smt2' - -demo6.smt2: demo6.v - yosys -ql demo6.yslog -p 'read_verilog demo6.v; prep -top demo6 -nordff; assertpmux; opt -keepdc -fast; write_smt2 -wires demo6.smt2' - -demo7.smt2: demo7.v - yosys -ql demo7.yslog -p 'read_verilog -formal demo7.v; prep -top demo7 -nordff; write_smt2 -wires demo7.smt2' - -demo8.smt2: demo8.v - yosys -ql demo8.yslog -p 'read_verilog -formal demo8.v; prep -top demo8 -nordff; write_smt2 -stbv -wires demo8.smt2' - -clean: - rm -f demo1.yslog demo1.smt2 demo1.vcd - rm -f demo2.yslog demo2.smt2 demo2.vcd demo2.smtc demo2_tb.v demo2_tb demo2_tb.vcd - rm -f demo3.yslog demo3.smt2 demo3.vcd - rm -f demo4.yslog demo4.smt2 demo4.vcd - rm -f demo5.yslog demo5.smt2 demo5.vcd - rm -f demo6.yslog demo6.smt2 - rm -f demo7.yslog demo7.smt2 - rm -f demo8.yslog demo8.smt2 - -.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 clean - diff --git a/yosys/examples/smtbmc/demo1.v b/yosys/examples/smtbmc/demo1.v deleted file mode 100644 index 567dde148..000000000 --- a/yosys/examples/smtbmc/demo1.v +++ /dev/null @@ -1,19 +0,0 @@ -module demo1(input clk, input addtwo, output iseven); - reg [3:0] cnt; - wire [3:0] next_cnt; - - inc inc_inst (addtwo, iseven, cnt, next_cnt); - - always @(posedge clk) - cnt = (iseven ? cnt == 10 : cnt == 11) ? 0 : next_cnt; - -`ifdef FORMAL - assert property (cnt != 15); - initial assume (!cnt[2]); -`endif -endmodule - -module inc(input addtwo, output iseven, input [3:0] a, output [3:0] y); - assign iseven = !a[0]; - assign y = a + (addtwo ? 2 : 1); -endmodule diff --git a/yosys/examples/smtbmc/demo2.v b/yosys/examples/smtbmc/demo2.v deleted file mode 100644 index 0cf529a42..000000000 --- a/yosys/examples/smtbmc/demo2.v +++ /dev/null @@ -1,29 +0,0 @@ -// Nothing to prove in this demo. -// Just an example for memories, vcd dumps and vlog testbench dumps. - -`ifdef FORMAL -`define assume(_expr_) assume(_expr_) -`else -`define assume(_expr_) -`endif - -module demo2(input clk, input [4:0] addr, output reg [31:0] data); - reg [31:0] mem [0:31]; - always @(negedge clk) - data <= mem[addr]; - - reg [31:0] used_addr = 0; - reg [31:0] used_dbits = 0; - reg initstate = 1; - - always @(posedge clk) begin - initstate <= 0; - `assume(!used_addr[addr]); - used_addr[addr] <= 1; - if (!initstate) begin - `assume(data != 0); - `assume((used_dbits & data) == 0); - used_dbits <= used_dbits | data; - end - end -endmodule diff --git a/yosys/examples/smtbmc/demo3.smtc b/yosys/examples/smtbmc/demo3.smtc deleted file mode 100644 index f5e017cf0..000000000 --- a/yosys/examples/smtbmc/demo3.smtc +++ /dev/null @@ -1,5 +0,0 @@ -initial -assume [rst] - -always -1 -assert (= [-1:mem] [mem]) diff --git a/yosys/examples/smtbmc/demo3.v b/yosys/examples/smtbmc/demo3.v deleted file mode 100644 index 13b3a1970..000000000 --- a/yosys/examples/smtbmc/demo3.v +++ /dev/null @@ -1,18 +0,0 @@ -// Whatever the initial content of this memory is at reset, it will never change -// see demo3.smtc for assumptions and assertions - -module demo3(input clk, rst, input [15:0] addr, output reg [31:0] data); - reg [31:0] mem [0:2**16-1]; - reg [15:0] addr_q; - - always @(posedge clk) begin - if (rst) begin - data <= mem[0] ^ 123456789; - addr_q <= 0; - end else begin - mem[addr_q] <= data ^ 123456789; - data <= mem[addr] ^ 123456789; - addr_q <= addr; - end - end -endmodule diff --git a/yosys/examples/smtbmc/demo4.smtc b/yosys/examples/smtbmc/demo4.smtc deleted file mode 100644 index 2f91f8164..000000000 --- a/yosys/examples/smtbmc/demo4.smtc +++ /dev/null @@ -1,11 +0,0 @@ -initial -assume [rst] - -always -1 -assume (not [rst]) -assume (=> [-1:inv2] [inv2]) - -final -2 -assume [-1:inv2] -assume (not [-2:inv2]) -assert (= [r1] [r2]) diff --git a/yosys/examples/smtbmc/demo4.v b/yosys/examples/smtbmc/demo4.v deleted file mode 100644 index 3f1b47277..000000000 --- a/yosys/examples/smtbmc/demo4.v +++ /dev/null @@ -1,13 +0,0 @@ -// Demo for "final" smtc constraints - -module demo4(input clk, rst, inv2, input [15:0] in, output reg [15:0] r1, r2); - always @(posedge clk) begin - if (rst) begin - r1 <= in; - r2 <= -in; - end else begin - r1 <= r1 + in; - r2 <= inv2 ? -(r2 - in) : (r2 - in); - end - end -endmodule diff --git a/yosys/examples/smtbmc/demo5.v b/yosys/examples/smtbmc/demo5.v deleted file mode 100644 index 63ace307c..000000000 --- a/yosys/examples/smtbmc/demo5.v +++ /dev/null @@ -1,18 +0,0 @@ -// Demo for $anyconst - -module demo5 (input clk); - wire [7:0] step_size = $anyconst; - reg [7:0] state = 0, count = 0; - reg [31:0] hash = 0; - - always @(posedge clk) begin - count <= count + 1; - hash <= ((hash << 5) + hash) ^ state; - state <= state + step_size; - end - - always @* begin - if (count == 42) - assert(hash == 32'h A18FAC0A); - end -endmodule diff --git a/yosys/examples/smtbmc/demo6.v b/yosys/examples/smtbmc/demo6.v deleted file mode 100644 index 62a72e2a8..000000000 --- a/yosys/examples/smtbmc/demo6.v +++ /dev/null @@ -1,14 +0,0 @@ -// Demo for assertpmux - -module demo6 (input A, B, C, D, E, output reg Y); - always @* begin - Y = 0; - if (A != B) begin - (* parallel_case *) - case (C) - A: Y = D; - B: Y = E; - endcase - end - end -endmodule diff --git a/yosys/examples/smtbmc/demo7.v b/yosys/examples/smtbmc/demo7.v deleted file mode 100644 index 63f6272f1..000000000 --- a/yosys/examples/smtbmc/demo7.v +++ /dev/null @@ -1,19 +0,0 @@ -// Demo for memory initialization - -module demo7; - wire [2:0] addr = $anyseq; - reg [15:0] memory [0:7]; - - initial begin - memory[0] = 1331; - memory[1] = 1331 + 1; - memory[2] = 1331 + 2; - memory[3] = 1331 + 4; - memory[4] = 1331 + 8; - memory[5] = 1331 + 16; - memory[6] = 1331 + 32; - memory[7] = 1331 + 64; - end - - assert property (1000 < memory[addr] && memory[addr] < 2000); -endmodule diff --git a/yosys/examples/smtbmc/demo8.v b/yosys/examples/smtbmc/demo8.v deleted file mode 100644 index c4c396cde..000000000 --- a/yosys/examples/smtbmc/demo8.v +++ /dev/null @@ -1,12 +0,0 @@ -// Simple exists-forall demo - -module demo8; - wire [7:0] prime = $anyconst; - wire [3:0] factor = $allconst; - - always @* begin - if (1 < factor && factor < prime) - assume((prime % factor) != 0); - assume(prime > 1); - end -endmodule diff --git a/yosys/frontends/aiger/Makefile.inc b/yosys/frontends/aiger/Makefile.inc deleted file mode 100644 index bc1112452..000000000 --- a/yosys/frontends/aiger/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += frontends/aiger/aigerparse.o - diff --git a/yosys/frontends/aiger/aigerparse.cc b/yosys/frontends/aiger/aigerparse.cc deleted file mode 100644 index 68552fd06..000000000 --- a/yosys/frontends/aiger/aigerparse.cc +++ /dev/null @@ -1,451 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * Eddie Hung - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// [[CITE]] The AIGER And-Inverter Graph (AIG) Format Version 20071012 -// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria. -// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf - -#ifndef _WIN32 -#include -#endif -#include - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" -#include "aigerparse.h" - -YOSYS_NAMESPACE_BEGIN - -AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name) - : design(design), f(f), clk_name(clk_name) -{ - module = new RTLIL::Module; - module->name = module_name; - if (design->module(module->name)) - log_error("Duplicate definition of module %s!\n", log_id(module->name)); -} - -void AigerReader::parse_aiger() -{ - std::string header; - f >> header; - if (header != "aag" && header != "aig") - log_error("Unsupported AIGER file!\n"); - - // Parse rest of header - if (!(f >> M >> I >> L >> O >> A)) - log_error("Invalid AIGER header\n"); - - // Optional values - B = C = J = F = 0; - if (f.peek() != ' ') goto end_of_header; - if (!(f >> B)) log_error("Invalid AIGER header\n"); - if (f.peek() != ' ') goto end_of_header; - if (!(f >> C)) log_error("Invalid AIGER header\n"); - if (f.peek() != ' ') goto end_of_header; - if (!(f >> J)) log_error("Invalid AIGER header\n"); - if (f.peek() != ' ') goto end_of_header; - if (!(f >> F)) log_error("Invalid AIGER header\n"); -end_of_header: - - std::string line; - std::getline(f, line); // Ignore up to start of next line, as standard - // says anything that follows could be used for - // optional sections - - log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F); - - line_count = 1; - - if (header == "aag") - parse_aiger_ascii(); - else if (header == "aig") - parse_aiger_binary(); - else - log_abort(); - - RTLIL::Wire* n0 = module->wire("\\n0"); - if (n0) - module->connect(n0, RTLIL::S0); - - for (unsigned i = 0; i < outputs.size(); ++i) { - RTLIL::Wire *wire = outputs[i]; - if (wire->port_input) { - RTLIL::Wire *o_wire = module->addWire(wire->name.str() + "_o"); - o_wire->port_output = true; - wire->port_output = false; - module->connect(o_wire, wire); - outputs[i] = o_wire; - } - } - - // Parse footer (symbol table, comments, etc.) - unsigned l1; - std::string s; - for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) { - if (c == 'i' || c == 'l' || c == 'o' || c == 'b') { - f.ignore(1); - if (!(f >> l1 >> s)) - log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count); - - if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size())) - log_error("Line %u has invalid symbol position!\n", line_count); - - RTLIL::Wire* wire; - if (c == 'i') wire = inputs[l1]; - else if (c == 'l') wire = latches[l1]; - else if (c == 'o') wire = outputs[l1]; - else if (c == 'b') wire = bad_properties[l1]; - else log_abort(); - - module->rename(wire, stringf("\\%s", s.c_str())); - } - else if (c == 'j' || c == 'f') { - // TODO - } - else if (c == 'c') { - f.ignore(1); - if (f.peek() == '\n') - break; - // Else constraint (TODO) - } - else - log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); - std::getline(f, line); // Ignore up to start of next line - } - - module->fixup_ports(); - design->add(module); -} - -static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal) -{ - const unsigned variable = literal >> 1; - const bool invert = literal & 1; - RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix? - RTLIL::Wire *wire = module->wire(wire_name); - if (wire) return wire; - log_debug("Creating %s\n", wire_name.c_str()); - wire = module->addWire(wire_name); - if (!invert) return wire; - RTLIL::IdString wire_inv_name(stringf("\\n%d", variable)); - RTLIL::Wire *wire_inv = module->wire(wire_inv_name); - if (wire_inv) { - if (module->cell(wire_inv_name)) return wire; - } - else { - log_debug("Creating %s\n", wire_inv_name.c_str()); - wire_inv = module->addWire(wire_inv_name); - } - - log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); - module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix? - - return wire; -} - -void AigerReader::parse_aiger_ascii() -{ - std::string line; - std::stringstream ss; - - unsigned l1, l2, l3; - - // Parse inputs - for (unsigned i = 1; i <= I; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an input!\n", line_count); - log_debug("%d is an input\n", l1); - log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted? - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_input = true; - inputs.push_back(wire); - } - - // Parse latches - RTLIL::Wire *clk_wire = nullptr; - if (L > 0) { - clk_wire = module->wire(clk_name); - log_assert(!clk_wire); - log_debug("Creating %s\n", clk_name.c_str()); - clk_wire = module->addWire(clk_name); - clk_wire->port_input = true; - } - for (unsigned i = 0; i < L; ++i, ++line_count) { - if (!(f >> l1 >> l2)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - log_debug("%d %d is a latch\n", l1, l2); - log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted? - RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - - module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); - - // Reset logic is optional in AIGER 1.9 - if (f.peek() == ' ') { - if (!(f >> l3)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - - if (l3 == 0) - q_wire->attributes["\\init"] = RTLIL::S0; - else if (l3 == 1) - q_wire->attributes["\\init"] = RTLIL::S1; - else if (l3 == l1) { - //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); - } - else - log_error("Line %u has invalid reset literal for latch!\n", line_count); - } - else { - // AIGER latches are assumed to be initialized to zero - q_wire->attributes["\\init"] = RTLIL::S0; - } - latches.push_back(q_wire); - } - - // Parse outputs - for (unsigned i = 0; i < O; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an output!\n", line_count); - - log_debug("%d is an output\n", l1); - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_output = true; - outputs.push_back(wire); - } - - // Parse bad properties - for (unsigned i = 0; i < B; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as a bad state property!\n", line_count); - - log_debug("%d is a bad state property\n", l1); - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_output = true; - bad_properties.push_back(wire); - } - - // TODO: Parse invariant constraints - for (unsigned i = 0; i < C; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse justice properties - for (unsigned i = 0; i < J; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse fairness constraints - for (unsigned i = 0; i < F; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // Parse AND - for (unsigned i = 0; i < A; ++i) { - if (!(f >> l1 >> l2 >> l3)) - log_error("Line %u cannot be interpreted as an AND!\n", line_count); - - log_debug("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted? - RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); - RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); - module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire); - } - std::getline(f, line); // Ignore up to start of next line -} - -static unsigned parse_next_delta_literal(std::istream &f, unsigned ref) -{ - unsigned x = 0, i = 0; - unsigned char ch; - while ((ch = f.get()) & 0x80) - x |= (ch & 0x7f) << (7 * i++); - return ref - (x | (ch << (7 * i))); -} - -void AigerReader::parse_aiger_binary() -{ - unsigned l1, l2, l3; - std::string line; - - // Parse inputs - for (unsigned i = 1; i <= I; ++i) { - RTLIL::Wire *wire = createWireIfNotExists(module, i << 1); - wire->port_input = true; - inputs.push_back(wire); - } - - // Parse latches - RTLIL::Wire *clk_wire = nullptr; - if (L > 0) { - clk_wire = module->wire(clk_name); - log_assert(!clk_wire); - log_debug("Creating %s\n", clk_name.c_str()); - clk_wire = module->addWire(clk_name); - clk_wire->port_input = true; - } - l1 = (I+1) * 2; - for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) { - if (!(f >> l2)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - log_debug("%d %d is a latch\n", l1, l2); - RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - - module->addDff(NEW_ID, clk_wire, d_wire, q_wire); - - // Reset logic is optional in AIGER 1.9 - if (f.peek() == ' ') { - if (!(f >> l3)) - log_error("Line %u cannot be interpreted as a latch!\n", line_count); - - if (l3 == 0) - q_wire->attributes["\\init"] = RTLIL::S0; - else if (l3 == 1) - q_wire->attributes["\\init"] = RTLIL::S1; - else if (l3 == l1) { - //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx); - } - else - log_error("Line %u has invalid reset literal for latch!\n", line_count); - } - else { - // AIGER latches are assumed to be initialized to zero - q_wire->attributes["\\init"] = RTLIL::S0; - } - latches.push_back(q_wire); - } - - // Parse outputs - for (unsigned i = 0; i < O; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as an output!\n", line_count); - - log_debug("%d is an output\n", l1); - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_output = true; - outputs.push_back(wire); - } - std::getline(f, line); // Ignore up to start of next line - - // Parse bad properties - for (unsigned i = 0; i < B; ++i, ++line_count) { - if (!(f >> l1)) - log_error("Line %u cannot be interpreted as a bad state property!\n", line_count); - - log_debug("%d is a bad state property\n", l1); - RTLIL::Wire *wire = createWireIfNotExists(module, l1); - wire->port_output = true; - bad_properties.push_back(wire); - } - if (B > 0) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse invariant constraints - for (unsigned i = 0; i < C; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse justice properties - for (unsigned i = 0; i < J; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // TODO: Parse fairness constraints - for (unsigned i = 0; i < F; ++i, ++line_count) - std::getline(f, line); // Ignore up to start of next line - - // Parse AND - l1 = (I+L+1) << 1; - for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) { - l2 = parse_next_delta_literal(f, l1); - l3 = parse_next_delta_literal(f, l2); - - log_debug("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted? - RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); - RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); - - RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_"); - and_cell->setPort("\\A", i1_wire); - and_cell->setPort("\\B", i2_wire); - and_cell->setPort("\\Y", o_wire); - } -} - -struct AigerFrontend : public Frontend { - AigerFrontend() : Frontend("aiger", "read AIGER file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_aiger [options] [filename]\n"); - log("\n"); - log("Load module from an AIGER file into the current design.\n"); - log("\n"); - log(" -module_name \n"); - log(" Name of module to be created (default: " -#ifdef _WIN32 - "top" // FIXME -#else - "" -#endif - ")\n"); - log("\n"); - log(" -clk_name \n"); - log(" AIGER latches to be transformed into posedge DFFs clocked by wire of"); - log(" this name (default: clk)\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing AIGER frontend.\n"); - - RTLIL::IdString clk_name = "\\clk"; - RTLIL::IdString module_name; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-module_name" && argidx+1 < args.size()) { - module_name = RTLIL::escape_id(args[++argidx]); - continue; - } - if (arg == "-clk_name" && argidx+1 < args.size()) { - clk_name = RTLIL::escape_id(args[++argidx]); - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - if (module_name.empty()) { -#ifdef _WIN32 - module_name = "top"; // FIXME: basename equivalent on Win32? -#else - char* bn = strdup(filename.c_str()); - module_name = RTLIL::escape_id(bn); - free(bn); -#endif - } - - AigerReader reader(design, *f, module_name, clk_name); - reader.parse_aiger(); - } -} AigerFrontend; - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/aiger/aigerparse.h b/yosys/frontends/aiger/aigerparse.h deleted file mode 100644 index 0e3719cc4..000000000 --- a/yosys/frontends/aiger/aigerparse.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * Eddie Hung - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef ABC_AIGERPARSE -#define ABC_AIGERPARSE - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -struct AigerReader -{ - RTLIL::Design *design; - std::istream &f; - RTLIL::IdString clk_name; - RTLIL::Module *module; - - unsigned M, I, L, O, A; - unsigned B, C, J, F; // Optional in AIGER 1.9 - unsigned line_count; - - std::vector inputs; - std::vector latches; - std::vector outputs; - std::vector bad_properties; - - AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name); - void parse_aiger(); - void parse_aiger_ascii(); - void parse_aiger_binary(); -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/ast/Makefile.inc b/yosys/frontends/ast/Makefile.inc deleted file mode 100644 index 91d917c91..000000000 --- a/yosys/frontends/ast/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ - -OBJS += frontends/ast/ast.o -OBJS += frontends/ast/simplify.o -OBJS += frontends/ast/genrtlil.o -OBJS += frontends/ast/dpicall.o - diff --git a/yosys/frontends/ast/ast.cc b/yosys/frontends/ast/ast.cc deleted file mode 100644 index 3d066af53..000000000 --- a/yosys/frontends/ast/ast.cc +++ /dev/null @@ -1,1581 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * Copyright (C) 2018 Ruben Undheim - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * This is the AST frontend library. - * - * The AST frontend library is not a frontend on it's own but provides a - * generic abstract syntax tree (AST) abstraction for HDL code and can be - * used by HDL frontends. See "ast.h" for an overview of the API and the - * Verilog frontend for an usage example. - * - */ - -#include "kernel/yosys.h" -#include "libs/sha1/sha1.h" -#include "ast.h" - -YOSYS_NAMESPACE_BEGIN - -using namespace AST; -using namespace AST_INTERNAL; - -// instantiate global variables (public API) -namespace AST { - std::string current_filename; - void (*set_line_num)(int) = NULL; - int (*get_line_num)() = NULL; -} - -// instantiate global variables (private API) -namespace AST_INTERNAL { - bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; - bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_autowire; - AstNode *current_ast, *current_ast_mod; - std::map current_scope; - const dict *genRTLIL_subst_ptr = NULL; - RTLIL::SigSpec ignoreThisSignalsInInitial; - AstNode *current_always, *current_top_block, *current_block, *current_block_child; - AstModule *current_module; - bool current_always_clocked; -} - -// convert node types to string -std::string AST::type2str(AstNodeType type) -{ - switch (type) - { -#define X(_item) case _item: return #_item; - X(AST_NONE) - X(AST_DESIGN) - X(AST_MODULE) - X(AST_TASK) - X(AST_FUNCTION) - X(AST_DPI_FUNCTION) - X(AST_WIRE) - X(AST_MEMORY) - X(AST_AUTOWIRE) - X(AST_PARAMETER) - X(AST_LOCALPARAM) - X(AST_DEFPARAM) - X(AST_PARASET) - X(AST_ARGUMENT) - X(AST_RANGE) - X(AST_MULTIRANGE) - X(AST_CONSTANT) - X(AST_REALVALUE) - X(AST_CELLTYPE) - X(AST_IDENTIFIER) - X(AST_PREFIX) - X(AST_ASSERT) - X(AST_ASSUME) - X(AST_LIVE) - X(AST_FAIR) - X(AST_COVER) - X(AST_FCALL) - X(AST_TO_BITS) - X(AST_TO_SIGNED) - X(AST_TO_UNSIGNED) - X(AST_CONCAT) - X(AST_REPLICATE) - X(AST_BIT_NOT) - X(AST_BIT_AND) - X(AST_BIT_OR) - X(AST_BIT_XOR) - X(AST_BIT_XNOR) - X(AST_REDUCE_AND) - X(AST_REDUCE_OR) - X(AST_REDUCE_XOR) - X(AST_REDUCE_XNOR) - X(AST_REDUCE_BOOL) - X(AST_SHIFT_LEFT) - X(AST_SHIFT_RIGHT) - X(AST_SHIFT_SLEFT) - X(AST_SHIFT_SRIGHT) - X(AST_LT) - X(AST_LE) - X(AST_EQ) - X(AST_NE) - X(AST_EQX) - X(AST_NEX) - X(AST_GE) - X(AST_GT) - X(AST_ADD) - X(AST_SUB) - X(AST_MUL) - X(AST_DIV) - X(AST_MOD) - X(AST_POW) - X(AST_POS) - X(AST_NEG) - X(AST_LOGIC_AND) - X(AST_LOGIC_OR) - X(AST_LOGIC_NOT) - X(AST_TERNARY) - X(AST_MEMRD) - X(AST_MEMWR) - X(AST_MEMINIT) - X(AST_TCALL) - X(AST_ASSIGN) - X(AST_CELL) - X(AST_PRIMITIVE) - X(AST_CELLARRAY) - X(AST_ALWAYS) - X(AST_INITIAL) - X(AST_BLOCK) - X(AST_ASSIGN_EQ) - X(AST_ASSIGN_LE) - X(AST_CASE) - X(AST_COND) - X(AST_CONDX) - X(AST_CONDZ) - X(AST_DEFAULT) - X(AST_FOR) - X(AST_WHILE) - X(AST_REPEAT) - X(AST_GENVAR) - X(AST_GENFOR) - X(AST_GENIF) - X(AST_GENCASE) - X(AST_GENBLOCK) - X(AST_TECALL) - X(AST_POSEDGE) - X(AST_NEGEDGE) - X(AST_EDGE) - X(AST_PACKAGE) -#undef X - default: - log_abort(); - } -} - -// check if attribute exists and has non-zero value -bool AstNode::get_bool_attribute(RTLIL::IdString id) -{ - if (attributes.count(id) == 0) - return false; - - AstNode *attr = attributes.at(id); - if (attr->type != AST_CONSTANT) - log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n", id.c_str()); - - return attr->integer != 0; -} - -// create new node (AstNode constructor) -// (the optional child arguments make it easier to create AST trees) -AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3) -{ - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; - - this->type = type; - filename = current_filename; - linenum = get_line_num(); - is_input = false; - is_output = false; - is_reg = false; - is_logic = false; - is_signed = false; - is_string = false; - is_wand = false; - is_wor = false; - is_unsized = false; - was_checked = false; - range_valid = false; - range_swapped = false; - port_id = 0; - range_left = -1; - range_right = 0; - integer = 0; - realvalue = 0; - id2ast = NULL; - basic_prep = false; - - if (child1) - children.push_back(child1); - if (child2) - children.push_back(child2); - if (child3) - children.push_back(child3); -} - -// create a (deep recursive) copy of a node -AstNode *AstNode::clone() const -{ - AstNode *that = new AstNode; - *that = *this; - for (auto &it : that->children) - it = it->clone(); - for (auto &it : that->attributes) - it.second = it.second->clone(); - return that; -} - -// create a (deep recursive) copy of a node use 'other' as target root node -void AstNode::cloneInto(AstNode *other) const -{ - AstNode *tmp = clone(); - other->delete_children(); - *other = *tmp; - tmp->children.clear(); - tmp->attributes.clear(); - delete tmp; -} - -// delete all children in this node -void AstNode::delete_children() -{ - for (auto &it : children) - delete it; - children.clear(); - - for (auto &it : attributes) - delete it.second; - attributes.clear(); -} - -// AstNode destructor -AstNode::~AstNode() -{ - delete_children(); -} - -// create a nice text representation of the node -// (traverse tree by recursion, use 'other' pointer for diffing two AST trees) -void AstNode::dumpAst(FILE *f, std::string indent) const -{ - if (f == NULL) { - for (auto f : log_files) - dumpAst(f, indent); - return; - } - - std::string type_name = type2str(type); - fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum); - - if (!flag_no_dump_ptr) { - if (id2ast) - fprintf(f, " [%p -> %p]", this, id2ast); - else - fprintf(f, " [%p]", this); - } - - if (!str.empty()) - fprintf(f, " str='%s'", str.c_str()); - if (!bits.empty()) { - fprintf(f, " bits='"); - for (size_t i = bits.size(); i > 0; i--) - fprintf(f, "%c", bits[i-1] == RTLIL::S0 ? '0' : - bits[i-1] == RTLIL::S1 ? '1' : - bits[i-1] == RTLIL::Sx ? 'x' : - bits[i-1] == RTLIL::Sz ? 'z' : '?'); - fprintf(f, "'(%d)", GetSize(bits)); - } - if (is_input) - fprintf(f, " input"); - if (is_output) - fprintf(f, " output"); - if (is_logic) - fprintf(f, " logic"); - if (is_reg) // this is an AST dump, not Verilog - if we see "logic reg" that's fine. - fprintf(f, " reg"); - if (is_signed) - fprintf(f, " signed"); - if (port_id > 0) - fprintf(f, " port=%d", port_id); - if (range_valid || range_left != -1 || range_right != 0) - fprintf(f, " %srange=[%d:%d]%s", range_swapped ? "swapped_" : "", range_left, range_right, range_valid ? "" : "!"); - if (integer != 0) - fprintf(f, " int=%u", (int)integer); - if (realvalue != 0) - fprintf(f, " real=%e", realvalue); - if (!multirange_dimensions.empty()) { - fprintf(f, " multirange=["); - for (int v : multirange_dimensions) - fprintf(f, " %d", v); - fprintf(f, " ]"); - } - fprintf(f, "\n"); - - for (auto &it : attributes) { - fprintf(f, "%s ATTR %s:\n", indent.c_str(), it.first.c_str()); - it.second->dumpAst(f, indent + " "); - } - - for (size_t i = 0; i < children.size(); i++) - children[i]->dumpAst(f, indent + " "); - - fflush(f); -} - -// helper function for AstNode::dumpVlog() -static std::string id2vl(std::string txt) -{ - if (txt.size() > 1 && txt[0] == '\\') - txt = txt.substr(1); - for (size_t i = 0; i < txt.size(); i++) { - if ('A' <= txt[i] && txt[i] <= 'Z') continue; - if ('a' <= txt[i] && txt[i] <= 'z') continue; - if ('0' <= txt[i] && txt[i] <= '9') continue; - if (txt[i] == '_') continue; - txt = "\\" + txt + " "; - break; - } - return txt; -} - -// dump AST node as Verilog pseudo-code -void AstNode::dumpVlog(FILE *f, std::string indent) const -{ - bool first = true; - std::string txt; - std::vector rem_children1, rem_children2; - - if (f == NULL) { - for (auto f : log_files) - dumpVlog(f, indent); - return; - } - - for (auto &it : attributes) { - fprintf(f, "%s" "(* %s = ", indent.c_str(), id2vl(it.first.str()).c_str()); - it.second->dumpVlog(f, ""); - fprintf(f, " *)%s", indent.empty() ? "" : "\n"); - } - - switch (type) - { - case AST_MODULE: - fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str()); - for (auto child : children) - if (child->type == AST_WIRE && (child->is_input || child->is_output)) { - fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str()); - first = false; - } - fprintf(f, ");\n"); - - for (auto child : children) - if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_DEFPARAM) - child->dumpVlog(f, indent + " "); - else - rem_children1.push_back(child); - - for (auto child : rem_children1) - if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY) - child->dumpVlog(f, indent + " "); - else - rem_children2.push_back(child); - rem_children1.clear(); - - for (auto child : rem_children2) - if (child->type == AST_TASK || child->type == AST_FUNCTION) - child->dumpVlog(f, indent + " "); - else - rem_children1.push_back(child); - rem_children2.clear(); - - for (auto child : rem_children1) - child->dumpVlog(f, indent + " "); - rem_children1.clear(); - - fprintf(f, "%s" "endmodule\n", indent.c_str()); - break; - - case AST_WIRE: - if (is_input && is_output) - fprintf(f, "%s" "inout", indent.c_str()); - else if (is_input) - fprintf(f, "%s" "input", indent.c_str()); - else if (is_output) - fprintf(f, "%s" "output", indent.c_str()); - else if (!is_reg) - fprintf(f, "%s" "wire", indent.c_str()); - if (is_reg) - fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str()); - if (is_signed) - fprintf(f, " signed"); - for (auto child : children) { - fprintf(f, " "); - child->dumpVlog(f, ""); - } - fprintf(f, " %s", id2vl(str).c_str()); - fprintf(f, ";\n"); - break; - - case AST_MEMORY: - fprintf(f, "%s" "memory", indent.c_str()); - if (is_signed) - fprintf(f, " signed"); - for (auto child : children) { - fprintf(f, " "); - child->dumpVlog(f, ""); - if (first) - fprintf(f, " %s", id2vl(str).c_str()); - first = false; - } - fprintf(f, ";\n"); - break; - - case AST_RANGE: - if (range_valid) { - if (range_swapped) - fprintf(f, "[%d:%d]", range_right, range_left); - else - fprintf(f, "[%d:%d]", range_left, range_right); - } else { - for (auto child : children) { - fprintf(f, "%c", first ? '[' : ':'); - child->dumpVlog(f, ""); - first = false; - } - fprintf(f, "]"); - } - break; - - case AST_ALWAYS: - fprintf(f, "%s" "always @", indent.c_str()); - for (auto child : children) { - if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) - continue; - fprintf(f, first ? "(" : ", "); - child->dumpVlog(f, ""); - first = false; - } - fprintf(f, first ? "*\n" : ")\n"); - for (auto child : children) { - if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) - child->dumpVlog(f, indent + " "); - } - break; - - case AST_INITIAL: - fprintf(f, "%s" "initial\n", indent.c_str()); - for (auto child : children) { - if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) - child->dumpVlog(f, indent + " "); - } - break; - - case AST_POSEDGE: - case AST_NEGEDGE: - case AST_EDGE: - if (type == AST_POSEDGE) - fprintf(f, "posedge "); - if (type == AST_NEGEDGE) - fprintf(f, "negedge "); - for (auto child : children) - child->dumpVlog(f, ""); - break; - - case AST_IDENTIFIER: - fprintf(f, "%s", id2vl(str).c_str()); - for (auto child : children) - child->dumpVlog(f, ""); - break; - - case AST_CONSTANT: - if (!str.empty()) - fprintf(f, "\"%s\"", str.c_str()); - else if (bits.size() == 32) - fprintf(f, "%d", RTLIL::Const(bits).as_int()); - else - fprintf(f, "%d'b %s", GetSize(bits), RTLIL::Const(bits).as_string().c_str()); - break; - - case AST_REALVALUE: - fprintf(f, "%e", realvalue); - break; - - case AST_BLOCK: - if (children.size() == 1) { - children[0]->dumpVlog(f, indent); - } else { - fprintf(f, "%s" "begin\n", indent.c_str()); - for (auto child : children) - child->dumpVlog(f, indent + " "); - fprintf(f, "%s" "end\n", indent.c_str()); - } - break; - - case AST_CASE: - if (!children.empty() && children[0]->type == AST_CONDX) - fprintf(f, "%s" "casex (", indent.c_str()); - else if (!children.empty() && children[0]->type == AST_CONDZ) - fprintf(f, "%s" "casez (", indent.c_str()); - else - fprintf(f, "%s" "case (", indent.c_str()); - children[0]->dumpVlog(f, ""); - fprintf(f, ")\n"); - for (size_t i = 1; i < children.size(); i++) { - AstNode *child = children[i]; - child->dumpVlog(f, indent + " "); - } - fprintf(f, "%s" "endcase\n", indent.c_str()); - break; - - case AST_COND: - case AST_CONDX: - case AST_CONDZ: - for (auto child : children) { - if (child->type == AST_BLOCK) { - fprintf(f, ":\n"); - child->dumpVlog(f, indent + " "); - first = true; - } else { - fprintf(f, "%s", first ? indent.c_str() : ", "); - if (child->type == AST_DEFAULT) - fprintf(f, "default"); - else - child->dumpVlog(f, ""); - first = false; - } - } - break; - - case AST_ASSIGN: - fprintf(f, "%sassign ", indent.c_str()); - children[0]->dumpVlog(f, ""); - fprintf(f, " = "); - children[1]->dumpVlog(f, ""); - fprintf(f, ";\n"); - break; - - case AST_ASSIGN_EQ: - case AST_ASSIGN_LE: - fprintf(f, "%s", indent.c_str()); - children[0]->dumpVlog(f, ""); - fprintf(f, " %s ", type == AST_ASSIGN_EQ ? "=" : "<="); - children[1]->dumpVlog(f, ""); - fprintf(f, ";\n"); - break; - - case AST_CONCAT: - fprintf(f, "{"); - for (int i = GetSize(children)-1; i >= 0; i--) { - auto child = children[i]; - if (!first) - fprintf(f, ", "); - child->dumpVlog(f, ""); - first = false; - } - fprintf(f, "}"); - break; - - case AST_REPLICATE: - fprintf(f, "{"); - children[0]->dumpVlog(f, ""); - fprintf(f, "{"); - children[1]->dumpVlog(f, ""); - fprintf(f, "}}"); - break; - - if (0) { case AST_BIT_NOT: txt = "~"; } - if (0) { case AST_REDUCE_AND: txt = "&"; } - if (0) { case AST_REDUCE_OR: txt = "|"; } - if (0) { case AST_REDUCE_XOR: txt = "^"; } - if (0) { case AST_REDUCE_XNOR: txt = "~^"; } - if (0) { case AST_REDUCE_BOOL: txt = "|"; } - if (0) { case AST_POS: txt = "+"; } - if (0) { case AST_NEG: txt = "-"; } - if (0) { case AST_LOGIC_NOT: txt = "!"; } - fprintf(f, "%s(", txt.c_str()); - children[0]->dumpVlog(f, ""); - fprintf(f, ")"); - break; - - if (0) { case AST_BIT_AND: txt = "&"; } - if (0) { case AST_BIT_OR: txt = "|"; } - if (0) { case AST_BIT_XOR: txt = "^"; } - if (0) { case AST_BIT_XNOR: txt = "~^"; } - if (0) { case AST_SHIFT_LEFT: txt = "<<"; } - if (0) { case AST_SHIFT_RIGHT: txt = ">>"; } - if (0) { case AST_SHIFT_SLEFT: txt = "<<<"; } - if (0) { case AST_SHIFT_SRIGHT: txt = ">>>"; } - if (0) { case AST_LT: txt = "<"; } - if (0) { case AST_LE: txt = "<="; } - if (0) { case AST_EQ: txt = "=="; } - if (0) { case AST_NE: txt = "!="; } - if (0) { case AST_EQX: txt = "==="; } - if (0) { case AST_NEX: txt = "!=="; } - if (0) { case AST_GE: txt = ">="; } - if (0) { case AST_GT: txt = ">"; } - if (0) { case AST_ADD: txt = "+"; } - if (0) { case AST_SUB: txt = "-"; } - if (0) { case AST_MUL: txt = "*"; } - if (0) { case AST_DIV: txt = "/"; } - if (0) { case AST_MOD: txt = "%"; } - if (0) { case AST_POW: txt = "**"; } - if (0) { case AST_LOGIC_AND: txt = "&&"; } - if (0) { case AST_LOGIC_OR: txt = "||"; } - fprintf(f, "("); - children[0]->dumpVlog(f, ""); - fprintf(f, ")%s(", txt.c_str()); - children[1]->dumpVlog(f, ""); - fprintf(f, ")"); - break; - - case AST_TERNARY: - fprintf(f, "("); - children[0]->dumpVlog(f, ""); - fprintf(f, ") ? ("); - children[1]->dumpVlog(f, ""); - fprintf(f, ") : ("); - children[2]->dumpVlog(f, ""); - fprintf(f, ")"); - break; - - default: - std::string type_name = type2str(type); - fprintf(f, "%s" "/** %s **/%s", indent.c_str(), type_name.c_str(), indent.empty() ? "" : "\n"); - // dumpAst(f, indent, NULL); - } - - fflush(f); -} - -// check if two AST nodes are identical -bool AstNode::operator==(const AstNode &other) const -{ - if (type != other.type) - return false; - if (children.size() != other.children.size()) - return false; - if (str != other.str) - return false; - if (bits != other.bits) - return false; - if (is_input != other.is_input) - return false; - if (is_output != other.is_output) - return false; - if (is_logic != other.is_logic) - return false; - if (is_reg != other.is_reg) - return false; - if (is_signed != other.is_signed) - return false; - if (is_string != other.is_string) - return false; - if (range_valid != other.range_valid) - return false; - if (range_swapped != other.range_swapped) - return false; - if (port_id != other.port_id) - return false; - if (range_left != other.range_left) - return false; - if (range_right != other.range_right) - return false; - if (integer != other.integer) - return false; - for (size_t i = 0; i < children.size(); i++) - if (*children[i] != *other.children[i]) - return false; - return true; -} - -// check if two AST nodes are not identical -bool AstNode::operator!=(const AstNode &other) const -{ - return !(*this == other); -} - -// check if this AST contains the given node -bool AstNode::contains(const AstNode *other) const -{ - if (this == other) - return true; - for (auto child : children) - if (child->contains(other)) - return true; - return false; -} - -// create an AST node for a constant (using a 32 bit int as value) -AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width) -{ - AstNode *node = new AstNode(AST_CONSTANT); - node->integer = v; - node->is_signed = is_signed; - for (int i = 0; i < width; i++) { - node->bits.push_back((v & 1) ? RTLIL::S1 : RTLIL::S0); - v = v >> 1; - } - node->range_valid = true; - node->range_left = width-1; - node->range_right = 0; - return node; -} - -// create an AST node for a constant (using a bit vector as value) -AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized) -{ - AstNode *node = new AstNode(AST_CONSTANT); - node->is_signed = is_signed; - node->bits = v; - for (size_t i = 0; i < 32; i++) { - if (i < node->bits.size()) - node->integer |= (node->bits[i] == RTLIL::S1) << i; - else if (is_signed && !node->bits.empty()) - node->integer |= (node->bits.back() == RTLIL::S1) << i; - } - node->range_valid = true; - node->range_left = node->bits.size()-1; - node->range_right = 0; - node->is_unsized = is_unsized; - return node; -} - -AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed) -{ - return mkconst_bits(v, is_signed, false); -} - -// create an AST node for a constant (using a string in bit vector form as value) -AstNode *AstNode::mkconst_str(const std::vector &v) -{ - AstNode *node = mkconst_str(RTLIL::Const(v).decode_string()); - while (GetSize(node->bits) < GetSize(v)) - node->bits.push_back(RTLIL::State::S0); - log_assert(node->bits == v); - return node; -} - -// create an AST node for a constant (using a string as value) -AstNode *AstNode::mkconst_str(const std::string &str) -{ - std::vector data; - data.reserve(str.size() * 8); - for (size_t i = 0; i < str.size(); i++) { - unsigned char ch = str[str.size() - i - 1]; - for (int j = 0; j < 8; j++) { - data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0); - ch = ch >> 1; - } - } - AstNode *node = AstNode::mkconst_bits(data, false); - node->is_string = true; - node->str = str; - return node; -} - -bool AstNode::bits_only_01() const -{ - for (auto bit : bits) - if (bit != RTLIL::S0 && bit != RTLIL::S1) - return false; - return true; -} - -RTLIL::Const AstNode::bitsAsUnsizedConst(int width) -{ - RTLIL::State extbit = bits.back(); - while (width > int(bits.size())) - bits.push_back(extbit); - return RTLIL::Const(bits); -} - -RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed) -{ - std::vector bits = this->bits; - if (width >= 0 && width < int(bits.size())) - bits.resize(width); - if (width >= 0 && width > int(bits.size())) { - RTLIL::State extbit = RTLIL::State::S0; - if (is_signed && !bits.empty()) - extbit = bits.back(); - while (width > int(bits.size())) - bits.push_back(extbit); - } - return RTLIL::Const(bits); -} - -RTLIL::Const AstNode::bitsAsConst(int width) -{ - return bitsAsConst(width, is_signed); -} - -RTLIL::Const AstNode::asAttrConst() -{ - log_assert(type == AST_CONSTANT); - - RTLIL::Const val; - val.bits = bits; - - if (is_string) { - val.flags |= RTLIL::CONST_FLAG_STRING; - log_assert(val.decode_string() == str); - } - - return val; -} - -RTLIL::Const AstNode::asParaConst() -{ - RTLIL::Const val = asAttrConst(); - if (is_signed) - val.flags |= RTLIL::CONST_FLAG_SIGNED; - return val; -} - -bool AstNode::asBool() const -{ - log_assert(type == AST_CONSTANT); - for (auto &bit : bits) - if (bit == RTLIL::State::S1) - return true; - return false; -} - -int AstNode::isConst() const -{ - if (type == AST_CONSTANT) - return 1; - if (type == AST_REALVALUE) - return 2; - return 0; -} - -uint64_t AstNode::asInt(bool is_signed) -{ - if (type == AST_CONSTANT) - { - RTLIL::Const v = bitsAsConst(64, is_signed); - uint64_t ret = 0; - - for (int i = 0; i < 64; i++) - if (v.bits.at(i) == RTLIL::State::S1) - ret |= uint64_t(1) << i; - - return ret; - } - - if (type == AST_REALVALUE) - return uint64_t(realvalue); - - log_abort(); -} - -double AstNode::asReal(bool is_signed) -{ - if (type == AST_CONSTANT) - { - RTLIL::Const val(bits); - - bool is_negative = is_signed && !val.bits.empty() && val.bits.back() == RTLIL::State::S1; - if (is_negative) - val = const_neg(val, val, false, false, val.bits.size()); - - double v = 0; - for (size_t i = 0; i < val.bits.size(); i++) - // IEEE Std 1800-2012 Par 6.12.2: Individual bits that are x or z in - // the net or the variable shall be treated as zero upon conversion. - if (val.bits.at(i) == RTLIL::State::S1) - v += exp2(i); - if (is_negative) - v *= -1; - - return v; - } - - if (type == AST_REALVALUE) - return realvalue; - - log_abort(); -} - -RTLIL::Const AstNode::realAsConst(int width) -{ - double v = round(realvalue); - RTLIL::Const result; -#ifdef EMSCRIPTEN - if (!isfinite(v)) { -#else - if (!std::isfinite(v)) { -#endif - result.bits = std::vector(width, RTLIL::State::Sx); - } else { - bool is_negative = v < 0; - if (is_negative) - v *= -1; - for (int i = 0; i < width; i++, v /= 2) - result.bits.push_back((fmod(floor(v), 2) != 0) ? RTLIL::State::S1 : RTLIL::State::S0); - if (is_negative) - result = const_neg(result, result, false, false, result.bits.size()); - } - return result; -} - -// create a new AstModule from an AST_MODULE AST node -static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL) -{ - log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); - - if (defer) - log("Storing AST representation for module `%s'.\n", ast->str.c_str()); - else - log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str()); - - current_module = new AstModule; - current_module->ast = NULL; - current_module->name = ast->str; - current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum); - current_module->set_bool_attribute("\\cells_not_processed"); - - current_ast_mod = ast; - AstNode *ast_before_simplify; - if (original_ast != NULL) - ast_before_simplify = original_ast; - else - ast_before_simplify = ast->clone(); - - if (flag_dump_ast1) { - log("Dumping AST before simplification:\n"); - ast->dumpAst(NULL, " "); - log("--- END OF AST DUMP ---\n"); - } - if (flag_dump_vlog1) { - log("Dumping Verilog AST before simplification:\n"); - ast->dumpVlog(NULL, " "); - log("--- END OF AST DUMP ---\n"); - } - - if (!defer) - { - bool blackbox_module = flag_lib; - - if (!blackbox_module && !flag_noblackbox) { - blackbox_module = true; - for (auto child : ast->children) { - if (child->type == AST_WIRE && (child->is_input || child->is_output)) - continue; - if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) - continue; - if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && - (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) - continue; - blackbox_module = false; - break; - } - } - - while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } - - if (flag_dump_ast2) { - log("Dumping AST after simplification:\n"); - ast->dumpAst(NULL, " "); - log("--- END OF AST DUMP ---\n"); - } - - if (flag_dump_vlog2) { - log("Dumping Verilog AST after simplification:\n"); - ast->dumpVlog(NULL, " "); - log("--- END OF AST DUMP ---\n"); - } - - if (flag_nowb && ast->attributes.count("\\whitebox")) { - delete ast->attributes.at("\\whitebox"); - ast->attributes.erase("\\whitebox"); - } - - if (ast->attributes.count("\\lib_whitebox")) { - if (!flag_lib || flag_nowb) { - delete ast->attributes.at("\\lib_whitebox"); - ast->attributes.erase("\\lib_whitebox"); - } else { - if (ast->attributes.count("\\whitebox")) { - delete ast->attributes.at("\\whitebox"); - ast->attributes.erase("\\whitebox"); - } - AstNode *n = ast->attributes.at("\\lib_whitebox"); - ast->attributes["\\whitebox"] = n; - ast->attributes.erase("\\lib_whitebox"); - } - } - - if (!blackbox_module && ast->attributes.count("\\blackbox")) { - AstNode *n = ast->attributes.at("\\blackbox"); - if (n->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n"); - blackbox_module = n->asBool(); - } - - if (blackbox_module && ast->attributes.count("\\whitebox")) { - AstNode *n = ast->attributes.at("\\whitebox"); - if (n->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n"); - blackbox_module = !n->asBool(); - } - - if (ast->attributes.count("\\noblackbox")) { - if (blackbox_module) { - AstNode *n = ast->attributes.at("\\noblackbox"); - if (n->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n"); - blackbox_module = !n->asBool(); - } - delete ast->attributes.at("\\noblackbox"); - ast->attributes.erase("\\noblackbox"); - } - - if (blackbox_module) - { - if (ast->attributes.count("\\whitebox")) { - delete ast->attributes.at("\\whitebox"); - ast->attributes.erase("\\whitebox"); - } - - if (ast->attributes.count("\\lib_whitebox")) { - delete ast->attributes.at("\\lib_whitebox"); - ast->attributes.erase("\\lib_whitebox"); - } - - std::vector new_children; - for (auto child : ast->children) { - if (child->type == AST_WIRE && (child->is_input || child->is_output)) { - new_children.push_back(child); - } else if (child->type == AST_PARAMETER) { - child->delete_children(); - child->children.push_back(AstNode::mkconst_int(0, false, 0)); - new_children.push_back(child); - } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && - (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) { - new_children.push_back(child); - } else { - delete child; - } - } - - ast->children.swap(new_children); - - if (ast->attributes.count("\\blackbox") == 0) { - ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false); - } - } - - ignoreThisSignalsInInitial = RTLIL::SigSpec(); - - for (auto &attr : ast->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - current_module->attributes[attr.first] = attr.second->asAttrConst(); - } - for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; - if (node->type == AST_WIRE || node->type == AST_MEMORY) - node->genRTLIL(); - } - for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; - if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL) - node->genRTLIL(); - } - - ignoreThisSignalsInInitial.sort_and_unify(); - - for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; - if (node->type == AST_INITIAL) - node->genRTLIL(); - } - - ignoreThisSignalsInInitial = RTLIL::SigSpec(); - } - - if (ast->type == AST_INTERFACE) - current_module->set_bool_attribute("\\is_interface"); - current_module->ast = ast_before_simplify; - current_module->nolatches = flag_nolatches; - current_module->nomeminit = flag_nomeminit; - current_module->nomem2reg = flag_nomem2reg; - current_module->mem2reg = flag_mem2reg; - current_module->noblackbox = flag_noblackbox; - current_module->lib = flag_lib; - current_module->nowb = flag_nowb; - current_module->noopt = flag_noopt; - current_module->icells = flag_icells; - current_module->pwires = flag_pwires; - current_module->autowire = flag_autowire; - current_module->fixup_ports(); - - if (flag_dump_rtlil) { - log("Dumping generated RTLIL:\n"); - log_module(current_module); - log("--- END OF RTLIL DUMP ---\n"); - } - - return current_module; -} - -// create AstModule instances for all modules in the AST tree and add them to 'design' -void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, - bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire) -{ - current_ast = ast; - flag_dump_ast1 = dump_ast1; - flag_dump_ast2 = dump_ast2; - flag_no_dump_ptr = no_dump_ptr; - flag_dump_vlog1 = dump_vlog1; - flag_dump_vlog2 = dump_vlog2; - flag_dump_rtlil = dump_rtlil; - flag_nolatches = nolatches; - flag_nomeminit = nomeminit; - flag_nomem2reg = nomem2reg; - flag_mem2reg = mem2reg; - flag_noblackbox = noblackbox; - flag_lib = lib; - flag_nowb = nowb; - flag_noopt = noopt; - flag_icells = icells; - flag_pwires = pwires; - flag_autowire = autowire; - - log_assert(current_ast->type == AST_DESIGN); - for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) - { - if ((*it)->type == AST_MODULE || (*it)->type == AST_INTERFACE) - { - for (auto n : design->verilog_globals) - (*it)->children.push_back(n->clone()); - - for (auto n : design->verilog_packages){ - for (auto o : n->children) { - AstNode *cloned_node = o->clone(); - cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); - (*it)->children.push_back(cloned_node); - } - } - - if (flag_icells && (*it)->str.substr(0, 2) == "\\$") - (*it)->str = (*it)->str.substr(1); - - if (defer) - (*it)->str = "$abstract" + (*it)->str; - - if (design->has((*it)->str)) { - RTLIL::Module *existing_mod = design->module((*it)->str); - if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { - log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", (*it)->str.c_str()); - } else if (nooverwrite) { - log("Ignoring re-definition of module `%s' at %s:%d.\n", - (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); - continue; - } else { - log("Replacing existing%s module `%s' at %s:%d.\n", - existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", - (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); - design->remove(existing_mod); - } - } - - design->add(process_module(*it, defer)); - } - else if ((*it)->type == AST_PACKAGE) - design->verilog_packages.push_back((*it)->clone()); - else - design->verilog_globals.push_back((*it)->clone()); - } -} - -// AstModule destructor -AstModule::~AstModule() -{ - if (ast != NULL) - delete ast; -} - - -// An interface port with modport is specified like this: -// . -// This function splits the interface_name from the modport_name, and fails if it is not a valid combination -std::pair AST::split_modport_from_type(std::string name_type) -{ - std::string interface_type = ""; - std::string interface_modport = ""; - size_t ndots = std::count(name_type.begin(), name_type.end(), '.'); - // Separate the interface instance name from any modports: - if (ndots == 0) { // Does not have modport - interface_type = name_type; - } - else { - std::stringstream name_type_stream(name_type); - std::string segment; - std::vector seglist; - while(std::getline(name_type_stream, segment, '.')) { - seglist.push_back(segment); - } - if (ndots == 1) { // Has modport - interface_type = seglist[0]; - interface_modport = seglist[1]; - } - else { // Erroneous port type - log_error("More than two '.' in signal port type (%s)\n", name_type.c_str()); - } - } - return std::pair(interface_type, interface_modport); - -} - -AstNode * AST::find_modport(AstNode *intf, std::string name) -{ - for (auto &ch : intf->children) - if (ch->type == AST_MODPORT) - if (ch->str == name) // Modport found - return ch; - return NULL; -} - -// Iterate over all wires in an interface and add them as wires in the AST module: -void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) -{ - for (auto &wire_it : intfmodule->wires_){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); - std::string origname = log_id(wire_it.first); - std::string newname = intfname + "." + origname; - wire->str = newname; - if (modport != NULL) { - bool found_in_modport = false; - // Search for the current wire in the wire list for the current modport - for (auto &ch : modport->children) { - if (ch->type == AST_MODPORTMEMBER) { - std::string compare_name = "\\" + origname; - if (ch->str == compare_name) { // Found signal. The modport decides whether it is input or output - found_in_modport = true; - wire->is_input = ch->is_input; - wire->is_output = ch->is_output; - break; - } - } - } - if (found_in_modport) { - module_ast->children.push_back(wire); - } - else { // If not found in modport, do not create port - delete wire; - } - } - else { // If no modport, set inout - wire->is_input = true; - wire->is_output = true; - module_ast->children.push_back(wire); - } - } -} - -// When an interface instance is found in a module, the whole RTLIL for the module will be rederived again -// from AST. The interface members are copied into the AST module with the prefix of the interface. -void AstModule::reprocess_module(RTLIL::Design *design, dict local_interfaces) -{ - bool is_top = false; - AstNode *new_ast = ast->clone(); - for (auto &intf : local_interfaces) { - std::string intfname = intf.first.str(); - RTLIL::Module *intfmodule = intf.second; - for (auto &wire_it : intfmodule->wires_){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); - std::string newname = log_id(wire_it.first); - newname = intfname + "." + newname; - wire->str = newname; - new_ast->children.push_back(wire); - } - } - - AstNode *ast_before_replacing_interface_ports = new_ast->clone(); - - // Explode all interface ports. Note this will only have an effect on 'top - // level' modules. Other sub-modules will have their interface ports - // exploded via the derive(..) function - for (size_t i =0; ichildren.size(); i++) - { - AstNode *ch2 = new_ast->children[i]; - if (ch2->type == AST_INTERFACEPORT) { // Is an interface port - std::string name_port = ch2->str; // Name of the interface port - if (ch2->children.size() > 0) { - for(size_t j=0; jchildren.size();j++) { - AstNode *ch = ch2->children[j]; - if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface - std::pair res = split_modport_from_type(ch->str); - std::string interface_type = res.first; - std::string interface_modport = res.second; // Is "", if no modport - if (design->modules_.count(interface_type) > 0) { - // Add a cell to the module corresponding to the interface port such that - // it can further propagated down if needed: - AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE); - celltype_for_intf->str = interface_type; - AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf); - cell_for_intf->str = name_port + "_inst_from_top_dummy"; - new_ast->children.push_back(cell_for_intf); - - // Get all members of this non-overridden dummy interface instance: - RTLIL::Module *intfmodule = design->modules_[interface_type]; // All interfaces should at this point in time (assuming - // reprocess_module is called from the hierarchy pass) be - // present in design->modules_ - AstModule *ast_module_of_interface = (AstModule*)intfmodule; - std::string interface_modport_compare_str = "\\" + interface_modport; - AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport - // Iterate over all wires in the interface and add them to the module: - explode_interface_port(new_ast, intfmodule, name_port, modport); - } - break; - } - } - } - } - } - - // The old module will be deleted. Rename and mark for deletion: - std::string original_name = this->name.str(); - std::string changed_name = original_name + "_before_replacing_local_interfaces"; - design->rename(this, changed_name); - this->set_bool_attribute("\\to_delete"); - - // Check if the module was the top module. If it was, we need to remove the top attribute and put it on the - // new module. - if (this->get_bool_attribute("\\initial_top")) { - this->attributes.erase("\\initial_top"); - is_top = true; - } - - // Generate RTLIL from AST for the new module and add to the design: - AstModule *newmod = process_module(new_ast, false, ast_before_replacing_interface_ports); - delete(new_ast); - design->add(newmod); - RTLIL::Module* mod = design->module(original_name); - if (is_top) - mod->set_bool_attribute("\\top"); - - // Set the attribute "interfaces_replaced_in_module" so that it does not happen again. - mod->set_bool_attribute("\\interfaces_replaced_in_module"); -} - -// create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces -// This method is used to explode the interface when the interface is a port of the module (not instantiated inside) -RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict parameters, dict interfaces, dict modports, bool mayfail) -{ - AstNode *new_ast = NULL; - std::string modname = derive_common(design, parameters, &new_ast, mayfail); - - // Since interfaces themselves may be instantiated with different parameters, - // "modname" must also take those into account, so that unique modules - // are derived for any variant of interface connections: - std::string interf_info = ""; - - bool has_interfaces = false; - for(auto &intf : interfaces) { - interf_info += log_id(intf.second->name); - has_interfaces = true; - } - - if (has_interfaces) - modname += "$interfaces$" + interf_info; - - - if (!design->has(modname)) { - new_ast->str = modname; - - // Iterate over all interfaces which are ports in this module: - for(auto &intf : interfaces) { - RTLIL::Module * intfmodule = intf.second; - std::string intfname = intf.first.str(); - // Check if a modport applies for the interface port: - AstNode *modport = NULL; - if (modports.count(intfname) > 0) { - std::string interface_modport = modports.at(intfname).str(); - AstModule *ast_module_of_interface = (AstModule*)intfmodule; - AstNode *ast_node_of_interface = ast_module_of_interface->ast; - modport = find_modport(ast_node_of_interface, interface_modport); - } - // Iterate over all wires in the interface and add them to the module: - explode_interface_port(new_ast, intfmodule, intfname, modport); - } - - design->add(process_module(new_ast, false)); - design->module(modname)->check(); - - RTLIL::Module* mod = design->module(modname); - - // Now that the interfaces have been exploded, we can delete the dummy port related to every interface. - for(auto &intf : interfaces) { - if(mod->wires_.count(intf.first)) { - mod->wires_.erase(intf.first); - mod->fixup_ports(); - // We copy the cell of the interface to the sub-module such that it can further be found if it is propagated - // down to sub-sub-modules etc. - RTLIL::Cell * new_subcell = mod->addCell(intf.first, intf.second->name); - new_subcell->set_bool_attribute("\\is_interface"); - } - else { - log_error("No port with matching name found (%s) in %s. Stopping\n", log_id(intf.first), modname.c_str()); - } - } - - // If any interfaces were replaced, set the attribute 'interfaces_replaced_in_module': - if (interfaces.size() > 0) { - mod->set_bool_attribute("\\interfaces_replaced_in_module"); - } - - } else { - log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); - } - - delete new_ast; - return modname; -} - -// create a new parametric module (when needed) and return the name of the generated module - without support for interfaces -RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict parameters, bool mayfail) -{ - AstNode *new_ast = NULL; - std::string modname = derive_common(design, parameters, &new_ast, mayfail); - - if (!design->has(modname)) { - new_ast->str = modname; - design->add(process_module(new_ast, false)); - design->module(modname)->check(); - } else { - log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); - } - - delete new_ast; - return modname; -} - -// create a new parametric module (when needed) and return the name of the generated module -std::string AstModule::derive_common(RTLIL::Design *design, dict parameters, AstNode **new_ast_out, bool) -{ - std::string stripped_name = name.str(); - - if (stripped_name.substr(0, 9) == "$abstract") - stripped_name = stripped_name.substr(9); - - log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); - - current_ast = NULL; - flag_dump_ast1 = false; - flag_dump_ast2 = false; - flag_dump_vlog1 = false; - flag_dump_vlog2 = false; - flag_nolatches = nolatches; - flag_nomeminit = nomeminit; - flag_nomem2reg = nomem2reg; - flag_mem2reg = mem2reg; - flag_noblackbox = noblackbox; - flag_lib = lib; - flag_nowb = nowb; - flag_noopt = noopt; - flag_icells = icells; - flag_pwires = pwires; - flag_autowire = autowire; - use_internal_line_num(); - - std::string para_info; - AstNode *new_ast = ast->clone(); - - int para_counter = 0; - int orig_parameters_n = parameters.size(); - for (auto it = new_ast->children.begin(); it != new_ast->children.end(); it++) { - AstNode *child = *it; - if (child->type != AST_PARAMETER) - continue; - para_counter++; - std::string para_id = child->str; - if (parameters.count(para_id) > 0) { - log("Parameter %s = %s\n", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[child->str]))); - rewrite_parameter: - para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); - delete child->children.at(0); - if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0) - child->children[0] = AstNode::mkconst_str(parameters[para_id].decode_string()); - else - child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0); - parameters.erase(para_id); - continue; - } - para_id = stringf("$%d", para_counter); - if (parameters.count(para_id) > 0) { - log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); - goto rewrite_parameter; - } - } - - for (auto param : parameters) { - AstNode *defparam = new AstNode(AST_DEFPARAM, new AstNode(AST_IDENTIFIER)); - defparam->children[0]->str = param.first.str(); - if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0) - defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string())); - else - defparam->children.push_back(AstNode::mkconst_bits(param.second.bits, (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0)); - new_ast->children.push_back(defparam); - } - - std::string modname; - - if (orig_parameters_n == 0) - modname = stripped_name; - else if (para_info.size() > 60) - modname = "$paramod$" + sha1(para_info) + stripped_name; - else - modname = "$paramod" + stripped_name + para_info; - - - (*new_ast_out) = new_ast; - return modname; -} - -RTLIL::Module *AstModule::clone() const -{ - AstModule *new_mod = new AstModule; - new_mod->name = name; - cloneInto(new_mod); - - new_mod->ast = ast->clone(); - new_mod->nolatches = nolatches; - new_mod->nomeminit = nomeminit; - new_mod->nomem2reg = nomem2reg; - new_mod->mem2reg = mem2reg; - new_mod->lib = lib; - new_mod->noopt = noopt; - new_mod->icells = icells; - new_mod->pwires = pwires; - new_mod->autowire = autowire; - - return new_mod; -} - -// internal dummy line number callbacks -namespace { - int internal_line_num; - void internal_set_line_num(int n) { - internal_line_num = n; - } - int internal_get_line_num() { - return internal_line_num; - } -} - -// use internal dummy line number callbacks -void AST::use_internal_line_num() -{ - set_line_num = &internal_set_line_num; - get_line_num = &internal_get_line_num; -} - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/ast/ast.h b/yosys/frontends/ast/ast.h deleted file mode 100644 index 54b2fb319..000000000 --- a/yosys/frontends/ast/ast.h +++ /dev/null @@ -1,341 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * This is the AST frontend library. - * - * The AST frontend library is not a frontend on it's own but provides a - * generic abstract syntax tree (AST) abstraction for HDL code and can be - * used by HDL frontends. See "ast.h" for an overview of the API and the - * Verilog frontend for an usage example. - * - */ - -#ifndef AST_H -#define AST_H - -#include "kernel/rtlil.h" -#include -#include - -YOSYS_NAMESPACE_BEGIN - -namespace AST -{ - // all node types, type2str() must be extended - // whenever a new node type is added here - enum AstNodeType - { - AST_NONE, - AST_DESIGN, - AST_MODULE, - AST_TASK, - AST_FUNCTION, - AST_DPI_FUNCTION, - - AST_WIRE, - AST_MEMORY, - AST_AUTOWIRE, - AST_PARAMETER, - AST_LOCALPARAM, - AST_DEFPARAM, - AST_PARASET, - AST_ARGUMENT, - AST_RANGE, - AST_MULTIRANGE, - AST_CONSTANT, - AST_REALVALUE, - AST_CELLTYPE, - AST_IDENTIFIER, - AST_PREFIX, - AST_ASSERT, - AST_ASSUME, - AST_LIVE, - AST_FAIR, - AST_COVER, - - AST_FCALL, - AST_TO_BITS, - AST_TO_SIGNED, - AST_TO_UNSIGNED, - AST_CONCAT, - AST_REPLICATE, - AST_BIT_NOT, - AST_BIT_AND, - AST_BIT_OR, - AST_BIT_XOR, - AST_BIT_XNOR, - AST_REDUCE_AND, - AST_REDUCE_OR, - AST_REDUCE_XOR, - AST_REDUCE_XNOR, - AST_REDUCE_BOOL, - AST_SHIFT_LEFT, - AST_SHIFT_RIGHT, - AST_SHIFT_SLEFT, - AST_SHIFT_SRIGHT, - AST_LT, - AST_LE, - AST_EQ, - AST_NE, - AST_EQX, - AST_NEX, - AST_GE, - AST_GT, - AST_ADD, - AST_SUB, - AST_MUL, - AST_DIV, - AST_MOD, - AST_POW, - AST_POS, - AST_NEG, - AST_LOGIC_AND, - AST_LOGIC_OR, - AST_LOGIC_NOT, - AST_TERNARY, - AST_MEMRD, - AST_MEMWR, - AST_MEMINIT, - - AST_TCALL, - AST_ASSIGN, - AST_CELL, - AST_PRIMITIVE, - AST_CELLARRAY, - AST_ALWAYS, - AST_INITIAL, - AST_BLOCK, - AST_ASSIGN_EQ, - AST_ASSIGN_LE, - AST_CASE, - AST_COND, - AST_CONDX, - AST_CONDZ, - AST_DEFAULT, - AST_FOR, - AST_WHILE, - AST_REPEAT, - - AST_GENVAR, - AST_GENFOR, - AST_GENIF, - AST_GENCASE, - AST_GENBLOCK, - AST_TECALL, - - AST_POSEDGE, - AST_NEGEDGE, - AST_EDGE, - - AST_INTERFACE, - AST_INTERFACEPORT, - AST_INTERFACEPORTTYPE, - AST_MODPORT, - AST_MODPORTMEMBER, - AST_PACKAGE - }; - - // convert an node type to a string (e.g. for debug output) - std::string type2str(AstNodeType type); - - // The AST is built using instances of this struct - struct AstNode - { - // for dict<> and pool<> - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - - // this nodes type - AstNodeType type; - - // the list of child nodes for this node - std::vector children; - - // the list of attributes assigned to this node - std::map attributes; - bool get_bool_attribute(RTLIL::IdString id); - - // node content - most of it is unused in most node types - std::string str; - std::vector bits; - bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized; - int port_id, range_left, range_right; - uint32_t integer; - double realvalue; - - // if this is a multirange memory then this vector contains offset and length of each dimension - std::vector multirange_dimensions; - - // this is set by simplify and used during RTLIL generation - AstNode *id2ast; - - // this is used by simplify to detect if basic analysis has been performed already on the node - bool basic_prep; - - // this is the original sourcecode location that resulted in this AST node - // it is automatically set by the constructor using AST::current_filename and - // the AST::get_line_num() callback function. - std::string filename; - int linenum; - - // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL, AstNode *child3 = NULL); - AstNode *clone() const; - void cloneInto(AstNode *other) const; - void delete_children(); - ~AstNode(); - - enum mem2reg_flags - { - /* status flags */ - MEM2REG_FL_ALL = 0x00000001, - MEM2REG_FL_ASYNC = 0x00000002, - MEM2REG_FL_INIT = 0x00000004, - - /* candidate flags */ - MEM2REG_FL_FORCED = 0x00000100, - MEM2REG_FL_SET_INIT = 0x00000200, - MEM2REG_FL_SET_ELSE = 0x00000400, - MEM2REG_FL_SET_ASYNC = 0x00000800, - MEM2REG_FL_EQ2 = 0x00001000, - MEM2REG_FL_CMPLX_LHS = 0x00002000, - MEM2REG_FL_CONST_LHS = 0x00004000, - MEM2REG_FL_VAR_LHS = 0x00008000, - - /* proc flags */ - MEM2REG_FL_EQ1 = 0x01000000, - }; - - // simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. - // it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL() - bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param); - AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); - void expand_genblock(std::string index_var, std::string prefix, std::map &name_map); - void replace_ids(const std::string &prefix, const std::map &rules); - void mem2reg_as_needed_pass1(dict> &mem2reg_places, - dict &mem2reg_flags, dict &proc_flags, uint32_t &status_flags); - bool mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block); - bool mem2reg_check(pool &mem2reg_set); - void mem2reg_remove(pool &mem2reg_set, vector &delnodes); - void meminfo(int &mem_width, int &mem_size, int &addr_bits); - - // additional functionality for evaluating constant functions - struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; }; - bool has_const_only_constructs(bool &recommend_const_eval); - void replace_variables(std::map &variables, AstNode *fcall); - AstNode *eval_const_function(AstNode *fcall); - bool is_simple_const_expr(); - - // create a human-readable text representation of the AST (for debugging) - void dumpAst(FILE *f, std::string indent) const; - void dumpVlog(FILE *f, std::string indent) const; - - // used by genRTLIL() for detecting expression width and sign - void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL); - void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL); - - // create RTLIL code for this AST node - // for expressions the resulting signal vector is returned - // all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module - RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false); - RTLIL::SigSpec genWidthRTLIL(int width, const dict *new_subst_ptr = NULL); - - // compare AST nodes - bool operator==(const AstNode &other) const; - bool operator!=(const AstNode &other) const; - bool contains(const AstNode *other) const; - - // helper functions for creating AST nodes for constants - static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32); - static AstNode *mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized); - static AstNode *mkconst_bits(const std::vector &v, bool is_signed); - static AstNode *mkconst_str(const std::vector &v); - static AstNode *mkconst_str(const std::string &str); - - // helper function for creating sign-extended const objects - RTLIL::Const bitsAsConst(int width, bool is_signed); - RTLIL::Const bitsAsConst(int width = -1); - RTLIL::Const bitsAsUnsizedConst(int width); - RTLIL::Const asAttrConst(); - RTLIL::Const asParaConst(); - uint64_t asInt(bool is_signed); - bool bits_only_01() const; - bool asBool() const; - - // helper functions for real valued const eval - int isConst() const; // return '1' for AST_CONSTANT and '2' for AST_REALVALUE - double asReal(bool is_signed); - RTLIL::Const realAsConst(int width); - }; - - // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code - void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit, - bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire); - - // parametric modules are supported directly by the AST library - // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions - struct AstModule : RTLIL::Module { - AstNode *ast; - bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire; - ~AstModule() YS_OVERRIDE; - RTLIL::IdString derive(RTLIL::Design *design, dict parameters, bool mayfail) YS_OVERRIDE; - RTLIL::IdString derive(RTLIL::Design *design, dict parameters, dict interfaces, dict modports, bool mayfail) YS_OVERRIDE; - std::string derive_common(RTLIL::Design *design, dict parameters, AstNode **new_ast_out, bool mayfail); - void reprocess_module(RTLIL::Design *design, dict local_interfaces) YS_OVERRIDE; - RTLIL::Module *clone() const YS_OVERRIDE; - }; - - // this must be set by the language frontend before parsing the sources - // the AstNode constructor then uses current_filename and get_line_num() - // to initialize the filename and linenum properties of new nodes - extern std::string current_filename; - extern void (*set_line_num)(int); - extern int (*get_line_num)(); - - // set set_line_num and get_line_num to internal dummy functions (done by simplify() and AstModule::derive - // to control the filename and linenum properties of new nodes not generated by a frontend parser) - void use_internal_line_num(); - - // call a DPI function - AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector &args); - - // Helper functions related to handling SystemVerilog interfaces - std::pair split_modport_from_type(std::string name_type); - AstNode * find_modport(AstNode *intf, std::string name); - void explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport); -} - -namespace AST_INTERNAL -{ - // internal state variables - extern bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit; - extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_pwires, flag_autowire; - extern AST::AstNode *current_ast, *current_ast_mod; - extern std::map current_scope; - extern const dict *genRTLIL_subst_ptr; - extern RTLIL::SigSpec ignoreThisSignalsInInitial; - extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child; - extern AST::AstModule *current_module; - extern bool current_always_clocked; - struct ProcessGenerator; -} - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/ast/dpicall.cc b/yosys/frontends/ast/dpicall.cc deleted file mode 100644 index e241142d3..000000000 --- a/yosys/frontends/ast/dpicall.cc +++ /dev/null @@ -1,148 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "ast.h" - -#ifdef YOSYS_ENABLE_PLUGINS - -#include -#include - -YOSYS_NAMESPACE_BEGIN - -typedef void (*ffi_fptr) (); - -static ffi_fptr resolve_fn (std::string symbol_name) -{ - if (symbol_name.find(':') != std::string::npos) - { - int pos = symbol_name.find(':'); - std::string plugin_name = symbol_name.substr(0, pos); - std::string real_symbol_name = symbol_name.substr(pos+1); - - while (loaded_plugin_aliases.count(plugin_name)) - plugin_name = loaded_plugin_aliases.at(plugin_name); - - if (loaded_plugins.count(plugin_name) == 0) - log_error("unable to resolve '%s': can't find plugin `%s'\n", symbol_name.c_str(), plugin_name.c_str()); - - void *symbol = dlsym(loaded_plugins.at(plugin_name), real_symbol_name.c_str()); - - if (symbol == nullptr) - log_error("unable to resolve '%s': can't find symbol `%s' in plugin `%s'\n", - symbol_name.c_str(), real_symbol_name.c_str(), plugin_name.c_str()); - - return (ffi_fptr) symbol; - } - - for (auto &it : loaded_plugins) { - void *symbol = dlsym(it.second, symbol_name.c_str()); - if (symbol != nullptr) - return (ffi_fptr) symbol; - } - - void *symbol = dlsym(RTLD_DEFAULT, symbol_name.c_str()); - if (symbol != nullptr) - return (ffi_fptr) symbol; - - log_error("unable to resolve '%s'.\n", symbol_name.c_str()); -} - -AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector &args) -{ - AST::AstNode *newNode = nullptr; - union { double f64; float f32; int32_t i32; } value_store [args.size() + 1]; - ffi_type *types [args.size() + 1]; - void *values [args.size() + 1]; - ffi_cif cif; - int status; - - log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str()); - - log_assert(GetSize(args) == GetSize(argtypes)); - for (int i = 0; i < GetSize(args); i++) { - if (argtypes[i] == "real") { - log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed)); - value_store[i].f64 = args[i]->asReal(args[i]->is_signed); - values[i] = &value_store[i].f64; - types[i] = &ffi_type_double; - } else if (argtypes[i] == "shortreal") { - log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed)); - value_store[i].f32 = args[i]->asReal(args[i]->is_signed); - values[i] = &value_store[i].f32; - types[i] = &ffi_type_double; - } else if (argtypes[i] == "integer") { - log(" arg %d (%s): %lld\n", i, argtypes[i].c_str(), (long long)args[i]->asInt(args[i]->is_signed)); - value_store[i].i32 = args[i]->asInt(args[i]->is_signed); - values[i] = &value_store[i].i32; - types[i] = &ffi_type_sint32; - } else { - log_error("invalid argtype '%s' for argument %d.\n", argtypes[i].c_str(), i); - } - } - - if (rtype == "integer") { - types[args.size()] = &ffi_type_slong; - values[args.size()] = &value_store[args.size()].i32; - } else if (rtype == "shortreal") { - types[args.size()] = &ffi_type_float; - values[args.size()] = &value_store[args.size()].f32; - } else if (rtype == "real") { - types[args.size()] = &ffi_type_double; - values[args.size()] = &value_store[args.size()].f64; - } else { - log_error("invalid rtype '%s'.\n", rtype.c_str()); - } - - if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, args.size(), types[args.size()], types)) != FFI_OK) - log_error("ffi_prep_cif failed: status %d.\n", status); - - ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values); - - if (rtype == "real") { - newNode = new AstNode(AST_REALVALUE); - newNode->realvalue = value_store[args.size()].f64; - log(" return realvalue: %g\n", newNode->asReal(true)); - } else if (rtype == "shortreal") { - newNode = new AstNode(AST_REALVALUE); - newNode->realvalue = value_store[args.size()].f32; - log(" return realvalue: %g\n", newNode->asReal(true)); - } else { - newNode = AstNode::mkconst_int(value_store[args.size()].i32, false); - log(" return integer: %lld\n", (long long)newNode->asInt(true)); - } - - return newNode; -} - -YOSYS_NAMESPACE_END - -#else /* YOSYS_ENABLE_PLUGINS */ - -YOSYS_NAMESPACE_BEGIN - -AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector&, const std::vector&) -{ - log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str()); -} - -YOSYS_NAMESPACE_END - -#endif /* YOSYS_ENABLE_PLUGINS */ - diff --git a/yosys/frontends/ast/genrtlil.cc b/yosys/frontends/ast/genrtlil.cc deleted file mode 100644 index 571ddd988..000000000 --- a/yosys/frontends/ast/genrtlil.cc +++ /dev/null @@ -1,1703 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * This is the AST frontend library. - * - * The AST frontend library is not a frontend on it's own but provides a - * generic abstract syntax tree (AST) abstraction for HDL code and can be - * used by HDL frontends. See "ast.h" for an overview of the API and the - * Verilog frontend for an usage example. - * - */ - -#include "kernel/log.h" -#include "kernel/utils.h" -#include "libs/sha1/sha1.h" -#include "ast.h" - -#include -#include -#include - -YOSYS_NAMESPACE_BEGIN - -using namespace AST; -using namespace AST_INTERNAL; - -// helper function for creating RTLIL code for unary operations -static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) -{ - std::stringstream sstr; - sstr << type << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++); - - RTLIL::Cell *cell = current_module->addCell(sstr.str(), type); - cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); - - RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width); - wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); - - if (gen_attributes) - for (auto &attr : that->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - cell->attributes[attr.first] = attr.second->asAttrConst(); - } - - cell->parameters["\\A_SIGNED"] = RTLIL::Const(that->children[0]->is_signed); - cell->parameters["\\A_WIDTH"] = RTLIL::Const(arg.size()); - cell->setPort("\\A", arg); - - cell->parameters["\\Y_WIDTH"] = result_width; - cell->setPort("\\Y", wire); - return wire; -} - -// helper function for extending bit width (preferred over SigSpec::extend() because of correct undef propagation in ConstEval) -static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_signed) -{ - if (width <= sig.size()) { - sig.extend_u0(width, is_signed); - return; - } - - std::stringstream sstr; - sstr << "$extend" << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++); - - RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$pos"); - cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); - - RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", width); - wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); - - if (that != NULL) - for (auto &attr : that->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - cell->attributes[attr.first] = attr.second->asAttrConst(); - } - - cell->parameters["\\A_SIGNED"] = RTLIL::Const(is_signed); - cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.size()); - cell->setPort("\\A", sig); - - cell->parameters["\\Y_WIDTH"] = width; - cell->setPort("\\Y", wire); - sig = wire; -} - -// helper function for creating RTLIL code for binary operations -static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) -{ - std::stringstream sstr; - sstr << type << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++); - - RTLIL::Cell *cell = current_module->addCell(sstr.str(), type); - cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); - - RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width); - wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); - - for (auto &attr : that->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - cell->attributes[attr.first] = attr.second->asAttrConst(); - } - - cell->parameters["\\A_SIGNED"] = RTLIL::Const(that->children[0]->is_signed); - cell->parameters["\\B_SIGNED"] = RTLIL::Const(that->children[1]->is_signed); - - cell->parameters["\\A_WIDTH"] = RTLIL::Const(left.size()); - cell->parameters["\\B_WIDTH"] = RTLIL::Const(right.size()); - - cell->setPort("\\A", left); - cell->setPort("\\B", right); - - cell->parameters["\\Y_WIDTH"] = result_width; - cell->setPort("\\Y", wire); - return wire; -} - -// helper function for creating RTLIL code for multiplexers -static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) -{ - log_assert(cond.size() == 1); - - std::stringstream sstr; - sstr << "$ternary$" << that->filename << ":" << that->linenum << "$" << (autoidx++); - - RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$mux"); - cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); - - RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", left.size()); - wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); - - for (auto &attr : that->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - cell->attributes[attr.first] = attr.second->asAttrConst(); - } - - cell->parameters["\\WIDTH"] = RTLIL::Const(left.size()); - - cell->setPort("\\A", right); - cell->setPort("\\B", left); - cell->setPort("\\S", cond); - cell->setPort("\\Y", wire); - - return wire; -} - -// helper class for converting AST always nodes to RTLIL processes -struct AST_INTERNAL::ProcessGenerator -{ - // input and output structures - AstNode *always; - RTLIL::SigSpec initSyncSignals; - RTLIL::Process *proc; - RTLIL::SigSpec outputSignals; - - // This always points to the RTLIL::CaseRule being filled at the moment - RTLIL::CaseRule *current_case; - - // This map contains the replacement pattern to be used in the right hand side - // of an assignment. E.g. in the code "foo = bar; foo = func(foo);" the foo in the right - // hand side of the 2nd assignment needs to be replace with the temporary signal holding - // the value assigned in the first assignment. So when the first assignment is processed - // the according information is appended to subst_rvalue_from and subst_rvalue_to. - stackmap subst_rvalue_map; - - // This map contains the replacement pattern to be used in the left hand side - // of an assignment. E.g. in the code "always @(posedge clk) foo <= bar" the signal bar - // should not be connected to the signal foo. Instead it must be connected to the temporary - // signal that is used as input for the register that drives the signal foo. - stackmap subst_lvalue_map; - - // The code here generates a number of temporary signal for each output register. This - // map helps generating nice numbered names for all this temporary signals. - std::map new_temp_count; - - // Buffer for generating the init action - RTLIL::SigSpec init_lvalue, init_rvalue; - - ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg) - { - // generate process and simple root case - proc = new RTLIL::Process; - proc->attributes["\\src"] = stringf("%s:%d", always->filename.c_str(), always->linenum); - proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, autoidx++); - for (auto &attr : always->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(always->filename, always->linenum, "Attribute `%s' with non-constant value!\n", - attr.first.c_str()); - proc->attributes[attr.first] = attr.second->asAttrConst(); - } - current_module->processes[proc->name] = proc; - current_case = &proc->root_case; - - // create initial temporary signal for all output registers - RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to; - collect_lvalues(subst_lvalue_from, always, true, true); - subst_lvalue_to = new_temp_signal(subst_lvalue_from); - subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to); - - bool found_global_syncs = false; - bool found_anyedge_syncs = false; - for (auto child : always->children) - { - if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && - child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute("\\gclk")) { - found_global_syncs = true; - } - if (child->type == AST_EDGE) { - if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->str == "\\$global_clock") - found_global_syncs = true; - else - found_anyedge_syncs = true; - } - } - - if (found_anyedge_syncs) { - if (found_global_syncs) - log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n"); - log("Note: Assuming pure combinatorial block at %s:%d in\n", always->filename.c_str(), always->linenum); - log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n"); - log("use of @* instead of @(...) for better match of synthesis and simulation.\n"); - } - - // create syncs for the process - bool found_clocked_sync = false; - for (auto child : always->children) - if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) { - if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast && - child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute("\\gclk")) - continue; - found_clocked_sync = true; - if (found_global_syncs || found_anyedge_syncs) - log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n"); - RTLIL::SyncRule *syncrule = new RTLIL::SyncRule; - syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn; - syncrule->signal = child->children[0]->genRTLIL(); - if (GetSize(syncrule->signal) != 1) - log_file_error(always->filename, always->linenum, "Found posedge/negedge event on a signal that is not 1 bit wide!\n"); - addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true); - proc->syncs.push_back(syncrule); - } - if (proc->syncs.empty()) { - RTLIL::SyncRule *syncrule = new RTLIL::SyncRule; - syncrule->type = found_global_syncs ? RTLIL::STg : RTLIL::STa; - syncrule->signal = RTLIL::SigSpec(); - addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true); - proc->syncs.push_back(syncrule); - } - - // create initial assignments for the temporary signals - if ((flag_nolatches || always->get_bool_attribute("\\nolatches") || current_module->get_bool_attribute("\\nolatches")) && !found_clocked_sync) { - subst_rvalue_map = subst_lvalue_from.to_sigbit_dict(RTLIL::SigSpec(RTLIL::State::Sx, GetSize(subst_lvalue_from))); - } else { - addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from); - } - - // process the AST - for (auto child : always->children) - if (child->type == AST_BLOCK) - processAst(child); - - if (initSyncSignals.size() > 0) - { - RTLIL::SyncRule *sync = new RTLIL::SyncRule; - sync->type = RTLIL::SyncType::STi; - proc->syncs.push_back(sync); - - log_assert(init_lvalue.size() == init_rvalue.size()); - - int offset = 0; - for (auto &init_lvalue_c : init_lvalue.chunks()) { - RTLIL::SigSpec lhs = init_lvalue_c; - RTLIL::SigSpec rhs = init_rvalue.extract(offset, init_lvalue_c.width); - remove_unwanted_lvalue_bits(lhs, rhs); - sync->actions.push_back(RTLIL::SigSig(lhs, rhs)); - offset += lhs.size(); - } - } - - outputSignals = RTLIL::SigSpec(subst_lvalue_from); - } - - void remove_unwanted_lvalue_bits(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) - { - RTLIL::SigSpec new_lhs, new_rhs; - - log_assert(GetSize(lhs) == GetSize(rhs)); - for (int i = 0; i < GetSize(lhs); i++) { - if (lhs[i].wire == nullptr) - continue; - new_lhs.append(lhs[i]); - new_rhs.append(rhs[i]); - } - - lhs = new_lhs; - rhs = new_rhs; - } - - // create new temporary signals - RTLIL::SigSpec new_temp_signal(RTLIL::SigSpec sig) - { - std::vector chunks = sig.chunks(); - - for (int i = 0; i < GetSize(chunks); i++) - { - RTLIL::SigChunk &chunk = chunks[i]; - if (chunk.wire == NULL) - continue; - - std::string wire_name; - do { - wire_name = stringf("$%d%s[%d:%d]", new_temp_count[chunk.wire]++, - chunk.wire->name.c_str(), chunk.width+chunk.offset-1, chunk.offset);; - if (chunk.wire->name.str().find('$') != std::string::npos) - wire_name += stringf("$%d", autoidx++); - } while (current_module->wires_.count(wire_name) > 0); - - RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width); - wire->attributes["\\src"] = stringf("%s:%d", always->filename.c_str(), always->linenum); - - chunk.wire = wire; - chunk.offset = 0; - } - - return chunks; - } - - // recursively traverse the AST an collect all assigned signals - void collect_lvalues(RTLIL::SigSpec ®, AstNode *ast, bool type_eq, bool type_le, bool run_sort_and_unify = true) - { - switch (ast->type) - { - case AST_CASE: - for (auto child : ast->children) - if (child != ast->children[0]) { - log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); - collect_lvalues(reg, child, type_eq, type_le, false); - } - break; - - case AST_COND: - case AST_CONDX: - case AST_CONDZ: - case AST_ALWAYS: - case AST_INITIAL: - for (auto child : ast->children) - if (child->type == AST_BLOCK) - collect_lvalues(reg, child, type_eq, type_le, false); - break; - - case AST_BLOCK: - for (auto child : ast->children) { - if (child->type == AST_ASSIGN_EQ && type_eq) - reg.append(child->children[0]->genRTLIL()); - if (child->type == AST_ASSIGN_LE && type_le) - reg.append(child->children[0]->genRTLIL()); - if (child->type == AST_CASE || child->type == AST_BLOCK) - collect_lvalues(reg, child, type_eq, type_le, false); - } - break; - - default: - log_abort(); - } - - if (run_sort_and_unify) { - std::set sorted_reg; - for (auto bit : reg) - if (bit.wire) - sorted_reg.insert(bit); - reg = RTLIL::SigSpec(sorted_reg); - } - } - - // remove all assignments to the given signal pattern in a case and all its children. - // e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this - // function is called to clean up the first two assignments as they are overwritten by - // the third assignment. - void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs) - { - for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) - it->first.remove2(pattern, &it->second); - - for (auto it = cs->switches.begin(); it != cs->switches.end(); it++) - for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++) - removeSignalFromCaseTree(pattern, *it2); - } - - // add an assignment (aka "action") but split it up in chunks. this way huge assignments - // are avoided and the generated $mux cells have a more "natural" size. - void addChunkActions(std::vector &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue, bool inSyncRule = false) - { - if (inSyncRule && initSyncSignals.size() > 0) { - init_lvalue.append(lvalue.extract(initSyncSignals)); - init_rvalue.append(lvalue.extract(initSyncSignals, &rvalue)); - lvalue.remove2(initSyncSignals, &rvalue); - } - log_assert(lvalue.size() == rvalue.size()); - - int offset = 0; - for (auto &lvalue_c : lvalue.chunks()) { - RTLIL::SigSpec lhs = lvalue_c; - RTLIL::SigSpec rhs = rvalue.extract(offset, lvalue_c.width); - if (inSyncRule && lvalue_c.wire && lvalue_c.wire->get_bool_attribute("\\nosync")) - rhs = RTLIL::SigSpec(RTLIL::State::Sx, rhs.size()); - remove_unwanted_lvalue_bits(lhs, rhs); - actions.push_back(RTLIL::SigSig(lhs, rhs)); - offset += lhs.size(); - } - } - - // recursively process the AST and fill the RTLIL::Process - void processAst(AstNode *ast) - { - switch (ast->type) - { - case AST_BLOCK: - for (auto child : ast->children) - processAst(child); - break; - - case AST_ASSIGN_EQ: - case AST_ASSIGN_LE: - { - RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue; - RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap()); - - pool lvalue_sigbits; - for (int i = 0; i < GetSize(lvalue); i++) { - if (lvalue_sigbits.count(lvalue[i]) > 0) { - unmapped_lvalue.remove(i); - lvalue.remove(i); - rvalue.remove(i--); - } else - lvalue_sigbits.insert(lvalue[i]); - } - - lvalue.replace(subst_lvalue_map.stdmap()); - - if (ast->type == AST_ASSIGN_EQ) { - for (int i = 0; i < GetSize(unmapped_lvalue); i++) - subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]); - } - - removeSignalFromCaseTree(lvalue, current_case); - remove_unwanted_lvalue_bits(lvalue, rvalue); - current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue)); - } - break; - - case AST_CASE: - { - RTLIL::SwitchRule *sw = new RTLIL::SwitchRule; - sw->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum); - sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap()); - current_case->switches.push_back(sw); - - for (auto &attr : ast->attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - sw->attributes[attr.first] = attr.second->asAttrConst(); - } - - RTLIL::SigSpec this_case_eq_lvalue; - collect_lvalues(this_case_eq_lvalue, ast, true, false); - - RTLIL::SigSpec this_case_eq_ltemp = new_temp_signal(this_case_eq_lvalue); - - RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue; - this_case_eq_rvalue.replace(subst_rvalue_map.stdmap()); - - RTLIL::CaseRule *default_case = NULL; - RTLIL::CaseRule *last_generated_case = NULL; - for (auto child : ast->children) - { - if (child == ast->children[0]) - continue; - log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); - - subst_lvalue_map.save(); - subst_rvalue_map.save(); - - for (int i = 0; i < GetSize(this_case_eq_lvalue); i++) - subst_lvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]); - - RTLIL::CaseRule *backup_case = current_case; - current_case = new RTLIL::CaseRule; - current_case->attributes["\\src"] = stringf("%s:%d", child->filename.c_str(), child->linenum); - last_generated_case = current_case; - addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); - for (auto node : child->children) { - if (node->type == AST_DEFAULT) - default_case = current_case; - else if (node->type == AST_BLOCK) - processAst(node); - else - current_case->compare.push_back(node->genWidthRTLIL(sw->signal.size(), &subst_rvalue_map.stdmap())); - } - if (default_case != current_case) - sw->cases.push_back(current_case); - else - log_assert(current_case->compare.size() == 0); - current_case = backup_case; - - subst_lvalue_map.restore(); - subst_rvalue_map.restore(); - } - - if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) { - #if 0 - // this is a valid transformation, but as optimization it is premature. - // better: add a default case that assigns 'x' to everything, and let later - // optimizations take care of the rest - last_generated_case->compare.clear(); - #else - default_case = new RTLIL::CaseRule; - addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue))); - sw->cases.push_back(default_case); - #endif - } else { - if (default_case == NULL) { - default_case = new RTLIL::CaseRule; - addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); - } - sw->cases.push_back(default_case); - } - - for (int i = 0; i < GetSize(this_case_eq_lvalue); i++) - subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]); - - this_case_eq_lvalue.replace(subst_lvalue_map.stdmap()); - removeSignalFromCaseTree(this_case_eq_lvalue, current_case); - addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp); - } - break; - - case AST_WIRE: - log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n"); - break; - - case AST_ASSIGN: - log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n"); - break; - - case AST_PARAMETER: - case AST_LOCALPARAM: - log_file_error(ast->filename, ast->linenum, "Found parameter declaration in block without label!\n"); - break; - - case AST_NONE: - case AST_TCALL: - case AST_FOR: - break; - - default: - // ast->dumpAst(NULL, "ast> "); - // current_ast_mod->dumpAst(NULL, "mod> "); - log_abort(); - } - } -}; - -// detect sign and width of an expression -void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real) -{ - std::string type_name; - bool sub_sign_hint = true; - int sub_width_hint = -1; - int this_width = 0; - AstNode *range = NULL; - AstNode *id_ast = NULL; - - bool local_found_real = false; - if (found_real == NULL) - found_real = &local_found_real; - - switch (type) - { - case AST_CONSTANT: - width_hint = max(width_hint, int(bits.size())); - if (!is_signed) - sign_hint = false; - break; - - case AST_REALVALUE: - *found_real = true; - width_hint = max(width_hint, 32); - break; - - case AST_IDENTIFIER: - id_ast = id2ast; - if (id_ast == NULL && current_scope.count(str)) - id_ast = current_scope.at(str); - if (!id_ast) - log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str()); - if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) { - if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) { - this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; - } else - if (id_ast->children[0]->type != AST_CONSTANT) - while (id_ast->simplify(true, false, false, 1, -1, false, true)) { } - if (id_ast->children[0]->type == AST_CONSTANT) - this_width = id_ast->children[0]->bits.size(); - else - log_file_error(filename, linenum, "Failed to detect width for parameter %s!\n", str.c_str()); - if (children.size() != 0) - range = children[0]; - } else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) { - if (!id_ast->range_valid) { - if (id_ast->type == AST_AUTOWIRE) - this_width = 1; - else { - // current_ast_mod->dumpAst(NULL, "mod> "); - // log("---\n"); - // id_ast->dumpAst(NULL, "decl> "); - // dumpAst(NULL, "ref> "); - log_file_error(filename, linenum, "Failed to detect width of signal access `%s'!\n", str.c_str()); - } - } else { - this_width = id_ast->range_left - id_ast->range_right + 1; - if (children.size() != 0) - range = children[0]; - } - } else if (id_ast->type == AST_GENVAR) { - this_width = 32; - } else if (id_ast->type == AST_MEMORY) { - if (!id_ast->children[0]->range_valid) - log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); - this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; - if (children.size() > 1) - range = children[1]; - } else - log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); - if (range) { - if (range->children.size() == 1) - this_width = 1; - else if (!range->range_valid) { - AstNode *left_at_zero_ast = children[0]->children[0]->clone(); - AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone(); - while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } - if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); - this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - delete left_at_zero_ast; - delete right_at_zero_ast; - } else - this_width = range->range_left - range->range_right + 1; - sign_hint = false; - } - width_hint = max(width_hint, this_width); - if (!id_ast->is_signed) - sign_hint = false; - break; - - case AST_TO_BITS: - while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { } - if (children[0]->type != AST_CONSTANT) - log_file_error(filename, linenum, "Left operand of tobits expression is not constant!\n"); - children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); - width_hint = max(width_hint, children[0]->bitsAsConst().as_int()); - break; - - case AST_TO_SIGNED: - children.at(0)->detectSignWidthWorker(width_hint, sub_sign_hint); - break; - - case AST_TO_UNSIGNED: - children.at(0)->detectSignWidthWorker(width_hint, sub_sign_hint); - sign_hint = false; - break; - - case AST_CONCAT: - for (auto child : children) { - sub_width_hint = 0; - sub_sign_hint = true; - child->detectSignWidthWorker(sub_width_hint, sub_sign_hint); - this_width += sub_width_hint; - } - width_hint = max(width_hint, this_width); - sign_hint = false; - break; - - case AST_REPLICATE: - while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { } - if (children[0]->type != AST_CONSTANT) - log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n"); - children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); - width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint); - sign_hint = false; - break; - - case AST_NEG: - case AST_BIT_NOT: - case AST_POS: - children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real); - break; - - case AST_BIT_AND: - case AST_BIT_OR: - case AST_BIT_XOR: - case AST_BIT_XNOR: - for (auto child : children) - child->detectSignWidthWorker(width_hint, sign_hint, found_real); - break; - - case AST_REDUCE_AND: - case AST_REDUCE_OR: - case AST_REDUCE_XOR: - case AST_REDUCE_XNOR: - case AST_REDUCE_BOOL: - width_hint = max(width_hint, 1); - sign_hint = false; - break; - - case AST_SHIFT_LEFT: - case AST_SHIFT_RIGHT: - case AST_SHIFT_SLEFT: - case AST_SHIFT_SRIGHT: - case AST_POW: - children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real); - break; - - case AST_LT: - case AST_LE: - case AST_EQ: - case AST_NE: - case AST_EQX: - case AST_NEX: - case AST_GE: - case AST_GT: - width_hint = max(width_hint, 1); - sign_hint = false; - break; - - case AST_ADD: - case AST_SUB: - case AST_MUL: - case AST_DIV: - case AST_MOD: - for (auto child : children) - child->detectSignWidthWorker(width_hint, sign_hint, found_real); - break; - - case AST_LOGIC_AND: - case AST_LOGIC_OR: - case AST_LOGIC_NOT: - width_hint = max(width_hint, 1); - sign_hint = false; - break; - - case AST_TERNARY: - children.at(1)->detectSignWidthWorker(width_hint, sign_hint, found_real); - children.at(2)->detectSignWidthWorker(width_hint, sign_hint, found_real); - break; - - case AST_MEMRD: - if (!id2ast->is_signed) - sign_hint = false; - if (!id2ast->children[0]->range_valid) - log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); - this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1; - width_hint = max(width_hint, this_width); - break; - - case AST_FCALL: - if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { - if (GetSize(children) == 1) { - while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { } - if (children[0]->type != AST_CONSTANT) - log_file_error(filename, linenum, "System function %s called with non-const argument!\n", - RTLIL::unescape_id(str).c_str()); - width_hint = max(width_hint, int(children[0]->asInt(true))); - } - break; - } - if (str == "\\$past") { - if (GetSize(children) > 0) { - sub_width_hint = 0; - sub_sign_hint = true; - children.at(0)->detectSignWidthWorker(sub_width_hint, sub_sign_hint); - width_hint = max(width_hint, sub_width_hint); - sign_hint = false; - } - break; - } - /* fall through */ - - // everything should have been handled above -> print error if not. - default: - for (auto f : log_files) - current_ast_mod->dumpAst(f, "verilog-ast> "); - log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str()); - } - - if (*found_real) - sign_hint = true; -} - -// detect sign and width of an expression -void AstNode::detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real) -{ - width_hint = -1; - sign_hint = true; - if (found_real) - *found_real = false; - detectSignWidthWorker(width_hint, sign_hint, found_real); -} - -// create RTLIL from an AST node -// all generated cells, wires and processes are added to the module pointed to by 'current_module' -// when the AST node is an expression (AST_ADD, AST_BIT_XOR, etc.), the result signal is returned. -// -// note that this function is influenced by a number of global variables that might be set when -// called from genWidthRTLIL(). also note that this function recursively calls itself to transform -// larger expressions into a netlist of cells. -RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) -{ - // in the following big switch() statement there are some uses of - // Clifford's Device (http://www.clifford.at/cfun/cliffdev/). In this - // cases this variable is used to hold the type of the cell that should - // be instantiated for this type of AST node. - std::string type_name; - - current_filename = filename; - set_line_num(linenum); - - switch (type) - { - // simply ignore this nodes. - // they are either leftovers from simplify() or are referenced by other nodes - // and are only accessed here thru this references - case AST_NONE: - case AST_TASK: - case AST_FUNCTION: - case AST_DPI_FUNCTION: - case AST_AUTOWIRE: - case AST_DEFPARAM: - case AST_GENVAR: - case AST_GENFOR: - case AST_GENBLOCK: - case AST_GENIF: - case AST_GENCASE: - case AST_PACKAGE: - case AST_MODPORT: - case AST_MODPORTMEMBER: - break; - case AST_INTERFACEPORT: { - // If a port in a module with unknown type is found, mark it with the attribute 'is_interface' - // This is used by the hierarchy pass to know when it can replace interface connection with the individual - // signals. - RTLIL::Wire *wire = current_module->addWire(str, 1); - wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - wire->start_offset = 0; - wire->port_id = port_id; - wire->port_input = true; - wire->port_output = true; - wire->set_bool_attribute("\\is_interface"); - if (children.size() > 0) { - for(size_t i=0; itype == AST_INTERFACEPORTTYPE) { - std::pair res = AST::split_modport_from_type(children[i]->str); - wire->attributes["\\interface_type"] = res.first; - if (res.second != "") - wire->attributes["\\interface_modport"] = res.second; - break; - } - } - } - wire->upto = 0; - } - break; - case AST_INTERFACEPORTTYPE: - break; - - // remember the parameter, needed for example in techmap - case AST_PARAMETER: - current_module->avail_parameters.insert(str); - /* fall through */ - case AST_LOCALPARAM: - if (flag_pwires) - { - if (GetSize(children) < 1 || children[0]->type != AST_CONSTANT) - log_file_error(filename, linenum, "Parameter `%s' with non-constant value!\n", str.c_str()); - - RTLIL::Const val = children[0]->bitsAsConst(); - RTLIL::Wire *wire = current_module->addWire(str, GetSize(val)); - current_module->connect(wire, val); - - wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - wire->attributes[type == AST_PARAMETER ? "\\parameter" : "\\localparam"] = 1; - - for (auto &attr : attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - wire->attributes[attr.first] = attr.second->asAttrConst(); - } - } - break; - - // create an RTLIL::Wire for an AST_WIRE node - case AST_WIRE: { - if (current_module->wires_.count(str) != 0) - log_file_error(filename, linenum, "Re-definition of signal `%s'!\n", str.c_str()); - if (!range_valid) - log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str()); - - if (!(range_left >= range_right || (range_left == -1 && range_right == 0))) - log_file_error(filename, linenum, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1); - - RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1); - wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - wire->start_offset = range_right; - wire->port_id = port_id; - wire->port_input = is_input; - wire->port_output = is_output; - wire->upto = range_swapped; - - for (auto &attr : attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - wire->attributes[attr.first] = attr.second->asAttrConst(); - } - - if (is_wand) wire->set_bool_attribute("\\wand"); - if (is_wor) wire->set_bool_attribute("\\wor"); - } - break; - - // create an RTLIL::Memory for an AST_MEMORY node - case AST_MEMORY: { - if (current_module->memories.count(str) != 0) - log_file_error(filename, linenum, "Re-definition of memory `%s'!\n", str.c_str()); - - log_assert(children.size() >= 2); - log_assert(children[0]->type == AST_RANGE); - log_assert(children[1]->type == AST_RANGE); - - if (!children[0]->range_valid || !children[1]->range_valid) - log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n", str.c_str()); - - RTLIL::Memory *memory = new RTLIL::Memory; - memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - memory->name = str; - memory->width = children[0]->range_left - children[0]->range_right + 1; - if (children[1]->range_right < children[1]->range_left) { - memory->start_offset = children[1]->range_right; - memory->size = children[1]->range_left - children[1]->range_right + 1; - } else { - memory->start_offset = children[1]->range_left; - memory->size = children[1]->range_right - children[1]->range_left + 1; - } - current_module->memories[memory->name] = memory; - - for (auto &attr : attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - memory->attributes[attr.first] = attr.second->asAttrConst(); - } - } - break; - - // simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node - case AST_CONSTANT: - case AST_REALVALUE: - { - if (width_hint < 0) - detectSignWidth(width_hint, sign_hint); - is_signed = sign_hint; - - if (type == AST_CONSTANT) { - if (is_unsized) { - return RTLIL::SigSpec(bitsAsUnsizedConst(width_hint)); - } else { - return RTLIL::SigSpec(bitsAsConst()); - } - } - - RTLIL::SigSpec sig = realAsConst(width_hint); - log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); - return sig; - } - - // simply return the corresponding RTLIL::SigSpec for an AST_IDENTIFIER node - // for identifiers with dynamic bit ranges (e.g. "foo[bar]" or "foo[bar+3:bar]") a - // shifter cell is created and the output signal of this cell is returned - case AST_IDENTIFIER: - { - RTLIL::Wire *wire = NULL; - RTLIL::SigChunk chunk; - bool is_interface = false; - - int add_undef_bits_msb = 0; - int add_undef_bits_lsb = 0; - - if (id2ast && id2ast->type == AST_AUTOWIRE && current_module->wires_.count(str) == 0) { - RTLIL::Wire *wire = current_module->addWire(str); - wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - wire->name = str; - if (flag_autowire) - log_file_warning(filename, linenum, "Identifier `%s' is implicitly declared.\n", str.c_str()); - else - log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); - } - else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) { - if (id2ast->children[0]->type != AST_CONSTANT) - log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", str.c_str()); - chunk = RTLIL::Const(id2ast->children[0]->bits); - goto use_const_chunk; - } - else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) { - RTLIL::Wire *current_wire = current_module->wire(str); - if (current_wire->get_bool_attribute("\\is_interface")) - is_interface = true; - // Ignore - } - // If an identifier is found that is not already known, assume that it is an interface: - else if (1) { // FIXME: Check if sv_mode first? - is_interface = true; - } - else { - log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", str.c_str()); - } - - if (id2ast->type == AST_MEMORY) - log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n", str.c_str()); - - // If identifier is an interface, create a RTLIL::SigSpec with a dummy wire with a attribute called 'is_interface' - // This makes it possible for the hierarchy pass to see what are interface connections and then replace them - // with the individual signals: - if (is_interface) { - RTLIL::Wire *dummy_wire; - std::string dummy_wire_name = "$dummywireforinterface" + str; - if (current_module->wires_.count(dummy_wire_name)) - dummy_wire = current_module->wires_[dummy_wire_name]; - else { - dummy_wire = current_module->addWire(dummy_wire_name); - dummy_wire->set_bool_attribute("\\is_interface"); - } - RTLIL::SigSpec tmp = RTLIL::SigSpec(dummy_wire); - return tmp; - } - - wire = current_module->wires_[str]; - chunk.wire = wire; - chunk.width = wire->width; - chunk.offset = 0; - - use_const_chunk: - if (children.size() != 0) { - if (children[0]->type != AST_RANGE) - log_file_error(filename, linenum, "Single range expected.\n"); - int source_width = id2ast->range_left - id2ast->range_right + 1; - int source_offset = id2ast->range_right; - if (!children[0]->range_valid) { - AstNode *left_at_zero_ast = children[0]->children[0]->clone(); - AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone(); - while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } - if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); - int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? - children[0]->children[1]->clone() : children[0]->children[0]->clone()); - fake_ast->children[0]->delete_children(); - RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(); - if (id2ast->range_right != 0) { - shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast->children[1]->is_signed); - fake_ast->children[1]->is_signed = true; - } - if (id2ast->range_swapped) { - shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed); - fake_ast->children[1]->is_signed = true; - } - if (GetSize(shift_val) >= 32) - fake_ast->children[1]->is_signed = true; - RTLIL::SigSpec sig = binop2rtlil(fake_ast, "$shiftx", width, fake_ast->children[0]->genRTLIL(), shift_val); - delete left_at_zero_ast; - delete right_at_zero_ast; - delete fake_ast; - return sig; - } else { - chunk.width = children[0]->range_left - children[0]->range_right + 1; - chunk.offset = children[0]->range_right - source_offset; - if (id2ast->range_swapped) - chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width); - if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) { - if (chunk.width == 1) - log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", - str.c_str()); - else - log_file_warning(filename, linenum, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", - children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); - chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); - } else { - if (chunk.width + chunk.offset > source_width) { - add_undef_bits_msb = (chunk.width + chunk.offset) - source_width; - chunk.width -= add_undef_bits_msb; - } - if (chunk.offset < 0) { - add_undef_bits_lsb = -chunk.offset; - chunk.width -= add_undef_bits_lsb; - chunk.offset += add_undef_bits_lsb; - } - if (add_undef_bits_lsb) - log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", - children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); - if (add_undef_bits_msb) - log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", - children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); - } - } - } - - RTLIL::SigSpec sig = { RTLIL::SigSpec(RTLIL::State::Sx, add_undef_bits_msb), chunk, RTLIL::SigSpec(RTLIL::State::Sx, add_undef_bits_lsb) }; - - if (genRTLIL_subst_ptr) - sig.replace(*genRTLIL_subst_ptr); - - is_signed = children.size() > 0 ? false : id2ast->is_signed && sign_hint; - return sig; - } - - // just pass thru the signal. the parent will evaluate the is_signed property and interpret the SigSpec accordingly - case AST_TO_SIGNED: - case AST_TO_UNSIGNED: { - RTLIL::SigSpec sig = children[0]->genRTLIL(); - if (sig.size() < width_hint) - sig.extend_u0(width_hint, sign_hint); - is_signed = sign_hint; - return sig; - } - - // concatenation of signals can be done directly using RTLIL::SigSpec - case AST_CONCAT: { - RTLIL::SigSpec sig; - for (auto it = children.begin(); it != children.end(); it++) - sig.append((*it)->genRTLIL()); - if (sig.size() < width_hint) - sig.extend_u0(width_hint, false); - return sig; - } - - // replication of signals can be done directly using RTLIL::SigSpec - case AST_REPLICATE: { - RTLIL::SigSpec left = children[0]->genRTLIL(); - RTLIL::SigSpec right = children[1]->genRTLIL(); - if (!left.is_fully_const()) - log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n"); - int count = left.as_int(); - RTLIL::SigSpec sig; - for (int i = 0; i < count; i++) - sig.append(right); - if (sig.size() < width_hint) - sig.extend_u0(width_hint, false); - is_signed = false; - return sig; - } - - // generate cells for unary operations: $not, $pos, $neg - if (0) { case AST_BIT_NOT: type_name = "$not"; } - if (0) { case AST_POS: type_name = "$pos"; } - if (0) { case AST_NEG: type_name = "$neg"; } - { - RTLIL::SigSpec arg = children[0]->genRTLIL(width_hint, sign_hint); - is_signed = children[0]->is_signed; - int width = arg.size(); - if (width_hint > 0) { - width = width_hint; - widthExtend(this, arg, width, is_signed); - } - return uniop2rtlil(this, type_name, width, arg); - } - - // generate cells for binary operations: $and, $or, $xor, $xnor - if (0) { case AST_BIT_AND: type_name = "$and"; } - if (0) { case AST_BIT_OR: type_name = "$or"; } - if (0) { case AST_BIT_XOR: type_name = "$xor"; } - if (0) { case AST_BIT_XNOR: type_name = "$xnor"; } - { - if (width_hint < 0) - detectSignWidth(width_hint, sign_hint); - RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); - RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint); - int width = max(left.size(), right.size()); - if (width_hint > 0) - width = width_hint; - is_signed = children[0]->is_signed && children[1]->is_signed; - return binop2rtlil(this, type_name, width, left, right); - } - - // generate cells for unary operations: $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor - if (0) { case AST_REDUCE_AND: type_name = "$reduce_and"; } - if (0) { case AST_REDUCE_OR: type_name = "$reduce_or"; } - if (0) { case AST_REDUCE_XOR: type_name = "$reduce_xor"; } - if (0) { case AST_REDUCE_XNOR: type_name = "$reduce_xnor"; } - { - RTLIL::SigSpec arg = children[0]->genRTLIL(); - RTLIL::SigSpec sig = uniop2rtlil(this, type_name, max(width_hint, 1), arg); - return sig; - } - - // generate cells for unary operations: $reduce_bool - // (this is actually just an $reduce_or, but for clarity a different cell type is used) - if (0) { case AST_REDUCE_BOOL: type_name = "$reduce_bool"; } - { - RTLIL::SigSpec arg = children[0]->genRTLIL(); - RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, max(width_hint, 1), arg) : arg; - return sig; - } - - // generate cells for binary operations: $shl, $shr, $sshl, $sshr - if (0) { case AST_SHIFT_LEFT: type_name = "$shl"; } - if (0) { case AST_SHIFT_RIGHT: type_name = "$shr"; } - if (0) { case AST_SHIFT_SLEFT: type_name = "$sshl"; } - if (0) { case AST_SHIFT_SRIGHT: type_name = "$sshr"; } - { - if (width_hint < 0) - detectSignWidth(width_hint, sign_hint); - RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); - RTLIL::SigSpec right = children[1]->genRTLIL(); - int width = width_hint > 0 ? width_hint : left.size(); - is_signed = children[0]->is_signed; - return binop2rtlil(this, type_name, width, left, right); - } - - // generate cells for binary operations: $pow - case AST_POW: - { - int right_width; - bool right_signed; - children[1]->detectSignWidth(right_width, right_signed); - if (width_hint < 0) - detectSignWidth(width_hint, sign_hint); - RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); - RTLIL::SigSpec right = children[1]->genRTLIL(right_width, right_signed); - int width = width_hint > 0 ? width_hint : left.size(); - is_signed = children[0]->is_signed; - if (!flag_noopt && left.is_fully_const() && left.as_int() == 2 && !right_signed) - return binop2rtlil(this, "$shl", width, RTLIL::SigSpec(1, left.size()), right); - return binop2rtlil(this, "$pow", width, left, right); - } - - // generate cells for binary operations: $lt, $le, $eq, $ne, $ge, $gt - if (0) { case AST_LT: type_name = "$lt"; } - if (0) { case AST_LE: type_name = "$le"; } - if (0) { case AST_EQ: type_name = "$eq"; } - if (0) { case AST_NE: type_name = "$ne"; } - if (0) { case AST_EQX: type_name = "$eqx"; } - if (0) { case AST_NEX: type_name = "$nex"; } - if (0) { case AST_GE: type_name = "$ge"; } - if (0) { case AST_GT: type_name = "$gt"; } - { - int width = max(width_hint, 1); - width_hint = -1, sign_hint = true; - children[0]->detectSignWidthWorker(width_hint, sign_hint); - children[1]->detectSignWidthWorker(width_hint, sign_hint); - RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); - RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint); - RTLIL::SigSpec sig = binop2rtlil(this, type_name, width, left, right); - return sig; - } - - // generate cells for binary operations: $add, $sub, $mul, $div, $mod - if (0) { case AST_ADD: type_name = "$add"; } - if (0) { case AST_SUB: type_name = "$sub"; } - if (0) { case AST_MUL: type_name = "$mul"; } - if (0) { case AST_DIV: type_name = "$div"; } - if (0) { case AST_MOD: type_name = "$mod"; } - { - if (width_hint < 0) - detectSignWidth(width_hint, sign_hint); - RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); - RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint); - #if 0 - int width = max(left.size(), right.size()); - if (width > width_hint && width_hint > 0) - width = width_hint; - if (width < width_hint) { - if (type == AST_ADD || type == AST_SUB || type == AST_DIV) - width++; - if (type == AST_SUB && (!children[0]->is_signed || !children[1]->is_signed)) - width = width_hint; - if (type == AST_MUL) - width = min(left.size() + right.size(), width_hint); - } - #else - int width = max(max(left.size(), right.size()), width_hint); - #endif - is_signed = children[0]->is_signed && children[1]->is_signed; - return binop2rtlil(this, type_name, width, left, right); - } - - // generate cells for binary operations: $logic_and, $logic_or - if (0) { case AST_LOGIC_AND: type_name = "$logic_and"; } - if (0) { case AST_LOGIC_OR: type_name = "$logic_or"; } - { - RTLIL::SigSpec left = children[0]->genRTLIL(); - RTLIL::SigSpec right = children[1]->genRTLIL(); - return binop2rtlil(this, type_name, max(width_hint, 1), left, right); - } - - // generate cells for unary operations: $logic_not - case AST_LOGIC_NOT: - { - RTLIL::SigSpec arg = children[0]->genRTLIL(); - return uniop2rtlil(this, "$logic_not", max(width_hint, 1), arg); - } - - // generate multiplexer for ternary operator (aka ?:-operator) - case AST_TERNARY: - { - if (width_hint < 0) - detectSignWidth(width_hint, sign_hint); - - RTLIL::SigSpec cond = children[0]->genRTLIL(); - RTLIL::SigSpec val1 = children[1]->genRTLIL(width_hint, sign_hint); - RTLIL::SigSpec val2 = children[2]->genRTLIL(width_hint, sign_hint); - - if (cond.size() > 1) - cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false); - - int width = max(val1.size(), val2.size()); - is_signed = children[1]->is_signed && children[2]->is_signed; - widthExtend(this, val1, width, is_signed); - widthExtend(this, val2, width, is_signed); - - RTLIL::SigSpec sig = mux2rtlil(this, cond, val1, val2); - - if (sig.size() < width_hint) - sig.extend_u0(width_hint, sign_hint); - return sig; - } - - // generate $memrd cells for memory read ports - case AST_MEMRD: - { - std::stringstream sstr; - sstr << "$memrd$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); - - RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memrd"); - cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - - RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width); - wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - - int mem_width, mem_size, addr_bits; - is_signed = id2ast->is_signed; - id2ast->meminfo(mem_width, mem_size, addr_bits); - - RTLIL::SigSpec addr_sig = children[0]->genRTLIL(); - - cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); - cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1)); - cell->setPort("\\ADDR", addr_sig); - cell->setPort("\\DATA", RTLIL::SigSpec(wire)); - - cell->parameters["\\MEMID"] = RTLIL::Const(str); - cell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr_sig)); - cell->parameters["\\WIDTH"] = RTLIL::Const(wire->width); - - cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); - cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); - cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0); - - if (!sign_hint) - is_signed = false; - - return RTLIL::SigSpec(wire); - } - - // generate $memwr cells for memory write ports - case AST_MEMWR: - case AST_MEMINIT: - { - std::stringstream sstr; - sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++); - - RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit"); - cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - - int mem_width, mem_size, addr_bits; - id2ast->meminfo(mem_width, mem_size, addr_bits); - - int num_words = 1; - if (type == AST_MEMINIT) { - if (children[2]->type != AST_CONSTANT) - log_file_error(filename, linenum, "Memory init with non-constant word count!\n"); - num_words = int(children[2]->asInt(false)); - cell->parameters["\\WORDS"] = RTLIL::Const(num_words); - } - - SigSpec addr_sig = children[0]->genRTLIL(); - - cell->setPort("\\ADDR", addr_sig); - cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words)); - - cell->parameters["\\MEMID"] = RTLIL::Const(str); - cell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr_sig)); - cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width); - - if (type == AST_MEMWR) { - cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); - cell->setPort("\\EN", children[2]->genRTLIL()); - cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); - cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); - } - - cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1); - } - break; - - // generate $assert cells - case AST_ASSERT: - case AST_ASSUME: - case AST_LIVE: - case AST_FAIR: - case AST_COVER: - { - const char *celltype = nullptr; - if (type == AST_ASSERT) celltype = "$assert"; - if (type == AST_ASSUME) celltype = "$assume"; - if (type == AST_LIVE) celltype = "$live"; - if (type == AST_FAIR) celltype = "$fair"; - if (type == AST_COVER) celltype = "$cover"; - - log_assert(children.size() == 2); - - RTLIL::SigSpec check = children[0]->genRTLIL(); - if (GetSize(check) != 1) - check = current_module->ReduceBool(NEW_ID, check); - - RTLIL::SigSpec en = children[1]->genRTLIL(); - if (GetSize(en) != 1) - en = current_module->ReduceBool(NEW_ID, en); - - IdString cellname; - if (str.empty()) { - std::stringstream sstr; - sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); - cellname = sstr.str(); - } else { - cellname = str; - } - - RTLIL::Cell *cell = current_module->addCell(cellname, celltype); - cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - - for (auto &attr : attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - cell->attributes[attr.first] = attr.second->asAttrConst(); - } - - cell->setPort("\\A", check); - cell->setPort("\\EN", en); - } - break; - - // add entries to current_module->connections for assignments (outside of always blocks) - case AST_ASSIGN: - { - RTLIL::SigSpec left = children[0]->genRTLIL(); - RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size()); - if (left.has_const()) { - RTLIL::SigSpec new_left, new_right; - for (int i = 0; i < GetSize(left); i++) - if (left[i].wire) { - new_left.append(left[i]); - new_right.append(right[i]); - } - log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n" - " old assignment: %s = %s\n new assignment: %s = %s.\n", - log_signal(left), log_signal(right), - log_signal(new_left), log_signal(new_right)); - left = new_left; - right = new_right; - } - current_module->connect(RTLIL::SigSig(left, right)); - } - break; - - // create an RTLIL::Cell for an AST_CELL - case AST_CELL: - { - int port_counter = 0, para_counter = 0; - - if (current_module->count_id(str) != 0) - log_file_error(filename, linenum, "Re-definition of cell `%s'!\n", str.c_str()); - - RTLIL::Cell *cell = current_module->addCell(str, ""); - cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - // Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass - cell->set_bool_attribute("\\module_not_derived"); - - for (auto it = children.begin(); it != children.end(); it++) { - AstNode *child = *it; - if (child->type == AST_CELLTYPE) { - cell->type = child->str; - if (flag_icells && cell->type.substr(0, 2) == "\\$") - cell->type = cell->type.substr(1); - continue; - } - if (child->type == AST_PARASET) { - int extra_const_flags = 0; - IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; - if (child->children[0]->type == AST_REALVALUE) { - log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n", - log_id(cell), log_id(paraname), child->children[0]->realvalue); - extra_const_flags = RTLIL::CONST_FLAG_REAL; - auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); - strnode->cloneInto(child->children[0]); - delete strnode; - } - if (child->children[0]->type != AST_CONSTANT) - log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n", - log_id(cell), log_id(paraname)); - cell->parameters[paraname] = child->children[0]->asParaConst(); - cell->parameters[paraname].flags |= extra_const_flags; - continue; - } - if (child->type == AST_ARGUMENT) { - RTLIL::SigSpec sig; - if (child->children.size() > 0) - sig = child->children[0]->genRTLIL(); - if (child->str.size() == 0) { - char buf[100]; - snprintf(buf, 100, "$%d", ++port_counter); - cell->setPort(buf, sig); - } else { - cell->setPort(child->str, sig); - } - continue; - } - log_abort(); - } - for (auto &attr : attributes) { - if (attr.second->type != AST_CONSTANT) - log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str()); - cell->attributes[attr.first] = attr.second->asAttrConst(); - } - if (cell->type.in("$specify2", "$specify3")) { - int src_width = GetSize(cell->getPort("\\SRC")); - int dst_width = GetSize(cell->getPort("\\DST")); - bool full = cell->getParam("\\FULL").as_bool(); - if (!full && src_width != dst_width) - log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n"); - if (cell->type == "$specify3") { - int dat_width = GetSize(cell->getPort("\\DAT")); - if (dat_width != dst_width) - log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n"); - } - cell->setParam("\\SRC_WIDTH", Const(src_width)); - cell->setParam("\\DST_WIDTH", Const(dst_width)); - } - if (cell->type == "$specrule") { - int src_width = GetSize(cell->getPort("\\SRC")); - int dst_width = GetSize(cell->getPort("\\DST")); - cell->setParam("\\SRC_WIDTH", Const(src_width)); - cell->setParam("\\DST_WIDTH", Const(dst_width)); - } - } - break; - - // use ProcessGenerator for always blocks - case AST_ALWAYS: { - AstNode *always = this->clone(); - ProcessGenerator generator(always); - ignoreThisSignalsInInitial.append(generator.outputSignals); - delete always; - } break; - - case AST_INITIAL: { - AstNode *always = this->clone(); - ProcessGenerator generator(always, ignoreThisSignalsInInitial); - delete always; - } break; - - case AST_TECALL: { - int sz = children.size(); - if (str == "$info") { - if (sz > 0) - log_file_info(filename, linenum, "%s.\n", children[0]->str.c_str()); - else - log_file_info(filename, linenum, "\n"); - } else if (str == "$warning") { - if (sz > 0) - log_file_warning(filename, linenum, "%s.\n", children[0]->str.c_str()); - else - log_file_warning(filename, linenum, "\n"); - } else if (str == "$error") { - if (sz > 0) - log_file_error(filename, linenum, "%s.\n", children[0]->str.c_str()); - else - log_file_error(filename, linenum, "\n"); - } else if (str == "$fatal") { - // TODO: 1st parameter, if exists, is 0,1 or 2, and passed to $finish() - // if no parameter is given, default value is 1 - // dollar_finish(sz ? children[0] : 1); - // perhaps create & use log_file_fatal() - if (sz > 0) - log_file_error(filename, linenum, "FATAL: %s.\n", children[0]->str.c_str()); - else - log_file_error(filename, linenum, "FATAL.\n"); - } else { - log_file_error(filename, linenum, "Unknown elabortoon system task '%s'.\n", str.c_str()); - } - } break; - - case AST_FCALL: { - if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") - { - string myid = stringf("%s$%d", str.c_str() + 1, autoidx++); - int width = width_hint; - - if (GetSize(children) > 1) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n", - RTLIL::unescape_id(str).c_str(), GetSize(children)); - - if (GetSize(children) == 1) { - if (children[0]->type != AST_CONSTANT) - log_file_error(filename, linenum, "System function %s called with non-const argument!\n", - RTLIL::unescape_id(str).c_str()); - width = children[0]->asInt(true); - } - - if (width <= 0) - log_file_error(filename, linenum, "Failed to detect width of %s!\n", RTLIL::unescape_id(str).c_str()); - - Cell *cell = current_module->addCell(myid, str.substr(1)); - cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - cell->parameters["\\WIDTH"] = width; - - if (attributes.count("\\reg")) { - auto &attr = attributes.at("\\reg"); - if (attr->type != AST_CONSTANT) - log_file_error(filename, linenum, "Attribute `reg' with non-constant value!\n"); - cell->attributes["\\reg"] = attr->asAttrConst(); - } - - Wire *wire = current_module->addWire(myid + "_wire", width); - wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); - cell->setPort("\\Y", wire); - - is_signed = sign_hint; - return SigSpec(wire); - } - } /* fall through */ - - // everything should have been handled above -> print error if not. - default: - for (auto f : log_files) - current_ast_mod->dumpAst(f, "verilog-ast> "); - type_name = type2str(type); - log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str()); - } - - return RTLIL::SigSpec(); -} - -// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or -// signals must be substituted before being used as input values (used by ProcessGenerator) -// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL(). -RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict *new_subst_ptr) -{ - const dict *backup_subst_ptr = genRTLIL_subst_ptr; - - if (new_subst_ptr) - genRTLIL_subst_ptr = new_subst_ptr; - - bool sign_hint = true; - int width_hint = width; - detectSignWidthWorker(width_hint, sign_hint); - RTLIL::SigSpec sig = genRTLIL(width_hint, sign_hint); - - genRTLIL_subst_ptr = backup_subst_ptr; - - if (width >= 0) - sig.extend_u0(width, is_signed); - - return sig; -} - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/ast/simplify.cc b/yosys/frontends/ast/simplify.cc deleted file mode 100644 index e947125bf..000000000 --- a/yosys/frontends/ast/simplify.cc +++ /dev/null @@ -1,3657 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * This is the AST frontend library. - * - * The AST frontend library is not a frontend on it's own but provides a - * generic abstract syntax tree (AST) abstraction for HDL code and can be - * used by HDL frontends. See "ast.h" for an overview of the API and the - * Verilog frontend for an usage example. - * - */ - -#include "kernel/log.h" -#include "libs/sha1/sha1.h" -#include "frontends/verilog/verilog_frontend.h" -#include "ast.h" - -#include -#include -#include -#include - -YOSYS_NAMESPACE_BEGIN - -using namespace AST; -using namespace AST_INTERNAL; - -// convert the AST into a simpler AST that has all parameters substituted by their -// values, unrolled for-loops, expanded generate blocks, etc. when this function -// is done with an AST it can be converted into RTLIL using genRTLIL(). -// -// this function also does all name resolving and sets the id2ast member of all -// nodes that link to a different node using names and lexical scoping. -bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) -{ - static int recursion_counter = 0; - static bool deep_recursion_warning = false; - - if (recursion_counter++ == 1000 && deep_recursion_warning) { - log_warning("Deep recursion in AST simplifier.\nDoes this design contain insanely long expressions?\n"); - deep_recursion_warning = false; - } - - AstNode *newNode = NULL; - bool did_something = false; - -#if 0 - log("-------------\n"); - log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), linenum, type2str(type).c_str(), this); - log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n", - int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param)); - // dumpAst(NULL, "> "); -#endif - - if (stage == 0) - { - log_assert(type == AST_MODULE || type == AST_INTERFACE); - - deep_recursion_warning = true; - while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { } - - if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg")) - { - dict> mem2reg_places; - dict mem2reg_candidates, dummy_proc_flags; - uint32_t flags = flag_mem2reg ? AstNode::MEM2REG_FL_ALL : 0; - mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, dummy_proc_flags, flags); - - pool mem2reg_set; - for (auto &it : mem2reg_candidates) - { - AstNode *mem = it.first; - uint32_t memflags = it.second; - bool this_nomeminit = flag_nomeminit; - log_assert((memflags & ~0x00ffff00) == 0); - - if (mem->get_bool_attribute("\\nomem2reg")) - continue; - - if (mem->get_bool_attribute("\\nomeminit") || get_bool_attribute("\\nomeminit")) - this_nomeminit = true; - - if (memflags & AstNode::MEM2REG_FL_FORCED) - goto silent_activate; - - if (memflags & AstNode::MEM2REG_FL_EQ2) - goto verbose_activate; - - if (memflags & AstNode::MEM2REG_FL_SET_ASYNC) - goto verbose_activate; - - if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit) - goto verbose_activate; - - if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS) - goto verbose_activate; - - if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS)) - goto verbose_activate; - - // log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags)); - continue; - - verbose_activate: - if (mem2reg_set.count(mem) == 0) { - std::string message = stringf("Replacing memory %s with list of registers.", mem->str.c_str()); - bool first_element = true; - for (auto &place : mem2reg_places[it.first]) { - message += stringf("%s%s", first_element ? " See " : ", ", place.c_str()); - first_element = false; - } - log_warning("%s\n", message.c_str()); - } - - silent_activate: - // log("Note: Replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags)); - mem2reg_set.insert(mem); - } - - for (auto node : mem2reg_set) - { - int mem_width, mem_size, addr_bits; - node->meminfo(mem_width, mem_size, addr_bits); - - int data_range_left = node->children[0]->range_left; - int data_range_right = node->children[0]->range_right; - - if (node->children[0]->range_swapped) - std::swap(data_range_left, data_range_right); - - for (int i = 0; i < mem_size; i++) { - AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, - mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); - reg->str = stringf("%s[%d]", node->str.c_str(), i); - reg->is_reg = true; - reg->is_signed = node->is_signed; - children.push_back(reg); - while (reg->simplify(true, false, false, 1, -1, false, false)) { } - } - } - - AstNode *async_block = NULL; - while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL, async_block)) { } - - vector delnodes; - mem2reg_remove(mem2reg_set, delnodes); - - for (auto node : delnodes) - delete node; - } - - while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { } - recursion_counter--; - return false; - } - - current_filename = filename; - set_line_num(linenum); - - // we do not look inside a task or function - // (but as soon as a task or function is instantiated we process the generated AST as usual) - if (type == AST_FUNCTION || type == AST_TASK) { - recursion_counter--; - return false; - } - - // deactivate all calls to non-synthesis system tasks - // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list - if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || - str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { - log_file_warning(filename, linenum, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); - delete_children(); - str = std::string(); - } - - if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) { - log_file_warning(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str()); - delete_children(); - str = std::string(); - } - - // print messages if this a call to $display() or $write() - // This code implements only a small subset of Verilog-2005 $display() format specifiers, - // but should be good enough for most uses - if ((type == AST_TCALL) && ((str == "$display") || (str == "$write"))) - { - int nargs = GetSize(children); - if (nargs < 1) - log_file_error(filename, linenum, "System task `%s' got %d arguments, expected >= 1.\n", - str.c_str(), int(children.size())); - - // First argument is the format string - AstNode *node_string = children[0]; - while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (node_string->type != AST_CONSTANT) - log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str()); - std::string sformat = node_string->bitsAsConst().decode_string(); - - // Other arguments are placeholders. Process the string as we go through it - std::string sout; - int next_arg = 1; - for (size_t i = 0; i < sformat.length(); i++) - { - // format specifier - if (sformat[i] == '%') - { - // If there's no next character, that's a problem - if (i+1 >= sformat.length()) - log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str()); - - char cformat = sformat[++i]; - - // %% is special, does not need a matching argument - if (cformat == '%') - { - sout += '%'; - continue; - } - - // Simplify the argument - AstNode *node_arg = nullptr; - - // Everything from here on depends on the format specifier - switch (cformat) - { - case 's': - case 'S': - case 'd': - case 'D': - case 'x': - case 'X': - if (next_arg >= GetSize(children)) - log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n", - cformat, str.c_str()); - - node_arg = children[next_arg++]; - while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (node_arg->type != AST_CONSTANT) - log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str()); - break; - - case 'm': - case 'M': - break; - - default: - log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); - break; - } - - switch (cformat) - { - case 's': - case 'S': - sout += node_arg->bitsAsConst().decode_string(); - break; - - case 'd': - case 'D': - { - char tmp[128]; - snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int()); - sout += tmp; - } - break; - - case 'x': - case 'X': - { - char tmp[128]; - snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int()); - sout += tmp; - } - break; - - case 'm': - case 'M': - sout += log_id(current_module->name); - break; - - default: - log_abort(); - } - } - - // not a format specifier - else - sout += sformat[i]; - } - - // Finally, print the message (only include a \n for $display, not for $write) - log("%s", sout.c_str()); - if (str == "$display") - log("\n"); - delete_children(); - str = std::string(); - } - - // activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.) - if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX) - const_fold = true; - if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM)) - const_fold = true; - - // in certain cases a function must be evaluated constant. this is what in_param controls. - if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX) - in_param = true; - - std::map backup_scope; - - // create name resolution entries for all objects with names - // also merge multiple declarations for the same wire (e.g. "output foobar; reg foobar;") - if (type == AST_MODULE) { - current_scope.clear(); - std::map this_wire_scope; - for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; - if (node->type == AST_WIRE) { - if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { - for (auto c : node->children[0]->children) { - if (!c->is_simple_const_expr()) { - if (attributes.count("\\dynports")) - delete attributes.at("\\dynports"); - attributes["\\dynports"] = AstNode::mkconst_int(1, true); - } - } - } - if (this_wire_scope.count(node->str) > 0) { - AstNode *first_node = this_wire_scope[node->str]; - if (first_node->is_input && node->is_reg) - goto wires_are_incompatible; - if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0) - goto wires_are_compatible; - if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) { - AstNode *r = node->children[0]; - if (r->range_valid && r->range_left == 0 && r->range_right == 0) { - delete r; - node->children.pop_back(); - } - } - if (first_node->children.size() != node->children.size()) - goto wires_are_incompatible; - for (size_t j = 0; j < node->children.size(); j++) { - AstNode *n1 = first_node->children[j], *n2 = node->children[j]; - if (n1->type == AST_RANGE && n2->type == AST_RANGE && n1->range_valid && n2->range_valid) { - if (n1->range_left != n2->range_left) - goto wires_are_incompatible; - if (n1->range_right != n2->range_right) - goto wires_are_incompatible; - } else if (*n1 != *n2) - goto wires_are_incompatible; - } - if (first_node->range_left != node->range_left) - goto wires_are_incompatible; - if (first_node->range_right != node->range_right) - goto wires_are_incompatible; - if (first_node->port_id == 0 && (node->is_input || node->is_output)) - goto wires_are_incompatible; - wires_are_compatible: - if (node->is_input) - first_node->is_input = true; - if (node->is_output) - first_node->is_output = true; - if (node->is_reg) - first_node->is_reg = true; - if (node->is_logic) - first_node->is_logic = true; - if (node->is_signed) - first_node->is_signed = true; - for (auto &it : node->attributes) { - if (first_node->attributes.count(it.first) > 0) - delete first_node->attributes[it.first]; - first_node->attributes[it.first] = it.second->clone(); - } - children.erase(children.begin()+(i--)); - did_something = true; - delete node; - continue; - wires_are_incompatible: - if (stage > 1) - log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", node->str.c_str()); - continue; - } - this_wire_scope[node->str] = node; - } - if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR || - node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL) { - backup_scope[node->str] = current_scope[node->str]; - current_scope[node->str] = node; - } - } - for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; - if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY) - while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) - did_something = true; - } - } - - auto backup_current_block = current_block; - auto backup_current_block_child = current_block_child; - auto backup_current_top_block = current_top_block; - auto backup_current_always = current_always; - auto backup_current_always_clocked = current_always_clocked; - - if (type == AST_ALWAYS || type == AST_INITIAL) - { - if (current_always != nullptr) - log_file_error(filename, linenum, "Invalid nesting of always blocks and/or initializations.\n"); - - current_always = this; - current_always_clocked = false; - - if (type == AST_ALWAYS) - for (auto child : children) { - if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) - current_always_clocked = true; - if (child->type == AST_EDGE && GetSize(child->children) == 1 && - child->children[0]->type == AST_IDENTIFIER && child->children[0]->str == "\\$global_clock") - current_always_clocked = true; - } - } - - int backup_width_hint = width_hint; - bool backup_sign_hint = sign_hint; - - bool detect_width_simple = false; - bool child_0_is_self_determined = false; - bool child_1_is_self_determined = false; - bool child_2_is_self_determined = false; - bool children_are_self_determined = false; - bool reset_width_after_children = false; - - switch (type) - { - case AST_ASSIGN_EQ: - case AST_ASSIGN_LE: - case AST_ASSIGN: - while (!children[0]->basic_prep && children[0]->simplify(false, false, true, stage, -1, false, in_param) == true) - did_something = true; - while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, in_param) == true) - did_something = true; - children[0]->detectSignWidth(backup_width_hint, backup_sign_hint); - children[1]->detectSignWidth(width_hint, sign_hint); - width_hint = max(width_hint, backup_width_hint); - child_0_is_self_determined = true; - // test only once, before optimizations and memory mappings but after assignment LHS was mapped to an identifier - if (children[0]->id2ast && !children[0]->was_checked) { - if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->id2ast->is_logic) - children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment - if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg) - log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); - if (type == AST_ASSIGN && children[0]->id2ast->is_reg) { - bool is_rand_reg = false; - if (children[1]->type == AST_FCALL) { - if (children[1]->str == "\\$anyconst") - is_rand_reg = true; - if (children[1]->str == "\\$anyseq") - is_rand_reg = true; - if (children[1]->str == "\\$allconst") - is_rand_reg = true; - if (children[1]->str == "\\$allseq") - is_rand_reg = true; - } - if (!is_rand_reg) - log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); - } - children[0]->was_checked = true; - } - break; - - case AST_PARAMETER: - case AST_LOCALPARAM: - while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true) - did_something = true; - children[0]->detectSignWidth(width_hint, sign_hint); - if (children.size() > 1 && children[1]->type == AST_RANGE) { - while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true) - did_something = true; - if (!children[1]->range_valid) - log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); - width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1); - } - break; - - case AST_TO_BITS: - case AST_TO_SIGNED: - case AST_TO_UNSIGNED: - case AST_CONCAT: - case AST_REPLICATE: - case AST_REDUCE_AND: - case AST_REDUCE_OR: - case AST_REDUCE_XOR: - case AST_REDUCE_XNOR: - case AST_REDUCE_BOOL: - detect_width_simple = true; - children_are_self_determined = true; - break; - - case AST_NEG: - case AST_BIT_NOT: - case AST_POS: - case AST_BIT_AND: - case AST_BIT_OR: - case AST_BIT_XOR: - case AST_BIT_XNOR: - case AST_ADD: - case AST_SUB: - case AST_MUL: - case AST_DIV: - case AST_MOD: - detect_width_simple = true; - break; - - case AST_SHIFT_LEFT: - case AST_SHIFT_RIGHT: - case AST_SHIFT_SLEFT: - case AST_SHIFT_SRIGHT: - case AST_POW: - detect_width_simple = true; - child_1_is_self_determined = true; - break; - - case AST_LT: - case AST_LE: - case AST_EQ: - case AST_NE: - case AST_EQX: - case AST_NEX: - case AST_GE: - case AST_GT: - width_hint = -1; - sign_hint = true; - for (auto child : children) { - while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true) - did_something = true; - child->detectSignWidthWorker(width_hint, sign_hint); - } - reset_width_after_children = true; - break; - - case AST_LOGIC_AND: - case AST_LOGIC_OR: - case AST_LOGIC_NOT: - detect_width_simple = true; - children_are_self_determined = true; - break; - - case AST_TERNARY: - detect_width_simple = true; - child_0_is_self_determined = true; - break; - - case AST_MEMRD: - detect_width_simple = true; - children_are_self_determined = true; - break; - - case AST_FCALL: - case AST_TCALL: - children_are_self_determined = true; - break; - - default: - width_hint = -1; - sign_hint = false; - } - - if (detect_width_simple && width_hint < 0) { - if (type == AST_REPLICATE) - while (children[0]->simplify(true, false, in_lvalue, stage, -1, false, true) == true) - did_something = true; - for (auto child : children) - while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true) - did_something = true; - detectSignWidth(width_hint, sign_hint); - } - - if (type == AST_FCALL && str == "\\$past") - detectSignWidth(width_hint, sign_hint); - - if (type == AST_TERNARY) { - int width_hint_left, width_hint_right; - bool sign_hint_left, sign_hint_right; - bool found_real_left, found_real_right; - children[1]->detectSignWidth(width_hint_left, sign_hint_left, &found_real_left); - children[2]->detectSignWidth(width_hint_right, sign_hint_right, &found_real_right); - if (found_real_left || found_real_right) { - child_1_is_self_determined = true; - child_2_is_self_determined = true; - } - } - - if (type == AST_CONDX && children.size() > 0 && children.at(0)->type == AST_CONSTANT) { - for (auto &bit : children.at(0)->bits) - if (bit == State::Sz || bit == State::Sx) - bit = State::Sa; - } - - if (type == AST_CONDZ && children.size() > 0 && children.at(0)->type == AST_CONSTANT) { - for (auto &bit : children.at(0)->bits) - if (bit == State::Sz) - bit = State::Sa; - } - - if (const_fold && type == AST_CASE) - { - while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { } - if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) { - std::vector new_children; - new_children.push_back(children[0]); - for (int i = 1; i < GetSize(children); i++) { - AstNode *child = children[i]; - log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); - for (auto v : child->children) { - if (v->type == AST_DEFAULT) - goto keep_const_cond; - if (v->type == AST_BLOCK) - continue; - while (v->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { } - if (v->type == AST_CONSTANT && v->bits_only_01()) { - if (v->bits == children[0]->bits) { - while (i+1 < GetSize(children)) - delete children[++i]; - goto keep_const_cond; - } - continue; - } - goto keep_const_cond; - } - if (0) - keep_const_cond: - new_children.push_back(child); - else - delete child; - } - new_children.swap(children); - } - } - - // simplify all children first - // (iterate by index as e.g. auto wires can add new children in the process) - for (size_t i = 0; i < children.size(); i++) { - bool did_something_here = true; - bool backup_flag_autowire = flag_autowire; - if ((type == AST_GENFOR || type == AST_FOR) && i >= 3) - break; - if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1) - break; - if (type == AST_GENBLOCK) - break; - if (type == AST_BLOCK && !str.empty()) - break; - if (type == AST_PREFIX && i >= 1) - break; - if (type == AST_DEFPARAM && i == 0) - flag_autowire = true; - while (did_something_here && i < children.size()) { - bool const_fold_here = const_fold, in_lvalue_here = in_lvalue; - int width_hint_here = width_hint; - bool sign_hint_here = sign_hint; - bool in_param_here = in_param; - if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE)) - const_fold_here = true, in_param_here = true; - if (type == AST_PARAMETER || type == AST_LOCALPARAM) - const_fold_here = true; - if (i == 0 && (type == AST_ASSIGN || type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE)) - in_lvalue_here = true; - if (type == AST_BLOCK) { - current_block = this; - current_block_child = children[i]; - } - if ((type == AST_ALWAYS || type == AST_INITIAL) && children[i]->type == AST_BLOCK) - current_top_block = children[i]; - if (i == 0 && child_0_is_self_determined) - width_hint_here = -1, sign_hint_here = false; - if (i == 1 && child_1_is_self_determined) - width_hint_here = -1, sign_hint_here = false; - if (i == 2 && child_2_is_self_determined) - width_hint_here = -1, sign_hint_here = false; - if (children_are_self_determined) - width_hint_here = -1, sign_hint_here = false; - did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage, width_hint_here, sign_hint_here, in_param_here); - if (did_something_here) - did_something = true; - } - if (stage == 2 && children[i]->type == AST_INITIAL && current_ast_mod != this) { - current_ast_mod->children.push_back(children[i]); - children.erase(children.begin() + (i--)); - did_something = true; - } - flag_autowire = backup_flag_autowire; - } - for (auto &attr : attributes) { - while (attr.second->simplify(true, false, false, stage, -1, false, true)) - did_something = true; - } - - if (reset_width_after_children) { - width_hint = backup_width_hint; - sign_hint = backup_sign_hint; - if (width_hint < 0) - detectSignWidth(width_hint, sign_hint); - } - - current_block = backup_current_block; - current_block_child = backup_current_block_child; - current_top_block = backup_current_top_block; - current_always = backup_current_always; - current_always_clocked = backup_current_always_clocked; - - for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) { - if (it->second == NULL) - current_scope.erase(it->first); - else - current_scope[it->first] = it->second; - } - - current_filename = filename; - set_line_num(linenum); - - if (type == AST_MODULE) - current_scope.clear(); - - // convert defparam nodes to cell parameters - if (type == AST_DEFPARAM && !children.empty()) - { - if (children[0]->type != AST_IDENTIFIER) - log_file_error(filename, linenum, "Module name in defparam contains non-constant expressions!\n"); - - string modname, paramname = children[0]->str; - - size_t pos = paramname.rfind('.'); - - while (pos != 0 && pos != std::string::npos) - { - modname = paramname.substr(0, pos); - - if (current_scope.count(modname)) - break; - - pos = paramname.rfind('.', pos - 1); - } - - if (pos == std::string::npos) - log_file_error(filename, linenum, "Can't find object for defparam `%s`!\n", RTLIL::unescape_id(paramname).c_str()); - - paramname = "\\" + paramname.substr(pos+1); - - if (current_scope.at(modname)->type != AST_CELL) - log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n", - RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str()); - - AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL); - paraset->str = paramname; - - AstNode *cell = current_scope.at(modname); - cell->children.insert(cell->children.begin() + 1, paraset); - delete_children(); - } - - // resolve constant prefixes - if (type == AST_PREFIX) { - if (children[0]->type != AST_CONSTANT) { - // dumpAst(NULL, "> "); - log_file_error(filename, linenum, "Index in generate block prefix syntax is not constant!\n"); - } - if (children[1]->type == AST_PREFIX) - children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param); - log_assert(children[1]->type == AST_IDENTIFIER); - newNode = children[1]->clone(); - const char *second_part = children[1]->str.c_str(); - if (second_part[0] == '\\') - second_part++; - newNode->str = stringf("%s[%d].%s", str.c_str(), children[0]->integer, second_part); - goto apply_newNode; - } - - // evaluate TO_BITS nodes - if (type == AST_TO_BITS) { - if (children[0]->type != AST_CONSTANT) - log_file_error(filename, linenum, "Left operand of to_bits expression is not constant!\n"); - if (children[1]->type != AST_CONSTANT) - log_file_error(filename, linenum, "Right operand of to_bits expression is not constant!\n"); - RTLIL::Const new_value = children[1]->bitsAsConst(children[0]->bitsAsConst().as_int(), children[1]->is_signed); - newNode = mkconst_bits(new_value.bits, children[1]->is_signed); - goto apply_newNode; - } - - // annotate constant ranges - if (type == AST_RANGE) { - bool old_range_valid = range_valid; - range_valid = false; - range_swapped = false; - range_left = -1; - range_right = 0; - log_assert(children.size() >= 1); - if (children[0]->type == AST_CONSTANT) { - range_valid = true; - range_left = children[0]->integer; - if (children.size() == 1) - range_right = range_left; - } - if (children.size() >= 2) { - if (children[1]->type == AST_CONSTANT) - range_right = children[1]->integer; - else - range_valid = false; - } - if (old_range_valid != range_valid) - did_something = true; - if (range_valid && range_left >= 0 && range_right > range_left) { - int tmp = range_right; - range_right = range_left; - range_left = tmp; - range_swapped = true; - } - } - - // annotate wires with their ranges - if (type == AST_WIRE) { - if (children.size() > 0) { - if (children[0]->range_valid) { - if (!range_valid) - did_something = true; - range_valid = true; - range_swapped = children[0]->range_swapped; - range_left = children[0]->range_left; - range_right = children[0]->range_right; - } - } else { - if (!range_valid) - did_something = true; - range_valid = true; - range_swapped = false; - range_left = 0; - range_right = 0; - } - } - - // resolve multiranges on memory decl - if (type == AST_MEMORY && children.size() > 1 && children[1]->type == AST_MULTIRANGE) - { - int total_size = 1; - multirange_dimensions.clear(); - for (auto range : children[1]->children) { - if (!range->range_valid) - log_file_error(filename, linenum, "Non-constant range on memory decl.\n"); - multirange_dimensions.push_back(min(range->range_left, range->range_right)); - multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1); - total_size *= multirange_dimensions.back(); - } - delete children[1]; - children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true)); - did_something = true; - } - - // resolve multiranges on memory access - if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY && children.size() > 0 && children[0]->type == AST_MULTIRANGE) - { - AstNode *index_expr = nullptr; - - for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++) - { - if (GetSize(children[0]->children) < i) - log_file_error(filename, linenum, "Insufficient number of array indices for %s.\n", log_id(str)); - - AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone(); - - if (id2ast->multirange_dimensions[2*i]) - new_index_expr = new AstNode(AST_SUB, new_index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i], true)); - - if (i == 0) - index_expr = new_index_expr; - else - index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i+1], true)), new_index_expr); - } - - for (int i = GetSize(id2ast->multirange_dimensions)/2; i < GetSize(children[0]->children); i++) - children.push_back(children[0]->children[i]->clone()); - - delete children[0]; - if (index_expr == nullptr) - children.erase(children.begin()); - else - children[0] = new AstNode(AST_RANGE, index_expr); - - did_something = true; - } - - // trim/extend parameters - if (type == AST_PARAMETER || type == AST_LOCALPARAM) { - if (children.size() > 1 && children[1]->type == AST_RANGE) { - if (!children[1]->range_valid) - log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); - int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; - if (children[0]->type == AST_REALVALUE) { - RTLIL::Const constvalue = children[0]->realAsConst(width); - log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", - children[0]->realvalue, log_signal(constvalue)); - delete children[0]; - children[0] = mkconst_bits(constvalue.bits, sign_hint); - did_something = true; - } - if (children[0]->type == AST_CONSTANT) { - if (width != int(children[0]->bits.size())) { - RTLIL::SigSpec sig(children[0]->bits); - sig.extend_u0(width, children[0]->is_signed); - AstNode *old_child_0 = children[0]; - children[0] = mkconst_bits(sig.as_const().bits, is_signed); - delete old_child_0; - } - children[0]->is_signed = is_signed; - } - range_valid = true; - range_swapped = children[1]->range_swapped; - range_left = children[1]->range_left; - range_right = children[1]->range_right; - } else - if (children.size() > 1 && children[1]->type == AST_REALVALUE && children[0]->type == AST_CONSTANT) { - double as_realvalue = children[0]->asReal(sign_hint); - delete children[0]; - children[0] = new AstNode(AST_REALVALUE); - children[0]->realvalue = as_realvalue; - did_something = true; - } - } - - // annotate identifiers using scope resolution and create auto-wires as needed - if (type == AST_IDENTIFIER) { - if (current_scope.count(str) == 0) { - for (auto node : current_ast_mod->children) { - if ((node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR || - node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION) && str == node->str) { - current_scope[node->str] = node; - break; - } - } - } - if (current_scope.count(str) == 0) { - if (flag_autowire || str == "\\$global_clock") { - AstNode *auto_wire = new AstNode(AST_AUTOWIRE); - auto_wire->str = str; - current_ast_mod->children.push_back(auto_wire); - current_scope[str] = auto_wire; - did_something = true; - } else { - log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); - } - } - if (id2ast != current_scope[str]) { - id2ast = current_scope[str]; - did_something = true; - } - } - - // split memory access with bit select to individual statements - if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue) - { - if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) - log_file_error(filename, linenum, "Invalid bit-select on memory access!\n"); - - int mem_width, mem_size, addr_bits; - id2ast->meminfo(mem_width, mem_size, addr_bits); - - int data_range_left = id2ast->children[0]->range_left; - int data_range_right = id2ast->children[0]->range_right; - - if (id2ast->children[0]->range_swapped) - std::swap(data_range_left, data_range_right); - - std::stringstream sstr; - sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); - std::string wire_id = sstr.str(); - - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); - wire->str = wire_id; - if (current_block) - wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); - current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *data = clone(); - delete data->children[1]; - data->children.pop_back(); - - AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data); - assign->children[0]->str = wire_id; - assign->children[0]->was_checked = true; - - if (current_block) - { - size_t assign_idx = 0; - while (assign_idx < current_block->children.size() && current_block->children[assign_idx] != current_block_child) - assign_idx++; - log_assert(assign_idx < current_block->children.size()); - current_block->children.insert(current_block->children.begin()+assign_idx, assign); - wire->is_reg = true; - } - else - { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - proc->children[0]->children.push_back(assign); - current_ast_mod->children.push_back(proc); - } - - newNode = new AstNode(AST_IDENTIFIER, children[1]->clone()); - newNode->str = wire_id; - newNode->id2ast = wire; - goto apply_newNode; - } - - if (type == AST_WHILE) - log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n"); - - if (type == AST_REPEAT) - { - AstNode *count = children[0]; - AstNode *body = children[1]; - - // eval count expression - while (count->simplify(true, false, false, stage, 32, true, false)) { } - - if (count->type != AST_CONSTANT) - log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n"); - - // convert to a block with the body repeated n times - type = AST_BLOCK; - children.clear(); - for (int i = 0; i < count->bitsAsConst().as_int(); i++) - children.insert(children.begin(), body->clone()); - - delete count; - delete body; - did_something = true; - } - - // unroll for loops and generate-for blocks - if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) - { - AstNode *init_ast = children[0]; - AstNode *while_ast = children[1]; - AstNode *next_ast = children[2]; - AstNode *body_ast = children[3]; - - while (body_ast->type == AST_GENBLOCK && body_ast->str.empty() && - body_ast->children.size() == 1 && body_ast->children.at(0)->type == AST_GENBLOCK) - body_ast = body_ast->children.at(0); - - if (init_ast->type != AST_ASSIGN_EQ) - log_file_error(filename, linenum, "Unsupported 1st expression of generate for-loop!\n"); - if (next_ast->type != AST_ASSIGN_EQ) - log_file_error(filename, linenum, "Unsupported 3rd expression of generate for-loop!\n"); - - if (type == AST_GENFOR) { - if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_GENVAR) - log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a gen var!\n"); - if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_GENVAR) - log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a gen var!\n"); - } else { - if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_WIRE) - log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a register!\n"); - if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_WIRE) - log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a register!\n"); - } - - if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast) - log_file_error(filename, linenum, "Incompatible left-hand sides in 1st and 3rd expression of generate for-loop!\n"); - - // eval 1st expression - AstNode *varbuf = init_ast->children[1]->clone(); - { - int expr_width_hint = -1; - bool expr_sign_hint = true; - varbuf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } - } - - if (varbuf->type != AST_CONSTANT) - log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); - - varbuf = new AstNode(AST_LOCALPARAM, varbuf); - varbuf->str = init_ast->children[0]->str; - - AstNode *backup_scope_varbuf = current_scope[varbuf->str]; - current_scope[varbuf->str] = varbuf; - - size_t current_block_idx = 0; - if (type == AST_FOR) { - while (current_block_idx < current_block->children.size() && - current_block->children[current_block_idx] != current_block_child) - current_block_idx++; - } - - while (1) - { - // eval 2nd expression - AstNode *buf = while_ast->clone(); - { - int expr_width_hint = -1; - bool expr_sign_hint = true; - buf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { } - } - - if (buf->type != AST_CONSTANT) - log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); - - if (buf->integer == 0) { - delete buf; - break; - } - delete buf; - - // expand body - int index = varbuf->children[0]->integer; - if (body_ast->type == AST_GENBLOCK) - buf = body_ast->clone(); - else - buf = new AstNode(AST_GENBLOCK, body_ast->clone()); - if (buf->str.empty()) { - std::stringstream sstr; - sstr << "$genblock$" << filename << ":" << linenum << "$" << (autoidx++); - buf->str = sstr.str(); - } - std::map name_map; - std::stringstream sstr; - sstr << buf->str << "[" << index << "]."; - buf->expand_genblock(varbuf->str, sstr.str(), name_map); - - if (type == AST_GENFOR) { - for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(false, false, false, stage, -1, false, false); - current_ast_mod->children.push_back(buf->children[i]); - } - } else { - for (size_t i = 0; i < buf->children.size(); i++) - current_block->children.insert(current_block->children.begin() + current_block_idx++, buf->children[i]); - } - buf->children.clear(); - delete buf; - - // eval 3rd expression - buf = next_ast->children[1]->clone(); - { - int expr_width_hint = -1; - bool expr_sign_hint = true; - buf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { } - } - - if (buf->type != AST_CONSTANT) - log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); - - delete varbuf->children[0]; - varbuf->children[0] = buf; - } - - if (type == AST_FOR) { - AstNode *buf = next_ast->clone(); - delete buf->children[1]; - buf->children[1] = varbuf->children[0]->clone(); - current_block->children.insert(current_block->children.begin() + current_block_idx++, buf); - } - - current_scope[varbuf->str] = backup_scope_varbuf; - delete varbuf; - delete_children(); - did_something = true; - } - - // check for local objects in unnamed block - if (type == AST_BLOCK && str.empty()) - { - for (size_t i = 0; i < children.size(); i++) - if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) - log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n"); - } - - // transform block with name - if (type == AST_BLOCK && !str.empty()) - { - std::map name_map; - expand_genblock(std::string(), str + ".", name_map); - - std::vector new_children; - for (size_t i = 0; i < children.size(); i++) - if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) { - children[i]->simplify(false, false, false, stage, -1, false, false); - current_ast_mod->children.push_back(children[i]); - current_scope[children[i]->str] = children[i]; - } else - new_children.push_back(children[i]); - - children.swap(new_children); - did_something = true; - str.clear(); - } - - // simplify unconditional generate block - if (type == AST_GENBLOCK && children.size() != 0) - { - if (!str.empty()) { - std::map name_map; - expand_genblock(std::string(), str + ".", name_map); - } - - for (size_t i = 0; i < children.size(); i++) { - children[i]->simplify(false, false, false, stage, -1, false, false); - current_ast_mod->children.push_back(children[i]); - } - - children.clear(); - did_something = true; - } - - // simplify generate-if blocks - if (type == AST_GENIF && children.size() != 0) - { - AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (buf->type != AST_CONSTANT) { - // for (auto f : log_files) - // dumpAst(f, "verilog-ast> "); - log_file_error(filename, linenum, "Condition for generate if is not constant!\n"); - } - if (buf->asBool() != 0) { - delete buf; - buf = children[1]->clone(); - } else { - delete buf; - buf = children.size() > 2 ? children[2]->clone() : NULL; - } - - if (buf) - { - if (buf->type != AST_GENBLOCK) - buf = new AstNode(AST_GENBLOCK, buf); - - if (!buf->str.empty()) { - std::map name_map; - buf->expand_genblock(std::string(), buf->str + ".", name_map); - } - - for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(false, false, false, stage, -1, false, false); - current_ast_mod->children.push_back(buf->children[i]); - } - - buf->children.clear(); - delete buf; - } - - delete_children(); - did_something = true; - } - - // simplify generate-case blocks - if (type == AST_GENCASE && children.size() != 0) - { - AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (buf->type != AST_CONSTANT) { - // for (auto f : log_files) - // dumpAst(f, "verilog-ast> "); - log_file_error(filename, linenum, "Condition for generate case is not constant!\n"); - } - - bool ref_signed = buf->is_signed; - RTLIL::Const ref_value = buf->bitsAsConst(); - delete buf; - - AstNode *selected_case = NULL; - for (size_t i = 1; i < children.size(); i++) - { - log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ); - - AstNode *this_genblock = NULL; - for (auto child : children.at(i)->children) { - log_assert(this_genblock == NULL); - if (child->type == AST_GENBLOCK) - this_genblock = child; - } - - for (auto child : children.at(i)->children) - { - if (child->type == AST_DEFAULT) { - if (selected_case == NULL) - selected_case = this_genblock; - continue; - } - if (child->type == AST_GENBLOCK) - continue; - - buf = child->clone(); - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (buf->type != AST_CONSTANT) { - // for (auto f : log_files) - // dumpAst(f, "verilog-ast> "); - log_file_error(filename, linenum, "Expression in generate case is not constant!\n"); - } - - bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool(); - delete buf; - - if (is_selected) { - selected_case = this_genblock; - i = children.size(); - break; - } - } - } - - if (selected_case != NULL) - { - log_assert(selected_case->type == AST_GENBLOCK); - buf = selected_case->clone(); - - if (!buf->str.empty()) { - std::map name_map; - buf->expand_genblock(std::string(), buf->str + ".", name_map); - } - - for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(false, false, false, stage, -1, false, false); - current_ast_mod->children.push_back(buf->children[i]); - } - - buf->children.clear(); - delete buf; - } - - delete_children(); - did_something = true; - } - - // unroll cell arrays - if (type == AST_CELLARRAY) - { - if (!children.at(0)->range_valid) - log_file_error(filename, linenum, "Non-constant array range on cell array.\n"); - - newNode = new AstNode(AST_GENBLOCK); - int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1; - - for (int i = 0; i < num; i++) { - int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i; - AstNode *new_cell = children.at(1)->clone(); - newNode->children.push_back(new_cell); - new_cell->str += stringf("[%d]", idx); - if (new_cell->type == AST_PRIMITIVE) { - log_file_error(filename, linenum, "Cell arrays of primitives are currently not supported.\n"); - } else { - log_assert(new_cell->children.at(0)->type == AST_CELLTYPE); - new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str()); - } - } - - goto apply_newNode; - } - - // replace primitives with assignments - if (type == AST_PRIMITIVE) - { - if (children.size() < 2) - log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n", str.c_str()); - - std::vector children_list; - for (auto child : children) { - log_assert(child->type == AST_ARGUMENT); - log_assert(child->children.size() == 1); - children_list.push_back(child->children[0]); - child->children.clear(); - delete child; - } - children.clear(); - - if (str == "bufif0" || str == "bufif1" || str == "notif0" || str == "notif1") - { - if (children_list.size() != 3) - log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n", str.c_str()); - - std::vector z_const(1, RTLIL::State::Sz); - - AstNode *mux_input = children_list.at(1); - if (str == "notif0" || str == "notif1") { - mux_input = new AstNode(AST_BIT_NOT, mux_input); - } - AstNode *node = new AstNode(AST_TERNARY, children_list.at(2)); - if (str == "bufif0") { - node->children.push_back(AstNode::mkconst_bits(z_const, false)); - node->children.push_back(mux_input); - } else { - node->children.push_back(mux_input); - node->children.push_back(AstNode::mkconst_bits(z_const, false)); - } - - str.clear(); - type = AST_ASSIGN; - children.push_back(children_list.at(0)); - children.back()->was_checked = true; - children.push_back(node); - did_something = true; - } - else - { - AstNodeType op_type = AST_NONE; - bool invert_results = false; - - if (str == "and") - op_type = AST_BIT_AND; - if (str == "nand") - op_type = AST_BIT_AND, invert_results = true; - if (str == "or") - op_type = AST_BIT_OR; - if (str == "nor") - op_type = AST_BIT_OR, invert_results = true; - if (str == "xor") - op_type = AST_BIT_XOR; - if (str == "xnor") - op_type = AST_BIT_XOR, invert_results = true; - if (str == "buf") - op_type = AST_POS; - if (str == "not") - op_type = AST_POS, invert_results = true; - log_assert(op_type != AST_NONE); - - AstNode *node = children_list[1]; - if (op_type != AST_POS) - for (size_t i = 2; i < children_list.size(); i++) - node = new AstNode(op_type, node, children_list[i]); - if (invert_results) - node = new AstNode(AST_BIT_NOT, node); - - str.clear(); - type = AST_ASSIGN; - children.push_back(children_list[0]); - children.back()->was_checked = true; - children.push_back(node); - did_something = true; - } - } - - // replace dynamic ranges in left-hand side expressions (e.g. "foo[bar] <= 1'b1;") with - // a big case block that selects the correct single-bit assignment. - if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) { - if (children[0]->type != AST_IDENTIFIER || children[0]->children.size() == 0) - goto skip_dynamic_range_lvalue_expansion; - if (children[0]->children[0]->range_valid || did_something) - goto skip_dynamic_range_lvalue_expansion; - if (children[0]->id2ast == NULL || children[0]->id2ast->type != AST_WIRE) - goto skip_dynamic_range_lvalue_expansion; - if (!children[0]->id2ast->range_valid) - goto skip_dynamic_range_lvalue_expansion; - int source_width = children[0]->id2ast->range_left - children[0]->id2ast->range_right + 1; - int result_width = 1; - AstNode *shift_expr = NULL; - AstNode *range = children[0]->children[0]; - if (range->children.size() == 1) { - shift_expr = range->children[0]->clone(); - } else { - shift_expr = range->children[1]->clone(); - AstNode *left_at_zero_ast = range->children[0]->clone(); - AstNode *right_at_zero_ast = range->children[1]->clone(); - while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { } - if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); - result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - } - did_something = true; - newNode = new AstNode(AST_CASE, shift_expr); - for (int i = 0; i <= source_width-result_width; i++) { - int start_bit = children[0]->id2ast->range_right + i; - AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); - AstNode *lvalue = children[0]->clone(); - lvalue->delete_children(); - lvalue->children.push_back(new AstNode(AST_RANGE, - mkconst_int(start_bit+result_width-1, true), mkconst_int(start_bit, true))); - cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); - newNode->children.push_back(cond); - } - goto apply_newNode; - } -skip_dynamic_range_lvalue_expansion:; - - if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && current_block != NULL) - { - std::stringstream sstr; - sstr << "$formal$" << filename << ":" << linenum << "$" << (autoidx++); - std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN"; - - AstNode *wire_check = new AstNode(AST_WIRE); - wire_check->str = id_check; - wire_check->was_checked = true; - current_ast_mod->children.push_back(wire_check); - current_scope[wire_check->str] = wire_check; - while (wire_check->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *wire_en = new AstNode(AST_WIRE); - wire_en->str = id_en; - wire_en->was_checked = true; - current_ast_mod->children.push_back(wire_en); - if (current_always_clocked) { - current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))))); - current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en; - current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true; - } - current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - - std::vector x_bit; - x_bit.push_back(RTLIL::State::Sx); - - AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false)); - assign_check->children[0]->str = id_check; - assign_check->children[0]->was_checked = true; - - AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1)); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - - AstNode *default_signals = new AstNode(AST_BLOCK); - default_signals->children.push_back(assign_check); - default_signals->children.push_back(assign_en); - current_top_block->children.insert(current_top_block->children.begin(), default_signals); - - assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); - assign_check->children[0]->str = id_check; - assign_check->children[0]->was_checked = true; - - if (current_always == nullptr || current_always->type != AST_INITIAL) { - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); - } else { - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_FCALL)); - assign_en->children[1]->str = "\\$initstate"; - } - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - - newNode = new AstNode(AST_BLOCK); - newNode->children.push_back(assign_check); - newNode->children.push_back(assign_en); - - AstNode *assertnode = new AstNode(type); - assertnode->str = str; - assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); - assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); - assertnode->children[0]->str = id_check; - assertnode->children[1]->str = id_en; - assertnode->attributes.swap(attributes); - current_ast_mod->children.push_back(assertnode); - - goto apply_newNode; - } - - if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && children.size() == 1) - { - children.push_back(mkconst_int(1, false, 1)); - did_something = true; - } - - // found right-hand side identifier for memory -> replace with memory read port - if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue && - children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) { - newNode = new AstNode(AST_MEMRD, children[0]->children[0]->clone()); - newNode->str = str; - newNode->id2ast = id2ast; - goto apply_newNode; - } - - // assignment with nontrivial member in left-hand concat expression -> split assignment - if ((type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_CONCAT && width_hint > 0) - { - bool found_nontrivial_member = false; - - for (auto child : children[0]->children) { - if (child->type == AST_IDENTIFIER && child->id2ast != NULL && child->id2ast->type == AST_MEMORY) - found_nontrivial_member = true; - } - - if (found_nontrivial_member) - { - newNode = new AstNode(AST_BLOCK); - - AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); - wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), linenum, autoidx++); - current_ast_mod->children.push_back(wire_tmp); - current_scope[wire_tmp->str] = wire_tmp; - wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); - while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } - wire_tmp->is_logic = true; - - AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); - wire_tmp_id->str = wire_tmp->str; - - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone())); - newNode->children.back()->was_checked = true; - - int cursor = 0; - for (auto child : children[0]->children) - { - int child_width_hint = -1; - bool child_sign_hint = true; - child->detectSignWidth(child_width_hint, child_sign_hint); - - AstNode *rhs = wire_tmp_id->clone(); - rhs->children.push_back(new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); - newNode->children.push_back(new AstNode(type, child->clone(), rhs)); - - cursor += child_width_hint; - } - - goto apply_newNode; - } - } - - // assignment with memory in left-hand side expression -> replace with memory write port - if (stage > 1 && (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_IDENTIFIER && - children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 && - children[0]->id2ast->children[0]->range_valid && children[0]->id2ast->children[1]->range_valid && - (children[0]->children.size() == 1 || children[0]->children.size() == 2) && children[0]->children[0]->type == AST_RANGE) - { - std::stringstream sstr; - sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); - std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; - - int mem_width, mem_size, addr_bits; - bool mem_signed = children[0]->id2ast->is_signed; - children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - - int data_range_left = children[0]->id2ast->children[0]->range_left; - int data_range_right = children[0]->id2ast->children[0]->range_right; - int mem_data_range_offset = std::min(data_range_left, data_range_right); - - int addr_width_hint = -1; - bool addr_sign_hint = true; - children[0]->children[0]->children[0]->detectSignWidthWorker(addr_width_hint, addr_sign_hint); - addr_bits = std::max(addr_bits, addr_width_hint); - - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); - wire_addr->str = id_addr; - wire_addr->was_checked = true; - current_ast_mod->children.push_back(wire_addr); - current_scope[wire_addr->str] = wire_addr; - while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); - wire_data->str = id_data; - wire_data->was_checked = true; - wire_data->is_signed = mem_signed; - current_ast_mod->children.push_back(wire_data); - current_scope[wire_data->str] = wire_data; - while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *wire_en = nullptr; - if (current_always->type != AST_INITIAL) { - wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); - wire_en->str = id_en; - wire_en->was_checked = true; - current_ast_mod->children.push_back(wire_en); - current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - } - - std::vector x_bits_addr, x_bits_data, set_bits_en; - for (int i = 0; i < addr_bits; i++) - x_bits_addr.push_back(RTLIL::State::Sx); - for (int i = 0; i < mem_width; i++) - x_bits_data.push_back(RTLIL::State::Sx); - for (int i = 0; i < mem_width; i++) - set_bits_en.push_back(RTLIL::State::S1); - - AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); - assign_addr->children[0]->str = id_addr; - assign_addr->children[0]->was_checked = true; - - AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); - assign_data->children[0]->str = id_data; - assign_data->children[0]->was_checked = true; - - AstNode *assign_en = nullptr; - if (current_always->type != AST_INITIAL) { - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - } - - AstNode *default_signals = new AstNode(AST_BLOCK); - default_signals->children.push_back(assign_addr); - default_signals->children.push_back(assign_data); - if (current_always->type != AST_INITIAL) - default_signals->children.push_back(assign_en); - current_top_block->children.insert(current_top_block->children.begin(), default_signals); - - assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); - assign_addr->children[0]->str = id_addr; - assign_addr->children[0]->was_checked = true; - - if (children[0]->children.size() == 2) - { - if (children[0]->children[1]->range_valid) - { - int offset = children[0]->children[1]->range_right; - int width = children[0]->children[1]->range_left - offset + 1; - offset -= mem_data_range_offset; - - std::vector padding_x(offset, RTLIL::State::Sx); - - assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), - new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); - assign_data->children[0]->str = id_data; - assign_data->children[0]->was_checked = true; - - if (current_always->type != AST_INITIAL) { - for (int i = 0; i < mem_width; i++) - set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - } - } - else - { - AstNode *the_range = children[0]->children[1]; - AstNode *left_at_zero_ast = the_range->children[0]->clone(); - AstNode *right_at_zero_ast = the_range->children.size() >= 2 ? the_range->children[1]->clone() : left_at_zero_ast->clone(); - AstNode *offset_ast = right_at_zero_ast->clone(); - - if (mem_data_range_offset) - offset_ast = new AstNode(AST_SUB, offset_ast, mkconst_int(mem_data_range_offset, true)); - - while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } - if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); - int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - - assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), - new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); - assign_data->children[0]->str = id_data; - assign_data->children[0]->was_checked = true; - - if (current_always->type != AST_INITIAL) { - for (int i = 0; i < mem_width; i++) - set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), - new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - } - - delete left_at_zero_ast; - delete right_at_zero_ast; - delete offset_ast; - } - } - else - { - assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); - assign_data->children[0]->str = id_data; - assign_data->children[0]->was_checked = true; - - if (current_always->type != AST_INITIAL) { - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - } - } - - newNode = new AstNode(AST_BLOCK); - newNode->children.push_back(assign_addr); - newNode->children.push_back(assign_data); - if (current_always->type != AST_INITIAL) - newNode->children.push_back(assign_en); - - AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR); - wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); - wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); - if (current_always->type != AST_INITIAL) - wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); - else - wrnode->children.push_back(AstNode::mkconst_int(1, false)); - wrnode->str = children[0]->str; - wrnode->id2ast = children[0]->id2ast; - wrnode->children[0]->str = id_addr; - wrnode->children[1]->str = id_data; - if (current_always->type != AST_INITIAL) - wrnode->children[2]->str = id_en; - current_ast_mod->children.push_back(wrnode); - - goto apply_newNode; - } - - // replace function and task calls with the code from the function or task - if ((type == AST_FCALL || type == AST_TCALL) && !str.empty()) - { - if (type == AST_FCALL) - { - if (str == "\\$initstate") - { - int myidx = autoidx++; - - AstNode *wire = new AstNode(AST_WIRE); - wire->str = stringf("$initstate$%d_wire", myidx); - current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE), new AstNode(AST_ARGUMENT, new AstNode(AST_IDENTIFIER))); - cell->str = stringf("$initstate$%d", myidx); - cell->children[0]->str = "$initstate"; - cell->children[1]->str = "\\Y"; - cell->children[1]->children[0]->str = wire->str; - cell->children[1]->children[0]->id2ast = wire; - current_ast_mod->children.push_back(cell); - while (cell->simplify(true, false, false, 1, -1, false, false)) { } - - newNode = new AstNode(AST_IDENTIFIER); - newNode->str = wire->str; - newNode->id2ast = wire; - goto apply_newNode; - } - - if (str == "\\$past") - { - if (width_hint < 0) - goto replace_fcall_later; - - int num_steps = 1; - - if (GetSize(children) != 1 && GetSize(children) != 2) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - - if (!current_always_clocked) - log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n", - RTLIL::unescape_id(str).c_str()); - - if (GetSize(children) == 2) - { - AstNode *buf = children[1]->clone(); - while (buf->simplify(true, false, false, stage, -1, false, false)) { } - if (buf->type != AST_CONSTANT) - log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); - - num_steps = buf->asInt(true); - delete buf; - } - - AstNode *block = nullptr; - - for (auto child : current_always->children) - if (child->type == AST_BLOCK) - block = child; - - log_assert(block != nullptr); - - if (num_steps == 0) { - newNode = children[0]->clone(); - goto apply_newNode; - } - - int myidx = autoidx++; - AstNode *outreg = nullptr; - - for (int i = 0; i < num_steps; i++) - { - AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, - mkconst_int(width_hint-1, true), mkconst_int(0, true))); - - reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), linenum, myidx, i); - reg->is_reg = true; - - current_ast_mod->children.push_back(reg); - - while (reg->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *regid = new AstNode(AST_IDENTIFIER); - regid->str = reg->str; - regid->id2ast = reg; - regid->was_checked = true; - - AstNode *rhs = nullptr; - - if (outreg == nullptr) { - rhs = children.at(0)->clone(); - } else { - rhs = new AstNode(AST_IDENTIFIER); - rhs->str = outreg->str; - rhs->id2ast = outreg; - } - - block->children.push_back(new AstNode(AST_ASSIGN_LE, regid, rhs)); - outreg = reg; - } - - newNode = new AstNode(AST_IDENTIFIER); - newNode->str = outreg->str; - newNode->id2ast = outreg; - goto apply_newNode; - } - - if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell" || str == "\\$changed") - { - if (GetSize(children) != 1) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - - if (!current_always_clocked) - log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n", - RTLIL::unescape_id(str).c_str()); - - AstNode *present = children.at(0)->clone(); - AstNode *past = clone(); - past->str = "\\$past"; - - if (str == "\\$stable") - newNode = new AstNode(AST_EQ, past, present); - - else if (str == "\\$changed") - newNode = new AstNode(AST_NE, past, present); - - else if (str == "\\$rose") - newNode = new AstNode(AST_LOGIC_AND, - new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, past, mkconst_int(1,false))), - new AstNode(AST_BIT_AND, present, mkconst_int(1,false))); - - else if (str == "\\$fell") - newNode = new AstNode(AST_LOGIC_AND, - new AstNode(AST_BIT_AND, past, mkconst_int(1,false)), - new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, present, mkconst_int(1,false)))); - - else - log_abort(); - - goto apply_newNode; - } - - // $anyconst and $anyseq are mapped in AstNode::genRTLIL() - if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { - recursion_counter--; - return false; - } - - if (str == "\\$clog2") - { - if (children.size() != 1) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - - AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (buf->type != AST_CONSTANT) - log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); - - RTLIL::Const arg_value = buf->bitsAsConst(); - if (arg_value.as_bool()) - arg_value = const_sub(arg_value, 1, false, false, GetSize(arg_value)); - delete buf; - - uint32_t result = 0; - for (size_t i = 0; i < arg_value.bits.size(); i++) - if (arg_value.bits.at(i) == RTLIL::State::S1) - result = i + 1; - - newNode = mkconst_int(result, true); - goto apply_newNode; - } - - if (str == "\\$size" || str == "\\$bits") - { - if (str == "\\$bits" && children.size() != 1) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - - if (str == "\\$size" && children.size() != 1 && children.size() != 2) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - - int dim = 1; - if (str == "\\$size" && children.size() == 2) { - AstNode *buf = children[1]->clone(); - // Evaluate constant expression - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - dim = buf->asInt(false); - delete buf; - } - AstNode *buf = children[0]->clone(); - int mem_depth = 1; - AstNode *id_ast = NULL; - - // Is this needed? - //while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - buf->detectSignWidth(width_hint, sign_hint); - - if (buf->type == AST_IDENTIFIER) { - id_ast = buf->id2ast; - if (id_ast == NULL && current_scope.count(buf->str)) - id_ast = current_scope.at(buf->str); - if (!id_ast) - log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str()); - if (id_ast->type == AST_MEMORY) { - // We got here only if the argument is a memory - // Otherwise $size() and $bits() return the expression width - AstNode *mem_range = id_ast->children[1]; - if (str == "\\$bits") { - if (mem_range->type == AST_RANGE) { - if (!mem_range->range_valid) - log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); - mem_depth = mem_range->range_left - mem_range->range_right + 1; - } else - log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); - } else { - // $size() - if (mem_range->type == AST_RANGE) { - if (!mem_range->range_valid) - log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); - int dims; - if (id_ast->multirange_dimensions.empty()) - dims = 1; - else - dims = GetSize(id_ast->multirange_dimensions)/2; - if (dim == 1) - width_hint = (dims > 1) ? id_ast->multirange_dimensions[1] : (mem_range->range_left - mem_range->range_right + 1); - else if (dim <= dims) { - width_hint = id_ast->multirange_dimensions[2*dim-1]; - } else if ((dim > dims+1) || (dim < 0)) - log_file_error(filename, linenum, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1); - } else - log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); - } - } - } - delete buf; - - newNode = mkconst_int(width_hint * mem_depth, false); - goto apply_newNode; - } - - if (str == "\\$ln" || str == "\\$log10" || str == "\\$exp" || str == "\\$sqrt" || str == "\\$pow" || - str == "\\$floor" || str == "\\$ceil" || str == "\\$sin" || str == "\\$cos" || str == "\\$tan" || - str == "\\$asin" || str == "\\$acos" || str == "\\$atan" || str == "\\$atan2" || str == "\\$hypot" || - str == "\\$sinh" || str == "\\$cosh" || str == "\\$tanh" || str == "\\$asinh" || str == "\\$acosh" || str == "\\$atanh" || - str == "\\$rtoi" || str == "\\$itor") - { - bool func_with_two_arguments = str == "\\$pow" || str == "\\$atan2" || str == "\\$hypot"; - double x = 0, y = 0; - - if (func_with_two_arguments) { - if (children.size() != 2) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 2.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - } else { - if (children.size() != 1) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - } - - if (children.size() >= 1) { - while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (!children[0]->isConst()) - log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n", - RTLIL::unescape_id(str).c_str()); - int child_width_hint = width_hint; - bool child_sign_hint = sign_hint; - children[0]->detectSignWidth(child_width_hint, child_sign_hint); - x = children[0]->asReal(child_sign_hint); - } - - if (children.size() >= 2) { - while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (!children[1]->isConst()) - log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n", - RTLIL::unescape_id(str).c_str()); - int child_width_hint = width_hint; - bool child_sign_hint = sign_hint; - children[1]->detectSignWidth(child_width_hint, child_sign_hint); - y = children[1]->asReal(child_sign_hint); - } - - if (str == "\\$rtoi") { - newNode = AstNode::mkconst_int(x, true); - } else { - newNode = new AstNode(AST_REALVALUE); - if (str == "\\$ln") newNode->realvalue = ::log(x); - else if (str == "\\$log10") newNode->realvalue = ::log10(x); - else if (str == "\\$exp") newNode->realvalue = ::exp(x); - else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x); - else if (str == "\\$pow") newNode->realvalue = ::pow(x, y); - else if (str == "\\$floor") newNode->realvalue = ::floor(x); - else if (str == "\\$ceil") newNode->realvalue = ::ceil(x); - else if (str == "\\$sin") newNode->realvalue = ::sin(x); - else if (str == "\\$cos") newNode->realvalue = ::cos(x); - else if (str == "\\$tan") newNode->realvalue = ::tan(x); - else if (str == "\\$asin") newNode->realvalue = ::asin(x); - else if (str == "\\$acos") newNode->realvalue = ::acos(x); - else if (str == "\\$atan") newNode->realvalue = ::atan(x); - else if (str == "\\$atan2") newNode->realvalue = ::atan2(x, y); - else if (str == "\\$hypot") newNode->realvalue = ::hypot(x, y); - else if (str == "\\$sinh") newNode->realvalue = ::sinh(x); - else if (str == "\\$cosh") newNode->realvalue = ::cosh(x); - else if (str == "\\$tanh") newNode->realvalue = ::tanh(x); - else if (str == "\\$asinh") newNode->realvalue = ::asinh(x); - else if (str == "\\$acosh") newNode->realvalue = ::acosh(x); - else if (str == "\\$atanh") newNode->realvalue = ::atanh(x); - else if (str == "\\$itor") newNode->realvalue = x; - else log_abort(); - } - goto apply_newNode; - } - - if (current_scope.count(str) != 0 && current_scope[str]->type == AST_DPI_FUNCTION) - { - AstNode *dpi_decl = current_scope[str]; - - std::string rtype, fname; - std::vector argtypes; - std::vector args; - - rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str); - fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str); - - for (int i = 2; i < GetSize(dpi_decl->children); i++) - { - if (i-2 >= GetSize(children)) - log_file_error(filename, linenum, "Insufficient number of arguments in DPI function call.\n"); - - argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); - args.push_back(children.at(i-2)->clone()); - while (args.back()->simplify(true, false, false, stage, -1, false, true)) { } - - if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) - log_file_error(filename, linenum, "Failed to evaluate DPI function with non-constant argument.\n"); - } - - newNode = dpi_call(rtype, fname, argtypes, args); - - for (auto arg : args) - delete arg; - - goto apply_newNode; - } - - if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION) - log_file_error(filename, linenum, "Can't resolve function name `%s'.\n", str.c_str()); - } - - if (type == AST_TCALL) - { - if (str == "$finish" || str == "$stop") - { - if (!current_always || current_always->type != AST_INITIAL) - log_file_error(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str()); - - log_file_error(filename, linenum, "System task `%s' executed.\n", str.c_str()); - } - - if (str == "\\$readmemh" || str == "\\$readmemb") - { - if (GetSize(children) < 2 || GetSize(children) > 4) - log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - - AstNode *node_filename = children[0]->clone(); - while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (node_filename->type != AST_CONSTANT) - log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); - - AstNode *node_memory = children[1]->clone(); - while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) - log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str()); - - int start_addr = -1, finish_addr = -1; - - if (GetSize(children) > 2) { - AstNode *node_addr = children[2]->clone(); - while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (node_addr->type != AST_CONSTANT) - log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str()); - start_addr = int(node_addr->asInt(false)); - } - - if (GetSize(children) > 3) { - AstNode *node_addr = children[3]->clone(); - while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } - if (node_addr->type != AST_CONSTANT) - log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str()); - finish_addr = int(node_addr->asInt(false)); - } - - bool unconditional_init = false; - if (current_always->type == AST_INITIAL) { - pool queue; - log_assert(current_always->children[0]->type == AST_BLOCK); - queue.insert(current_always->children[0]); - while (!unconditional_init && !queue.empty()) { - pool next_queue; - for (auto n : queue) - for (auto c : n->children) { - if (c == this) - unconditional_init = true; - next_queue.insert(c); - } - next_queue.swap(queue); - } - } - - newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); - delete node_filename; - delete node_memory; - goto apply_newNode; - } - - if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK) - log_file_error(filename, linenum, "Can't resolve task name `%s'.\n", str.c_str()); - } - - AstNode *decl = current_scope[str]; - - std::stringstream sstr; - sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++) << "$"; - std::string prefix = sstr.str(); - - bool recommend_const_eval = false; - bool require_const_eval = in_param ? false : has_const_only_constructs(recommend_const_eval); - if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count("\\via_celltype")) - { - bool all_args_const = true; - for (auto child : children) { - while (child->simplify(true, false, false, 1, -1, false, true)) { } - if (child->type != AST_CONSTANT) - all_args_const = false; - } - - if (all_args_const) { - AstNode *func_workspace = current_scope[str]->clone(); - newNode = func_workspace->eval_const_function(this); - delete func_workspace; - goto apply_newNode; - } - - if (in_param) - log_file_error(filename, linenum, "Non-constant function call in constant expression.\n"); - if (require_const_eval) - log_file_error(filename, linenum, "Function %s can only be called with constant arguments.\n", str.c_str()); - } - - size_t arg_count = 0; - std::map replace_rules; - vector added_mod_children; - dict wire_cache; - vector new_stmts; - vector output_assignments; - - if (current_block == NULL) - { - log_assert(type == AST_FCALL); - - AstNode *wire = NULL; - for (auto child : decl->children) - if (child->type == AST_WIRE && child->str == str) - wire = child->clone(); - log_assert(wire != NULL); - - wire->str = prefix + str; - wire->port_id = 0; - wire->is_input = false; - wire->is_output = false; - - current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *lvalue = new AstNode(AST_IDENTIFIER); - lvalue->str = wire->str; - - AstNode *always = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, - new AstNode(AST_ASSIGN_EQ, lvalue, clone()))); - always->children[0]->children[0]->was_checked = true; - - current_ast_mod->children.push_back(always); - - goto replace_fcall_with_id; - } - - if (decl->attributes.count("\\via_celltype")) - { - std::string celltype = decl->attributes.at("\\via_celltype")->asAttrConst().decode_string(); - std::string outport = str; - - if (celltype.find(' ') != std::string::npos) { - int pos = celltype.find(' '); - outport = RTLIL::escape_id(celltype.substr(pos+1)); - celltype = RTLIL::escape_id(celltype.substr(0, pos)); - } else - celltype = RTLIL::escape_id(celltype); - - AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE)); - cell->str = prefix.substr(0, GetSize(prefix)-1); - cell->children[0]->str = celltype; - - for (auto attr : decl->attributes) - if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0) - { - AstNode *cell_arg = new AstNode(AST_PARASET, attr.second->clone()); - cell_arg->str = RTLIL::escape_id(attr.first.str().substr(strlen("\\via_celltype_defparam_"))); - cell->children.push_back(cell_arg); - } - - for (auto child : decl->children) - if (child->type == AST_WIRE && (child->is_input || child->is_output || (type == AST_FCALL && child->str == str))) - { - AstNode *wire = child->clone(); - wire->str = prefix + wire->str; - wire->port_id = 0; - wire->is_input = false; - wire->is_output = false; - current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *wire_id = new AstNode(AST_IDENTIFIER); - wire_id->str = wire->str; - - if ((child->is_input || child->is_output) && arg_count < children.size()) - { - AstNode *arg = children[arg_count++]->clone(); - AstNode *assign = child->is_input ? - new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) : - new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone()); - assign->children[0]->was_checked = true; - - for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) - continue; - current_block->children.insert(it, assign); - break; - } - } - - AstNode *cell_arg = new AstNode(AST_ARGUMENT, wire_id); - cell_arg->str = child->str == str ? outport : child->str; - cell->children.push_back(cell_arg); - } - - current_ast_mod->children.push_back(cell); - goto replace_fcall_with_id; - } - - for (auto child : decl->children) - if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) - { - AstNode *wire = nullptr; - - if (wire_cache.count(child->str)) - { - wire = wire_cache.at(child->str); - if (wire->children.empty()) { - for (auto c : child->children) - wire->children.push_back(c->clone()); - } else if (!child->children.empty()) { - while (child->simplify(true, false, false, stage, -1, false, false)) { } - if (GetSize(child->children) == GetSize(wire->children)) { - for (int i = 0; i < GetSize(child->children); i++) - if (*child->children.at(i) != *wire->children.at(i)) - goto tcall_incompatible_wires; - } else { - tcall_incompatible_wires: - log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", child->str.c_str()); - } - } - } - else - { - wire = child->clone(); - wire->str = prefix + wire->str; - wire->port_id = 0; - wire->is_input = false; - wire->is_output = false; - wire->is_reg = true; - wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); - wire_cache[child->str] = wire; - - current_ast_mod->children.push_back(wire); - added_mod_children.push_back(wire); - } - - if (child->type == AST_WIRE) - while (wire->simplify(true, false, false, 1, -1, false, false)) { } - - replace_rules[child->str] = wire->str; - current_scope[wire->str] = wire; - - if ((child->is_input || child->is_output) && arg_count < children.size()) - { - AstNode *arg = children[arg_count++]->clone(); - AstNode *wire_id = new AstNode(AST_IDENTIFIER); - wire_id->str = wire->str; - AstNode *assign = child->is_input ? - new AstNode(AST_ASSIGN_EQ, wire_id, arg) : - new AstNode(AST_ASSIGN_EQ, arg, wire_id); - assign->children[0]->was_checked = true; - if (child->is_input) - new_stmts.push_back(assign); - else - output_assignments.push_back(assign); - } - } - - for (auto child : added_mod_children) { - child->replace_ids(prefix, replace_rules); - while (child->simplify(true, false, false, 1, -1, false, false)) { } - } - - for (auto child : decl->children) - if (child->type != AST_WIRE && child->type != AST_MEMORY && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM) - { - AstNode *stmt = child->clone(); - stmt->replace_ids(prefix, replace_rules); - new_stmts.push_back(stmt); - } - - new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end()); - - for (auto it = current_block->children.begin(); ; it++) { - log_assert(it != current_block->children.end()); - if (*it == current_block_child) { - current_block->children.insert(it, new_stmts.begin(), new_stmts.end()); - break; - } - } - - replace_fcall_with_id: - if (type == AST_FCALL) { - delete_children(); - type = AST_IDENTIFIER; - str = prefix + str; - } - if (type == AST_TCALL) - str = ""; - did_something = true; - } - -replace_fcall_later:; - - // perform const folding when activated - if (const_fold) - { - bool string_op; - std::vector tmp_bits; - RTLIL::Const (*const_func)(const RTLIL::Const&, const RTLIL::Const&, bool, bool, int); - RTLIL::Const dummy_arg; - - switch (type) - { - case AST_IDENTIFIER: - if (current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM)) { - if (current_scope[str]->children[0]->type == AST_CONSTANT) { - if (children.size() != 0 && children[0]->type == AST_RANGE && children[0]->range_valid) { - std::vector data; - bool param_upto = current_scope[str]->range_valid && current_scope[str]->range_swapped; - int param_offset = current_scope[str]->range_valid ? current_scope[str]->range_right : 0; - int param_width = current_scope[str]->range_valid ? current_scope[str]->range_left - current_scope[str]->range_right + 1 : - GetSize(current_scope[str]->children[0]->bits); - int tmp_range_left = children[0]->range_left, tmp_range_right = children[0]->range_right; - if (param_upto) { - tmp_range_left = (param_width + 2*param_offset) - children[0]->range_right - 1; - tmp_range_right = (param_width + 2*param_offset) - children[0]->range_left - 1; - } - for (int i = tmp_range_right; i <= tmp_range_left; i++) { - int index = i - param_offset; - if (0 <= index && index < param_width) - data.push_back(current_scope[str]->children[0]->bits[index]); - else - data.push_back(RTLIL::State::Sx); - } - newNode = mkconst_bits(data, false); - } else - if (children.size() == 0) - newNode = current_scope[str]->children[0]->clone(); - } else - if (current_scope[str]->children[0]->isConst()) - newNode = current_scope[str]->children[0]->clone(); - } - else if (at_zero && current_scope.count(str) > 0 && (current_scope[str]->type == AST_WIRE || current_scope[str]->type == AST_AUTOWIRE)) { - newNode = mkconst_int(0, sign_hint, width_hint); - } - break; - case AST_BIT_NOT: - if (children[0]->type == AST_CONSTANT) { - RTLIL::Const y = RTLIL::const_not(children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint); - newNode = mkconst_bits(y.bits, sign_hint); - } - break; - case AST_TO_SIGNED: - case AST_TO_UNSIGNED: - if (children[0]->type == AST_CONSTANT) { - RTLIL::Const y = children[0]->bitsAsConst(width_hint, sign_hint); - newNode = mkconst_bits(y.bits, type == AST_TO_SIGNED); - } - break; - if (0) { case AST_BIT_AND: const_func = RTLIL::const_and; } - if (0) { case AST_BIT_OR: const_func = RTLIL::const_or; } - if (0) { case AST_BIT_XOR: const_func = RTLIL::const_xor; } - if (0) { case AST_BIT_XNOR: const_func = RTLIL::const_xnor; } - if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { - RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), - children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.bits, sign_hint); - } - break; - if (0) { case AST_REDUCE_AND: const_func = RTLIL::const_reduce_and; } - if (0) { case AST_REDUCE_OR: const_func = RTLIL::const_reduce_or; } - if (0) { case AST_REDUCE_XOR: const_func = RTLIL::const_reduce_xor; } - if (0) { case AST_REDUCE_XNOR: const_func = RTLIL::const_reduce_xnor; } - if (0) { case AST_REDUCE_BOOL: const_func = RTLIL::const_reduce_bool; } - if (children[0]->type == AST_CONSTANT) { - RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), dummy_arg, false, false, -1); - newNode = mkconst_bits(y.bits, false); - } - break; - case AST_LOGIC_NOT: - if (children[0]->type == AST_CONSTANT) { - RTLIL::Const y = RTLIL::const_logic_not(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1); - newNode = mkconst_bits(y.bits, false); - } else - if (children[0]->isConst()) { - newNode = mkconst_int(children[0]->asReal(sign_hint) == 0, false, 1); - } - break; - if (0) { case AST_LOGIC_AND: const_func = RTLIL::const_logic_and; } - if (0) { case AST_LOGIC_OR: const_func = RTLIL::const_logic_or; } - if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { - RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), RTLIL::Const(children[1]->bits), - children[0]->is_signed, children[1]->is_signed, -1); - newNode = mkconst_bits(y.bits, false); - } else - if (children[0]->isConst() && children[1]->isConst()) { - if (type == AST_LOGIC_AND) - newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) && (children[1]->asReal(sign_hint) != 0), false, 1); - else - newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) || (children[1]->asReal(sign_hint) != 0), false, 1); - } - break; - if (0) { case AST_SHIFT_LEFT: const_func = RTLIL::const_shl; } - if (0) { case AST_SHIFT_RIGHT: const_func = RTLIL::const_shr; } - if (0) { case AST_SHIFT_SLEFT: const_func = RTLIL::const_sshl; } - if (0) { case AST_SHIFT_SRIGHT: const_func = RTLIL::const_sshr; } - if (0) { case AST_POW: const_func = RTLIL::const_pow; } - if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { - RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), - RTLIL::Const(children[1]->bits), sign_hint, type == AST_POW ? children[1]->is_signed : false, width_hint); - newNode = mkconst_bits(y.bits, sign_hint); - } else - if (type == AST_POW && children[0]->isConst() && children[1]->isConst()) { - newNode = new AstNode(AST_REALVALUE); - newNode->realvalue = pow(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); - } - break; - if (0) { case AST_LT: const_func = RTLIL::const_lt; } - if (0) { case AST_LE: const_func = RTLIL::const_le; } - if (0) { case AST_EQ: const_func = RTLIL::const_eq; } - if (0) { case AST_NE: const_func = RTLIL::const_ne; } - if (0) { case AST_EQX: const_func = RTLIL::const_eqx; } - if (0) { case AST_NEX: const_func = RTLIL::const_nex; } - if (0) { case AST_GE: const_func = RTLIL::const_ge; } - if (0) { case AST_GT: const_func = RTLIL::const_gt; } - if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { - int cmp_width = max(children[0]->bits.size(), children[1]->bits.size()); - bool cmp_signed = children[0]->is_signed && children[1]->is_signed; - RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed), - children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1); - newNode = mkconst_bits(y.bits, false); - } else - if (children[0]->isConst() && children[1]->isConst()) { - bool cmp_signed = (children[0]->type == AST_REALVALUE || children[0]->is_signed) && (children[1]->type == AST_REALVALUE || children[1]->is_signed); - switch (type) { - case AST_LT: newNode = mkconst_int(children[0]->asReal(cmp_signed) < children[1]->asReal(cmp_signed), false, 1); break; - case AST_LE: newNode = mkconst_int(children[0]->asReal(cmp_signed) <= children[1]->asReal(cmp_signed), false, 1); break; - case AST_EQ: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; - case AST_NE: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; - case AST_EQX: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; - case AST_NEX: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; - case AST_GE: newNode = mkconst_int(children[0]->asReal(cmp_signed) >= children[1]->asReal(cmp_signed), false, 1); break; - case AST_GT: newNode = mkconst_int(children[0]->asReal(cmp_signed) > children[1]->asReal(cmp_signed), false, 1); break; - default: log_abort(); - } - } - break; - if (0) { case AST_ADD: const_func = RTLIL::const_add; } - if (0) { case AST_SUB: const_func = RTLIL::const_sub; } - if (0) { case AST_MUL: const_func = RTLIL::const_mul; } - if (0) { case AST_DIV: const_func = RTLIL::const_div; } - if (0) { case AST_MOD: const_func = RTLIL::const_mod; } - if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { - RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), - children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.bits, sign_hint); - } else - if (children[0]->isConst() && children[1]->isConst()) { - newNode = new AstNode(AST_REALVALUE); - switch (type) { - case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; - case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; - case AST_MUL: newNode->realvalue = children[0]->asReal(sign_hint) * children[1]->asReal(sign_hint); break; - case AST_DIV: newNode->realvalue = children[0]->asReal(sign_hint) / children[1]->asReal(sign_hint); break; - case AST_MOD: newNode->realvalue = fmod(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); break; - default: log_abort(); - } - } - break; - if (0) { case AST_POS: const_func = RTLIL::const_pos; } - if (0) { case AST_NEG: const_func = RTLIL::const_neg; } - if (children[0]->type == AST_CONSTANT) { - RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint); - newNode = mkconst_bits(y.bits, sign_hint); - } else - if (children[0]->isConst()) { - newNode = new AstNode(AST_REALVALUE); - if (type == AST_POS) - newNode->realvalue = +children[0]->asReal(sign_hint); - else - newNode->realvalue = -children[0]->asReal(sign_hint); - } - break; - case AST_TERNARY: - if (children[0]->isConst()) - { - bool found_sure_true = false; - bool found_maybe_true = false; - - if (children[0]->type == AST_CONSTANT) - for (auto &bit : children[0]->bits) { - if (bit == RTLIL::State::S1) - found_sure_true = true; - if (bit > RTLIL::State::S1) - found_maybe_true = true; - } - else - found_sure_true = children[0]->asReal(sign_hint) != 0; - - AstNode *choice = NULL, *not_choice = NULL; - if (found_sure_true) - choice = children[1], not_choice = children[2]; - else if (!found_maybe_true) - choice = children[2], not_choice = children[1]; - - if (choice != NULL) { - if (choice->type == AST_CONSTANT) { - int other_width_hint = width_hint; - bool other_sign_hint = sign_hint, other_real = false; - not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real); - if (other_real) { - newNode = new AstNode(AST_REALVALUE); - choice->detectSignWidth(width_hint, sign_hint); - newNode->realvalue = choice->asReal(sign_hint); - } else { - RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint); - if (choice->is_string && y.bits.size() % 8 == 0 && sign_hint == false) - newNode = mkconst_str(y.bits); - else - newNode = mkconst_bits(y.bits, sign_hint); - } - } else - if (choice->isConst()) { - newNode = choice->clone(); - } - } else if (children[1]->type == AST_CONSTANT && children[2]->type == AST_CONSTANT) { - RTLIL::Const a = children[1]->bitsAsConst(width_hint, sign_hint); - RTLIL::Const b = children[2]->bitsAsConst(width_hint, sign_hint); - log_assert(a.bits.size() == b.bits.size()); - for (size_t i = 0; i < a.bits.size(); i++) - if (a.bits[i] != b.bits[i]) - a.bits[i] = RTLIL::State::Sx; - newNode = mkconst_bits(a.bits, sign_hint); - } else if (children[1]->isConst() && children[2]->isConst()) { - newNode = new AstNode(AST_REALVALUE); - if (children[1]->asReal(sign_hint) == children[2]->asReal(sign_hint)) - newNode->realvalue = children[1]->asReal(sign_hint); - else - // IEEE Std 1800-2012 Sec. 11.4.11 states that the entry in Table 7-1 for - // the data type in question should be returned if the ?: is ambiguous. The - // value in Table 7-1 for the 'real' type is 0.0. - newNode->realvalue = 0.0; - } - } - break; - case AST_CONCAT: - string_op = !children.empty(); - for (auto it = children.begin(); it != children.end(); it++) { - if ((*it)->type != AST_CONSTANT) - goto not_const; - if (!(*it)->is_string) - string_op = false; - tmp_bits.insert(tmp_bits.end(), (*it)->bits.begin(), (*it)->bits.end()); - } - newNode = string_op ? mkconst_str(tmp_bits) : mkconst_bits(tmp_bits, false); - break; - case AST_REPLICATE: - if (children.at(0)->type != AST_CONSTANT || children.at(1)->type != AST_CONSTANT) - goto not_const; - for (int i = 0; i < children[0]->bitsAsConst().as_int(); i++) - tmp_bits.insert(tmp_bits.end(), children.at(1)->bits.begin(), children.at(1)->bits.end()); - newNode = children.at(1)->is_string ? mkconst_str(tmp_bits) : mkconst_bits(tmp_bits, false); - break; - default: - not_const: - break; - } - } - - // if any of the above set 'newNode' -> use 'newNode' as template to update 'this' - if (newNode) { -apply_newNode: - // fprintf(stderr, "----\n"); - // dumpAst(stderr, "- "); - // newNode->dumpAst(stderr, "+ "); - log_assert(newNode != NULL); - newNode->filename = filename; - newNode->linenum = linenum; - newNode->cloneInto(this); - delete newNode; - did_something = true; - } - - if (!did_something) - basic_prep = true; - - recursion_counter--; - return did_something; -} - -static void replace_result_wire_name_in_function(AstNode *node, std::string &from, std::string &to) -{ - for (auto &it : node->children) - replace_result_wire_name_in_function(it, from, to); - if (node->str == from) - node->str = to; -} - -// replace a readmem[bh] TCALL ast node with a block of memory assignments -AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init) -{ - int mem_width, mem_size, addr_bits; - memory->meminfo(mem_width, mem_size, addr_bits); - - AstNode *block = new AstNode(AST_BLOCK); - - AstNode *meminit = nullptr; - int next_meminit_cursor=0; - vector meminit_bits; - int meminit_size=0; - - std::ifstream f; - f.open(mem_filename.c_str()); - yosys_input_files.insert(mem_filename); - - if (f.fail()) - log_file_error(filename, linenum, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str()); - - log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid); - int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right; - int range_min = min(range_left, range_right), range_max = max(range_left, range_right); - - if (start_addr < 0) - start_addr = range_min; - - if (finish_addr < 0) - finish_addr = range_max + 1; - - bool in_comment = false; - int increment = start_addr <= finish_addr ? +1 : -1; - int cursor = start_addr; - - while (!f.eof()) - { - std::string line, token; - std::getline(f, line); - - for (int i = 0; i < GetSize(line); i++) { - if (in_comment && line.substr(i, 2) == "*/") { - line[i] = ' '; - line[i+1] = ' '; - in_comment = false; - continue; - } - if (!in_comment && line.substr(i, 2) == "/*") - in_comment = true; - if (in_comment) - line[i] = ' '; - } - - while (1) - { - token = next_token(line, " \t\r\n"); - if (token.empty() || token.substr(0, 2) == "//") - break; - - if (token[0] == '@') { - token = token.substr(1); - const char *nptr = token.c_str(); - char *endptr; - cursor = strtol(nptr, &endptr, 16); - if (!*nptr || *endptr) - log_file_error(filename, linenum, "Can not parse address `%s` for %s.\n", nptr, str.c_str()); - continue; - } - - AstNode *value = VERILOG_FRONTEND::const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); - - if (unconditional_init) - { - if (meminit == nullptr || cursor != next_meminit_cursor) - { - if (meminit != nullptr) { - meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); - meminit->children[2] = AstNode::mkconst_int(meminit_size, false); - } - - meminit = new AstNode(AST_MEMINIT); - meminit->children.push_back(AstNode::mkconst_int(cursor, false)); - meminit->children.push_back(nullptr); - meminit->children.push_back(nullptr); - meminit->str = memory->str; - meminit->id2ast = memory; - meminit_bits.clear(); - meminit_size = 0; - - current_ast_mod->children.push_back(meminit); - next_meminit_cursor = cursor; - } - - meminit_size++; - next_meminit_cursor++; - meminit_bits.insert(meminit_bits.end(), value->bits.begin(), value->bits.end()); - delete value; - } - else - { - block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); - block->children.back()->children[0]->str = memory->str; - block->children.back()->children[0]->id2ast = memory; - block->children.back()->children[0]->was_checked = true; - } - - cursor += increment; - if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) - break; - } - - if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) - break; - } - - if (meminit != nullptr) { - meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); - meminit->children[2] = AstNode::mkconst_int(meminit_size, false); - } - - return block; -} - -// annotate the names of all wires and other named objects in a generate block -void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map &name_map) -{ - if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) { - current_scope[index_var]->children[0]->cloneInto(this); - return; - } - - if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0) - str = name_map[str]; - - std::map backup_name_map; - - for (size_t i = 0; i < children.size(); i++) { - AstNode *child = children[i]; - if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || - child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL) { - if (backup_name_map.size() == 0) - backup_name_map = name_map; - std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix; - size_t pos = child->str.rfind('.'); - if (pos == std::string::npos) - pos = child->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0; - else - pos = pos + 1; - new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos); - if (new_name[0] != '$' && new_name[0] != '\\') - new_name = prefix[0] + new_name; - name_map[child->str] = new_name; - if (child->type == AST_FUNCTION) - replace_result_wire_name_in_function(child, child->str, new_name); - else - child->str = new_name; - current_scope[new_name] = child; - } - } - - for (size_t i = 0; i < children.size(); i++) { - AstNode *child = children[i]; - // AST_PREFIX member names should not be prefixed; a nested AST_PREFIX - // still needs to recursed-into - if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER) - continue; - if (child->type != AST_FUNCTION && child->type != AST_TASK) - child->expand_genblock(index_var, prefix, name_map); - } - - if (backup_name_map.size() > 0) - name_map.swap(backup_name_map); -} - -// rename stuff (used when tasks of functions are instantiated) -void AstNode::replace_ids(const std::string &prefix, const std::map &rules) -{ - if (type == AST_BLOCK) - { - std::map new_rules = rules; - std::string new_prefix = prefix + str; - - for (auto child : children) - if (child->type == AST_WIRE) { - new_rules[child->str] = new_prefix + child->str; - child->str = new_prefix + child->str; - } - - for (auto child : children) - if (child->type != AST_WIRE) - child->replace_ids(new_prefix, new_rules); - } - else - { - if (type == AST_IDENTIFIER && rules.count(str) > 0) - str = rules.at(str); - for (auto child : children) - child->replace_ids(prefix, rules); - } -} - -// helper function for mem2reg_as_needed_pass1 -static void mark_memories_assign_lhs_complex(dict> &mem2reg_places, - dict &mem2reg_candidates, AstNode *that) -{ - for (auto &child : that->children) - mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child); - - if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { - AstNode *mem = that->id2ast; - if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) - mem2reg_places[mem].insert(stringf("%s:%d", that->filename.c_str(), that->linenum)); - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS; - } -} - -// find memories that should be replaced by registers -void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg_places, - dict &mem2reg_candidates, dict &proc_flags, uint32_t &flags) -{ - uint32_t children_flags = 0; - int lhs_children_counter = 0; - - if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) - { - // mark all memories that are used in a complex expression on the left side of an assignment - for (auto &lhs_child : children[0]->children) - mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, lhs_child); - - if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY) - { - AstNode *mem = children[0]->id2ast; - - // activate mem2reg if this is assigned in an async proc - if (flags & AstNode::MEM2REG_FL_ASYNC) { - if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC)) - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC; - } - - // remember if this is assigned blocking (=) - if (type == AST_ASSIGN_EQ) { - if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1)) - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); - proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; - } - - // for proper (non-init) writes: remember if this is a constant index or not - if ((flags & MEM2REG_FL_INIT) == 0) { - if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) { - if (children[0]->children[0]->children[0]->type == AST_CONSTANT) - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS; - else - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS; - } - } - - // remember where this is - if (flags & MEM2REG_FL_INIT) { - if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT; - } else { - if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE)) - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE; - } - } - - lhs_children_counter = 1; - } - - if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY) - { - AstNode *mem = id2ast; - - // flag if used after blocking assignment (in same proc) - if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) { - mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2; - } - } - - // also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg' - if (type == AST_MEMORY && (get_bool_attribute("\\mem2reg") || (flags & AstNode::MEM2REG_FL_ALL) || !is_reg)) - mem2reg_candidates[this] |= AstNode::MEM2REG_FL_FORCED; - - if (type == AST_MODULE && get_bool_attribute("\\mem2reg")) - children_flags |= AstNode::MEM2REG_FL_ALL; - - dict *proc_flags_p = NULL; - - if (type == AST_ALWAYS) { - int count_edge_events = 0; - for (auto child : children) - if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) - count_edge_events++; - if (count_edge_events != 1) - children_flags |= AstNode::MEM2REG_FL_ASYNC; - proc_flags_p = new dict; - } - - if (type == AST_INITIAL) { - children_flags |= AstNode::MEM2REG_FL_INIT; - proc_flags_p = new dict; - } - - uint32_t backup_flags = flags; - flags |= children_flags; - log_assert((flags & ~0x000000ff) == 0); - - for (auto child : children) - { - if (lhs_children_counter > 0) { - lhs_children_counter--; - if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) { - for (auto c : child->children[0]->children) { - if (proc_flags_p) - c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); - else - c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags); - } - } - } else - if (proc_flags_p) - child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); - else - child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags); - } - - flags &= ~children_flags | backup_flags; - - if (proc_flags_p) { -#ifndef NDEBUG - for (auto it : *proc_flags_p) - log_assert((it.second & ~0xff000000) == 0); -#endif - delete proc_flags_p; - } -} - -bool AstNode::mem2reg_check(pool &mem2reg_set) -{ - if (type != AST_IDENTIFIER || !id2ast || !mem2reg_set.count(id2ast)) - return false; - - if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1) - log_file_error(filename, linenum, "Invalid array access.\n"); - - return true; -} - -void AstNode::mem2reg_remove(pool &mem2reg_set, vector &delnodes) -{ - log_assert(mem2reg_set.count(this) == 0); - - if (mem2reg_set.count(id2ast)) - id2ast = nullptr; - - for (size_t i = 0; i < children.size(); i++) { - if (mem2reg_set.count(children[i]) > 0) { - delnodes.push_back(children[i]); - children.erase(children.begin() + (i--)); - } else { - children[i]->mem2reg_remove(mem2reg_set, delnodes); - } - } -} - -// actually replace memories with registers -bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block) -{ - bool did_something = false; - - if (type == AST_BLOCK) - block = this; - - if (type == AST_FUNCTION || type == AST_TASK) - return false; - - if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast)) - { - log_assert(children[0]->type == AST_CONSTANT); - log_assert(children[1]->type == AST_CONSTANT); - log_assert(children[2]->type == AST_CONSTANT); - - int cursor = children[0]->asInt(false); - Const data = children[1]->bitsAsConst(); - int length = children[2]->asInt(false); - - if (length != 0) - { - AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK)); - mod->children.push_back(block); - block = block->children[0]; - - int wordsz = GetSize(data) / length; - - for (int i = 0; i < length; i++) { - block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false))); - block->children.back()->children[0]->str = str; - block->children.back()->children[0]->id2ast = id2ast; - block->children.back()->children[0]->was_checked = true; - } - } - - AstNode *newNode = new AstNode(AST_NONE); - newNode->cloneInto(this); - delete newNode; - - did_something = true; - } - - if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) - { - if (async_block == NULL) { - async_block = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - mod->children.push_back(async_block); - } - - AstNode *newNode = clone(); - newNode->type = AST_ASSIGN_EQ; - newNode->children[0]->was_checked = true; - async_block->children[0]->children.push_back(newNode); - - newNode = new AstNode(AST_NONE); - newNode->cloneInto(this); - delete newNode; - - did_something = true; - } - - if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->mem2reg_check(mem2reg_set) && - children[0]->children[0]->children[0]->type != AST_CONSTANT) - { - std::stringstream sstr; - sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); - std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; - - int mem_width, mem_size, addr_bits; - bool mem_signed = children[0]->id2ast->is_signed; - children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); - wire_addr->str = id_addr; - wire_addr->is_reg = true; - wire_addr->was_checked = true; - wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); - mod->children.push_back(wire_addr); - while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); - wire_data->str = id_data; - wire_data->is_reg = true; - wire_data->was_checked = true; - wire_data->is_signed = mem_signed; - wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); - mod->children.push_back(wire_data); - while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } - - log_assert(block != NULL); - size_t assign_idx = 0; - while (assign_idx < block->children.size() && block->children[assign_idx] != this) - assign_idx++; - log_assert(assign_idx < block->children.size()); - - AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); - assign_addr->children[0]->str = id_addr; - assign_addr->children[0]->was_checked = true; - block->children.insert(block->children.begin()+assign_idx+1, assign_addr); - - AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); - case_node->children[0]->str = id_addr; - for (int i = 0; i < mem_size; i++) { - if (children[0]->children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->children[0]->integer) != i) - continue; - AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(type, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); - if (children[0]->children.size() == 2) - assign_reg->children[0]->children.push_back(children[0]->children[1]->clone()); - assign_reg->children[0]->str = stringf("%s[%d]", children[0]->str.c_str(), i); - assign_reg->children[1]->str = id_data; - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); - } - block->children.insert(block->children.begin()+assign_idx+2, case_node); - - children[0]->delete_children(); - children[0]->range_valid = false; - children[0]->id2ast = NULL; - children[0]->str = id_data; - type = AST_ASSIGN_EQ; - children[0]->was_checked = true; - - did_something = true; - } - - if (mem2reg_check(mem2reg_set)) - { - AstNode *bit_part_sel = NULL; - if (children.size() == 2) - bit_part_sel = children[1]->clone(); - - if (children[0]->children[0]->type == AST_CONSTANT) - { - int id = children[0]->children[0]->integer; - str = stringf("%s[%d]", str.c_str(), id); - - delete_children(); - range_valid = false; - id2ast = NULL; - } - else - { - std::stringstream sstr; - sstr << "$mem2reg_rd$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); - std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; - - int mem_width, mem_size, addr_bits; - bool mem_signed = id2ast->is_signed; - id2ast->meminfo(mem_width, mem_size, addr_bits); - - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); - wire_addr->str = id_addr; - wire_addr->is_reg = true; - wire_addr->was_checked = true; - if (block) - wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); - mod->children.push_back(wire_addr); - while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); - wire_data->str = id_data; - wire_data->is_reg = true; - wire_data->was_checked = true; - wire_data->is_signed = mem_signed; - if (block) - wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); - mod->children.push_back(wire_data); - while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); - assign_addr->children[0]->str = id_addr; - assign_addr->children[0]->was_checked = true; - - AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); - case_node->children[0]->str = id_addr; - - for (int i = 0; i < mem_size; i++) { - if (children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->integer) != i) - continue; - AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); - assign_reg->children[0]->str = id_data; - assign_reg->children[0]->was_checked = true; - assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i); - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); - } - - std::vector x_bits; - for (int i = 0; i < mem_width; i++) - x_bits.push_back(RTLIL::State::Sx); - - AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); - assign_reg->children[0]->str = id_data; - assign_reg->children[0]->was_checked = true; - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); - - if (block) - { - size_t assign_idx = 0; - while (assign_idx < block->children.size() && !block->children[assign_idx]->contains(this)) - assign_idx++; - log_assert(assign_idx < block->children.size()); - block->children.insert(block->children.begin()+assign_idx, case_node); - block->children.insert(block->children.begin()+assign_idx, assign_addr); - } - else - { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - proc->children[0]->children.push_back(case_node); - mod->children.push_back(proc); - mod->children.push_back(assign_addr); - } - - delete_children(); - range_valid = false; - id2ast = NULL; - str = id_data; - } - - if (bit_part_sel) - children.push_back(bit_part_sel); - - did_something = true; - } - - log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0); - - auto children_list = children; - for (size_t i = 0; i < children_list.size(); i++) - if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block, async_block)) - did_something = true; - - return did_something; -} - -// calculate memory dimensions -void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits) -{ - log_assert(type == AST_MEMORY); - - mem_width = children[0]->range_left - children[0]->range_right + 1; - mem_size = children[1]->range_left - children[1]->range_right; - - if (mem_size < 0) - mem_size *= -1; - mem_size += min(children[1]->range_left, children[1]->range_right) + 1; - - addr_bits = 1; - while ((1 << addr_bits) < mem_size) - addr_bits++; -} - -bool AstNode::has_const_only_constructs(bool &recommend_const_eval) -{ - if (type == AST_FOR) - recommend_const_eval = true; - if (type == AST_WHILE || type == AST_REPEAT) - return true; - if (type == AST_FCALL && current_scope.count(str)) - if (current_scope[str]->has_const_only_constructs(recommend_const_eval)) - return true; - for (auto child : children) - if (child->AstNode::has_const_only_constructs(recommend_const_eval)) - return true; - return false; -} - -bool AstNode::is_simple_const_expr() -{ - if (type == AST_IDENTIFIER) - return false; - for (auto child : children) - if (!child->is_simple_const_expr()) - return false; - return true; -} - -// helper function for AstNode::eval_const_function() -void AstNode::replace_variables(std::map &variables, AstNode *fcall) -{ - if (type == AST_IDENTIFIER && variables.count(str)) { - int offset = variables.at(str).offset, width = variables.at(str).val.bits.size(); - if (!children.empty()) { - if (children.size() != 1 || children.at(0)->type != AST_RANGE) - log_file_error(filename, linenum, "Memory access in constant function is not supported\n%s:%d: ...called from here.\n", - fcall->filename.c_str(), fcall->linenum); - children.at(0)->replace_variables(variables, fcall); - while (simplify(true, false, false, 1, -1, false, true)) { } - if (!children.at(0)->range_valid) - log_file_error(filename, linenum, "Non-constant range\n%s:%d: ... called from here.\n", - fcall->filename.c_str(), fcall->linenum); - offset = min(children.at(0)->range_left, children.at(0)->range_right); - width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width); - } - offset -= variables.at(str).offset; - std::vector &var_bits = variables.at(str).val.bits; - std::vector new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width); - AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed); - newNode->cloneInto(this); - delete newNode; - return; - } - - for (auto &child : children) - child->replace_variables(variables, fcall); -} - -// evaluate functions with all-const arguments -AstNode *AstNode::eval_const_function(AstNode *fcall) -{ - std::map backup_scope; - std::map variables; - bool delete_temp_block = false; - AstNode *block = NULL; - - size_t argidx = 0; - for (auto child : children) - { - if (child->type == AST_BLOCK) - { - log_assert(block == NULL); - block = child; - continue; - } - - if (child->type == AST_WIRE) - { - while (child->simplify(true, false, false, 1, -1, false, true)) { } - if (!child->range_valid) - log_file_error(child->filename, child->linenum, "Can't determine size of variable %s\n%s:%d: ... called from here.\n", - child->str.c_str(), fcall->filename.c_str(), fcall->linenum); - variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1); - variables[child->str].offset = min(child->range_left, child->range_right); - variables[child->str].is_signed = child->is_signed; - if (child->is_input && argidx < fcall->children.size()) - variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size()); - backup_scope[child->str] = current_scope[child->str]; - current_scope[child->str] = child; - continue; - } - - log_assert(block == NULL); - delete_temp_block = true; - block = new AstNode(AST_BLOCK); - block->children.push_back(child->clone()); - } - - log_assert(block != NULL); - log_assert(variables.count(str) != 0); - - while (!block->children.empty()) - { - AstNode *stmt = block->children.front(); - -#if 0 - log("-----------------------------------\n"); - for (auto &it : variables) - log("%20s %40s\n", it.first.c_str(), log_signal(it.second.val)); - stmt->dumpAst(NULL, "stmt> "); -#endif - - if (stmt->type == AST_ASSIGN_EQ) - { - if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 && - stmt->children.at(0)->children.at(0)->type == AST_RANGE) - stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall); - stmt->children.at(1)->replace_variables(variables, fcall); - while (stmt->simplify(true, false, false, 1, -1, false, true)) { } - - if (stmt->type != AST_ASSIGN_EQ) - continue; - - if (stmt->children.at(1)->type != AST_CONSTANT) - log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here. X\n", - fcall->filename.c_str(), fcall->linenum); - - if (stmt->children.at(0)->type != AST_IDENTIFIER) - log_file_error(stmt->filename, stmt->linenum, "Unsupported composite left hand side in constant function\n%s:%d: ... called from here.\n", - fcall->filename.c_str(), fcall->linenum); - - if (!variables.count(stmt->children.at(0)->str)) - log_file_error(stmt->filename, stmt->linenum, "Assignment to non-local variable in constant function\n%s:%d: ... called from here.\n", - fcall->filename.c_str(), fcall->linenum); - - if (stmt->children.at(0)->children.empty()) { - variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size()); - } else { - AstNode *range = stmt->children.at(0)->children.at(0); - if (!range->range_valid) - log_file_error(range->filename, range->linenum, "Non-constant range\n%s:%d: ... called from here.\n", - fcall->filename.c_str(), fcall->linenum); - int offset = min(range->range_left, range->range_right); - int width = std::abs(range->range_left - range->range_right) + 1; - varinfo_t &v = variables[stmt->children.at(0)->str]; - RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size()); - for (int i = 0; i < width; i++) - v.val.bits.at(i+offset-v.offset) = r.bits.at(i); - } - - delete block->children.front(); - block->children.erase(block->children.begin()); - continue; - } - - if (stmt->type == AST_FOR) - { - block->children.insert(block->children.begin(), stmt->children.at(0)); - stmt->children.at(3)->children.push_back(stmt->children.at(2)); - stmt->children.erase(stmt->children.begin() + 2); - stmt->children.erase(stmt->children.begin()); - stmt->type = AST_WHILE; - continue; - } - - if (stmt->type == AST_WHILE) - { - AstNode *cond = stmt->children.at(0)->clone(); - cond->replace_variables(variables, fcall); - while (cond->simplify(true, false, false, 1, -1, false, true)) { } - - if (cond->type != AST_CONSTANT) - log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", - fcall->filename.c_str(), fcall->linenum); - - if (cond->asBool()) { - block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); - } else { - delete block->children.front(); - block->children.erase(block->children.begin()); - } - - delete cond; - continue; - } - - if (stmt->type == AST_REPEAT) - { - AstNode *num = stmt->children.at(0)->clone(); - num->replace_variables(variables, fcall); - while (num->simplify(true, false, false, 1, -1, false, true)) { } - - if (num->type != AST_CONSTANT) - log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", - fcall->filename.c_str(), fcall->linenum); - - block->children.erase(block->children.begin()); - for (int i = 0; i < num->bitsAsConst().as_int(); i++) - block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); - - delete stmt; - delete num; - continue; - } - - if (stmt->type == AST_CASE) - { - AstNode *expr = stmt->children.at(0)->clone(); - expr->replace_variables(variables, fcall); - while (expr->simplify(true, false, false, 1, -1, false, true)) { } - - AstNode *sel_case = NULL; - for (size_t i = 1; i < stmt->children.size(); i++) - { - bool found_match = false; - log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ); - - if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) { - sel_case = stmt->children.at(i)->children.back(); - continue; - } - - for (size_t j = 0; j+1 < stmt->children.at(i)->children.size() && !found_match; j++) - { - AstNode *cond = stmt->children.at(i)->children.at(j)->clone(); - cond->replace_variables(variables, fcall); - - cond = new AstNode(AST_EQ, expr->clone(), cond); - while (cond->simplify(true, false, false, 1, -1, false, true)) { } - - if (cond->type != AST_CONSTANT) - log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", - fcall->filename.c_str(), fcall->linenum); - - found_match = cond->asBool(); - delete cond; - } - - if (found_match) { - sel_case = stmt->children.at(i)->children.back(); - break; - } - } - - block->children.erase(block->children.begin()); - if (sel_case) - block->children.insert(block->children.begin(), sel_case->clone()); - delete stmt; - delete expr; - continue; - } - - if (stmt->type == AST_BLOCK) - { - block->children.erase(block->children.begin()); - block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); - stmt->children.clear(); - delete stmt; - continue; - } - - log_file_error(stmt->filename, stmt->linenum, "Unsupported language construct in constant function\n%s:%d: ... called from here.\n", - fcall->filename.c_str(), fcall->linenum); - log_abort(); - } - - if (delete_temp_block) - delete block; - - for (auto &it : backup_scope) - if (it.second == NULL) - current_scope.erase(it.first); - else - current_scope[it.first] = it.second; - - return AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed); -} - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/blif/Makefile.inc b/yosys/frontends/blif/Makefile.inc deleted file mode 100644 index 9729184eb..000000000 --- a/yosys/frontends/blif/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += frontends/blif/blifparse.o - diff --git a/yosys/frontends/blif/blifparse.cc b/yosys/frontends/blif/blifparse.cc deleted file mode 100644 index a6a07863f..000000000 --- a/yosys/frontends/blif/blifparse.cc +++ /dev/null @@ -1,626 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "blifparse.h" - -YOSYS_NAMESPACE_BEGIN - -static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, std::istream &f) -{ - string strbuf; - int buffer_len = 0; - buffer[0] = 0; - - while (1) - { - buffer_len += strlen(buffer + buffer_len); - while (buffer_len > 0 && (buffer[buffer_len-1] == ' ' || buffer[buffer_len-1] == '\t' || - buffer[buffer_len-1] == '\r' || buffer[buffer_len-1] == '\n')) - buffer[--buffer_len] = 0; - - if (buffer_size-buffer_len < 4096) { - buffer_size *= 2; - buffer = (char*)realloc(buffer, buffer_size); - } - - if (buffer_len == 0 || buffer[buffer_len-1] == '\\') { - if (buffer_len > 0 && buffer[buffer_len-1] == '\\') - buffer[--buffer_len] = 0; - line_count++; - if (!std::getline(f, strbuf)) - return false; - while (buffer_size-buffer_len < strbuf.size()+1) { - buffer_size *= 2; - buffer = (char*)realloc(buffer, buffer_size); - } - strcpy(buffer+buffer_len, strbuf.c_str()); - } else - return true; - } -} - -static std::pair wideports_split(std::string name) -{ - int pos = -1; - - if (name.empty() || name.back() != ']') - goto failed; - - for (int i = 0; i+1 < GetSize(name); i++) { - if (name[i] == '[') - pos = i; - else if (name[i] < '0' || name[i] > '9') - pos = -1; - else if (i == pos+1 && name[i] == '0' && name[i+1] != ']') - pos = -1; - } - - if (pos >= 0) - return std::pair("\\" + name.substr(0, pos), atoi(name.c_str() + pos+1)+1); - -failed: - return std::pair("\\" + name, 0); -} - -void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode, bool wideports) -{ - RTLIL::Module *module = nullptr; - RTLIL::Const *lutptr = NULL; - RTLIL::Cell *sopcell = NULL; - RTLIL::Cell *lastcell = nullptr; - RTLIL::State lut_default_state = RTLIL::State::Sx; - std::string err_reason; - int blif_maxnum = 0, sopmode = -1; - - auto blif_wire = [&](const std::string &wire_name) -> Wire* - { - if (wire_name[0] == '$') - { - for (int i = 0; i+1 < GetSize(wire_name); i++) - { - if (wire_name[i] != '$') - continue; - - int len = 0; - while (i+len+1 < GetSize(wire_name) && '0' <= wire_name[i+len+1] && wire_name[i+len+1] <= '9') - len++; - - if (len > 0) { - string num_str = wire_name.substr(i+1, len); - int num = atoi(num_str.c_str()) & 0x0fffffff; - blif_maxnum = std::max(blif_maxnum, num); - } - } - } - - IdString wire_id = RTLIL::escape_id(wire_name); - Wire *wire = module->wire(wire_id); - - if (wire == nullptr) - wire = module->addWire(wire_id); - - return wire; - }; - - dict *obj_attributes = nullptr; - dict *obj_parameters = nullptr; - - dict> wideports_cache; - - size_t buffer_size = 4096; - char *buffer = (char*)malloc(buffer_size); - int line_count = 0; - - while (1) - { - if (!read_next_line(buffer, buffer_size, line_count, f)) { - if (module != nullptr) - goto error; - free(buffer); - return; - } - - continue_without_read: - if (buffer[0] == '#') - continue; - - if (buffer[0] == '.') - { - if (lutptr) { - for (auto &bit : lutptr->bits) - if (bit == RTLIL::State::Sx) - bit = lut_default_state; - lutptr = NULL; - lut_default_state = RTLIL::State::Sx; - } - - if (sopcell) { - sopcell = NULL; - sopmode = -1; - } - - char *cmd = strtok(buffer, " \t\r\n"); - - if (!strcmp(cmd, ".model")) { - if (module != nullptr) - goto error; - module = new RTLIL::Module; - lastcell = nullptr; - module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n")); - obj_attributes = &module->attributes; - obj_parameters = nullptr; - if (design->module(module->name)) - log_error("Duplicate definition of module %s in line %d!\n", log_id(module->name), line_count); - design->add(module); - continue; - } - - if (module == nullptr) - goto error; - - if (!strcmp(cmd, ".end")) - { - for (auto &wp : wideports_cache) - { - auto name = wp.first; - int width = wp.second.first; - bool isinput = wp.second.second; - - RTLIL::Wire *wire = module->addWire(name, width); - wire->port_input = isinput; - wire->port_output = !isinput; - - for (int i = 0; i < width; i++) { - RTLIL::IdString other_name = name.str() + stringf("[%d]", i); - RTLIL::Wire *other_wire = module->wire(other_name); - if (other_wire) { - other_wire->port_input = false; - other_wire->port_output = false; - if (isinput) - module->connect(other_wire, SigSpec(wire, i)); - else - module->connect(SigSpec(wire, i), other_wire); - } - } - } - - module->fixup_ports(); - wideports_cache.clear(); - - if (run_clean) - { - Const buffer_lut(vector({State::S0, State::S1})); - vector remove_cells; - - for (auto cell : module->cells()) - if (cell->type == "$lut" && cell->getParam("\\LUT") == buffer_lut) { - module->connect(cell->getPort("\\Y"), cell->getPort("\\A")); - remove_cells.push_back(cell); - } - - for (auto cell : remove_cells) - module->remove(cell); - - Wire *true_wire = module->wire("$true"); - Wire *false_wire = module->wire("$false"); - Wire *undef_wire = module->wire("$undef"); - - if (true_wire != nullptr) - module->rename(true_wire, stringf("$true$%d", ++blif_maxnum)); - - if (false_wire != nullptr) - module->rename(false_wire, stringf("$false$%d", ++blif_maxnum)); - - if (undef_wire != nullptr) - module->rename(undef_wire, stringf("$undef$%d", ++blif_maxnum)); - - autoidx = std::max(autoidx, blif_maxnum+1); - blif_maxnum = 0; - } - - module = nullptr; - lastcell = nullptr; - obj_attributes = nullptr; - obj_parameters = nullptr; - continue; - } - - if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) - { - char *p; - while ((p = strtok(NULL, " \t\r\n")) != NULL) - { - RTLIL::IdString wire_name(stringf("\\%s", p)); - RTLIL::Wire *wire = module->wire(wire_name); - if (wire == nullptr) - wire = module->addWire(wire_name); - if (!strcmp(cmd, ".inputs")) - wire->port_input = true; - else - wire->port_output = true; - - if (wideports) { - std::pair wp = wideports_split(p); - if (wp.second > 0) { - wideports_cache[wp.first].first = std::max(wideports_cache[wp.first].first, wp.second); - wideports_cache[wp.first].second = !strcmp(cmd, ".inputs"); - } - } - } - obj_attributes = nullptr; - obj_parameters = nullptr; - continue; - } - - if (!strcmp(cmd, ".cname")) - { - char *p = strtok(NULL, " \t\r\n"); - if (p == NULL) - goto error; - - if(lastcell == nullptr || module == nullptr) - { - err_reason = stringf("No primitive object to attach .cname %s.", p); - goto error_with_reason; - } - - module->rename(lastcell, p); - continue; - } - - if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) { - char *n = strtok(NULL, " \t\r\n"); - char *v = strtok(NULL, "\r\n"); - IdString id_n = RTLIL::escape_id(n); - Const const_v; - if (v[0] == '"') { - std::string str(v+1); - if (str.back() == '"') - str.resize(str.size()-1); - const_v = Const(str); - } else { - int n = strlen(v); - const_v.bits.resize(n); - for (int i = 0; i < n; i++) - const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0; - } - if (!strcmp(cmd, ".attr")) { - if (obj_attributes == nullptr) { - err_reason = stringf("No object to attach .attr too."); - goto error_with_reason; - } - (*obj_attributes)[id_n] = const_v; - } else { - if (obj_parameters == nullptr) { - err_reason = stringf("No object to attach .param too."); - goto error_with_reason; - } - (*obj_parameters)[id_n] = const_v; - } - continue; - } - - if (!strcmp(cmd, ".latch")) - { - char *d = strtok(NULL, " \t\r\n"); - char *q = strtok(NULL, " \t\r\n"); - char *edge = strtok(NULL, " \t\r\n"); - char *clock = strtok(NULL, " \t\r\n"); - char *init = strtok(NULL, " \t\r\n"); - RTLIL::Cell *cell = nullptr; - - if (clock == nullptr && edge != nullptr) { - init = edge; - edge = nullptr; - } - - if (init != nullptr && (init[0] == '0' || init[0] == '1')) - blif_wire(q)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1); - - if (clock == nullptr) - goto no_latch_clock; - - if (!strcmp(edge, "re")) - cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q)); - else if (!strcmp(edge, "fe")) - cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false); - else if (!strcmp(edge, "ah")) - cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q)); - else if (!strcmp(edge, "al")) - cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false); - else { - no_latch_clock: - if (dff_name.empty()) { - cell = module->addFf(NEW_ID, blif_wire(d), blif_wire(q)); - } else { - cell = module->addCell(NEW_ID, dff_name); - cell->setPort("\\D", blif_wire(d)); - cell->setPort("\\Q", blif_wire(q)); - } - } - - lastcell = cell; - obj_attributes = &cell->attributes; - obj_parameters = &cell->parameters; - continue; - } - - if (!strcmp(cmd, ".gate") || !strcmp(cmd, ".subckt")) - { - char *p = strtok(NULL, " \t\r\n"); - if (p == NULL) - goto error; - - IdString celltype = RTLIL::escape_id(p); - RTLIL::Cell *cell = module->addCell(NEW_ID, celltype); - - dict> cell_wideports_cache; - - while ((p = strtok(NULL, " \t\r\n")) != NULL) - { - char *q = strchr(p, '='); - if (q == NULL || !q[0]) - goto error; - *(q++) = 0; - - if (wideports) { - std::pair wp = wideports_split(p); - if (wp.second > 0) - cell_wideports_cache[wp.first][wp.second-1] = blif_wire(q); - else - cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec()); - } else { - cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec()); - } - } - - for (auto &it : cell_wideports_cache) - { - int width = 0; - for (auto &b : it.second) - width = std::max(width, b.first + 1); - - SigSpec sig; - - for (int i = 0; i < width; i++) { - if (it.second.count(i)) - sig.append(it.second.at(i)); - else - sig.append(module->addWire(NEW_ID)); - } - - cell->setPort(it.first, sig); - } - - lastcell = cell; - obj_attributes = &cell->attributes; - obj_parameters = &cell->parameters; - continue; - } - - obj_attributes = nullptr; - obj_parameters = nullptr; - - if (!strcmp(cmd, ".barbuf") || !strcmp(cmd, ".conn")) - { - char *p = strtok(NULL, " \t\r\n"); - if (p == NULL) - goto error; - - char *q = strtok(NULL, " \t\r\n"); - if (q == NULL) - goto error; - - module->connect(blif_wire(q), blif_wire(p)); - continue; - } - - if (!strcmp(cmd, ".names")) - { - char *p; - RTLIL::SigSpec input_sig, output_sig; - while ((p = strtok(NULL, " \t\r\n")) != NULL) - input_sig.append(blif_wire(p)); - output_sig = input_sig.extract(input_sig.size()-1, 1); - input_sig = input_sig.extract(0, input_sig.size()-1); - - if (input_sig.size() == 0) - { - RTLIL::State state = RTLIL::State::Sa; - while (1) { - if (!read_next_line(buffer, buffer_size, line_count, f)) - goto error; - for (int i = 0; buffer[i]; i++) { - if (buffer[i] == ' ' || buffer[i] == '\t') - continue; - if (i == 0 && buffer[i] == '.') - goto finished_parsing_constval; - if (buffer[i] == '0') { - if (state == RTLIL::State::S1) - goto error; - state = RTLIL::State::S0; - continue; - } - if (buffer[i] == '1') { - if (state == RTLIL::State::S0) - goto error; - state = RTLIL::State::S1; - continue; - } - goto error; - } - } - - finished_parsing_constval: - if (state == RTLIL::State::Sa) - state = RTLIL::State::S0; - if (output_sig.as_wire()->name == "$undef") - state = RTLIL::State::Sx; - module->connect(RTLIL::SigSig(output_sig, state)); - goto continue_without_read; - } - - if (sop_mode) - { - sopcell = module->addCell(NEW_ID, "$sop"); - sopcell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size()); - sopcell->parameters["\\DEPTH"] = 0; - sopcell->parameters["\\TABLE"] = RTLIL::Const(); - sopcell->setPort("\\A", input_sig); - sopcell->setPort("\\Y", output_sig); - sopmode = -1; - lastcell = sopcell; - } - else - { - RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut"); - cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size()); - cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size()); - cell->setPort("\\A", input_sig); - cell->setPort("\\Y", output_sig); - lutptr = &cell->parameters.at("\\LUT"); - lut_default_state = RTLIL::State::Sx; - lastcell = cell; - } - continue; - } - - goto error; - } - - if (lutptr == NULL && sopcell == NULL) - goto error; - - char *input = strtok(buffer, " \t\r\n"); - char *output = strtok(NULL, " \t\r\n"); - - if (input == NULL || output == NULL || (strcmp(output, "0") && strcmp(output, "1"))) - goto error; - - int input_len = strlen(input); - - if (sopcell) - { - log_assert(sopcell->parameters["\\WIDTH"].as_int() == input_len); - sopcell->parameters["\\DEPTH"] = sopcell->parameters["\\DEPTH"].as_int() + 1; - - for (int i = 0; i < input_len; i++) - switch (input[i]) { - case '0': - sopcell->parameters["\\TABLE"].bits.push_back(State::S1); - sopcell->parameters["\\TABLE"].bits.push_back(State::S0); - break; - case '1': - sopcell->parameters["\\TABLE"].bits.push_back(State::S0); - sopcell->parameters["\\TABLE"].bits.push_back(State::S1); - break; - default: - sopcell->parameters["\\TABLE"].bits.push_back(State::S0); - sopcell->parameters["\\TABLE"].bits.push_back(State::S0); - break; - } - - if (sopmode == -1) { - sopmode = (*output == '1'); - if (!sopmode) { - SigSpec outnet = sopcell->getPort("\\Y"); - SigSpec tempnet = module->addWire(NEW_ID); - module->addNotGate(NEW_ID, tempnet, outnet); - sopcell->setPort("\\Y", tempnet); - } - } else - log_assert(sopmode == (*output == '1')); - } - - if (lutptr) - { - if (input_len > 12) - goto error; - - for (int i = 0; i < (1 << input_len); i++) { - for (int j = 0; j < input_len; j++) { - char c1 = input[j]; - if (c1 != '-') { - char c2 = (i & (1 << j)) != 0 ? '1' : '0'; - if (c1 != c2) - goto try_next_value; - } - } - lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1; - try_next_value:; - } - - lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0; - } - } - - return; - -error: - log_error("Syntax error in line %d!\n", line_count); -error_with_reason: - log_error("Syntax error in line %d: %s\n", line_count, err_reason.c_str()); -} - -struct BlifFrontend : public Frontend { - BlifFrontend() : Frontend("blif", "read BLIF file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_blif [options] [filename]\n"); - log("\n"); - log("Load modules from a BLIF file into the current design.\n"); - log("\n"); - log(" -sop\n"); - log(" Create $sop cells instead of $lut cells\n"); - log("\n"); - log(" -wideports\n"); - log(" Merge ports that match the pattern 'name[int]' into a single\n"); - log(" multi-bit port 'name'.\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - bool sop_mode = false; - bool wideports = false; - - log_header(design, "Executing BLIF frontend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-sop") { - sop_mode = true; - continue; - } - if (arg == "-wideports") { - wideports = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - parse_blif(design, *f, "", true, sop_mode, wideports); - } -} BlifFrontend; - -YOSYS_NAMESPACE_END - diff --git a/yosys/frontends/blif/blifparse.h b/yosys/frontends/blif/blifparse.h deleted file mode 100644 index 955b6aacf..000000000 --- a/yosys/frontends/blif/blifparse.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef ABC_BLIFPARSE -#define ABC_BLIFPARSE - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, - bool run_clean = false, bool sop_mode = false, bool wideports = false); - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/ilang/.gitignore b/yosys/frontends/ilang/.gitignore deleted file mode 100644 index f586b33c7..000000000 --- a/yosys/frontends/ilang/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -ilang_lexer.cc -ilang_parser.output -ilang_parser.tab.cc -ilang_parser.tab.hh diff --git a/yosys/frontends/ilang/Makefile.inc b/yosys/frontends/ilang/Makefile.inc deleted file mode 100644 index 6f1f0e8fc..000000000 --- a/yosys/frontends/ilang/Makefile.inc +++ /dev/null @@ -1,19 +0,0 @@ - -GENFILES += frontends/ilang/ilang_parser.tab.cc -GENFILES += frontends/ilang/ilang_parser.tab.hh -GENFILES += frontends/ilang/ilang_parser.output -GENFILES += frontends/ilang/ilang_lexer.cc - -frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y - $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -o $@ -d -r all -b frontends/ilang/ilang_parser $< - -frontends/ilang/ilang_parser.tab.hh: frontends/ilang/ilang_parser.tab.cc - -frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l - $(Q) mkdir -p $(dir $@) - $(P) flex -o frontends/ilang/ilang_lexer.cc $< - -OBJS += frontends/ilang/ilang_parser.tab.o frontends/ilang/ilang_lexer.o -OBJS += frontends/ilang/ilang_frontend.o - diff --git a/yosys/frontends/ilang/ilang_frontend.cc b/yosys/frontends/ilang/ilang_frontend.cc deleted file mode 100644 index 30d9ff79d..000000000 --- a/yosys/frontends/ilang/ilang_frontend.cc +++ /dev/null @@ -1,100 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation (as generated by the 'ilang' backend). - * - */ - -#include "ilang_frontend.h" -#include "kernel/register.h" -#include "kernel/log.h" - -void rtlil_frontend_ilang_yyerror(char const *s) -{ - YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s); -} - -YOSYS_NAMESPACE_BEGIN - -struct IlangFrontend : public Frontend { - IlangFrontend() : Frontend("ilang", "read modules from ilang file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_ilang [filename]\n"); - log("\n"); - log("Load modules from an ilang file to the current design. (ilang is a text\n"); - log("representation of a design in yosys's internal format.)\n"); - log("\n"); - log(" -nooverwrite\n"); - log(" ignore re-definitions of modules. (the default behavior is to\n"); - log(" create an error message if the existing module is not a blackbox\n"); - log(" module, and overwrite the existing module if it is a blackbox module.)\n"); - log("\n"); - log(" -overwrite\n"); - log(" overwrite existing modules with the same name\n"); - log("\n"); - log(" -lib\n"); - log(" only create empty blackbox modules\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - ILANG_FRONTEND::flag_nooverwrite = false; - ILANG_FRONTEND::flag_overwrite = false; - ILANG_FRONTEND::flag_lib = false; - - log_header(design, "Executing ILANG frontend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-nooverwrite") { - ILANG_FRONTEND::flag_nooverwrite = true; - ILANG_FRONTEND::flag_overwrite = false; - continue; - } - if (arg == "-overwrite") { - ILANG_FRONTEND::flag_nooverwrite = false; - ILANG_FRONTEND::flag_overwrite = true; - continue; - } - if (arg == "-lib") { - ILANG_FRONTEND::flag_lib = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - log("Input filename: %s\n", filename.c_str()); - - ILANG_FRONTEND::lexin = f; - ILANG_FRONTEND::current_design = design; - rtlil_frontend_ilang_yydebug = false; - rtlil_frontend_ilang_yyrestart(NULL); - rtlil_frontend_ilang_yyparse(); - rtlil_frontend_ilang_yylex_destroy(); - } -} IlangFrontend; - -YOSYS_NAMESPACE_END - diff --git a/yosys/frontends/ilang/ilang_frontend.h b/yosys/frontends/ilang/ilang_frontend.h deleted file mode 100644 index f8a152841..000000000 --- a/yosys/frontends/ilang/ilang_frontend.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation (as generated by the 'ilang' backend). - * - */ - -#ifndef ILANG_FRONTEND_H -#define ILANG_FRONTEND_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -namespace ILANG_FRONTEND { - extern std::istream *lexin; - extern RTLIL::Design *current_design; - extern bool flag_nooverwrite; - extern bool flag_overwrite; - extern bool flag_lib; -} - -YOSYS_NAMESPACE_END - -extern int rtlil_frontend_ilang_yydebug; -int rtlil_frontend_ilang_yylex(void); -void rtlil_frontend_ilang_yyerror(char const *s); -void rtlil_frontend_ilang_yyrestart(FILE *f); -int rtlil_frontend_ilang_yyparse(void); -int rtlil_frontend_ilang_yylex_destroy(void); -int rtlil_frontend_ilang_yyget_lineno(void); - -#endif - diff --git a/yosys/frontends/ilang/ilang_lexer.l b/yosys/frontends/ilang/ilang_lexer.l deleted file mode 100644 index 4fd0ae855..000000000 --- a/yosys/frontends/ilang/ilang_lexer.l +++ /dev/null @@ -1,139 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation (as generated by the 'ilang' backend). - * - */ - -%{ - -#ifdef __clang__ -// bison generates code using the 'register' storage class specifier -#pragma clang diagnostic ignored "-Wdeprecated-register" -#endif - -#include "frontends/ilang/ilang_frontend.h" -#include "ilang_parser.tab.hh" - -USING_YOSYS_NAMESPACE - -#define YY_INPUT(buf,result,max_size) \ - result = readsome(*ILANG_FRONTEND::lexin, buf, max_size) - -%} - -%option yylineno -%option noyywrap -%option nounput -%option prefix="rtlil_frontend_ilang_yy" - -%x STRING - -%% - -"autoidx" { return TOK_AUTOIDX; } -"module" { return TOK_MODULE; } -"attribute" { return TOK_ATTRIBUTE; } -"parameter" { return TOK_PARAMETER; } -"signed" { return TOK_SIGNED; } -"real" { return TOK_REAL; } -"wire" { return TOK_WIRE; } -"memory" { return TOK_MEMORY; } -"width" { return TOK_WIDTH; } -"upto" { return TOK_UPTO; } -"offset" { return TOK_OFFSET; } -"size" { return TOK_SIZE; } -"input" { return TOK_INPUT; } -"output" { return TOK_OUTPUT; } -"inout" { return TOK_INOUT; } -"cell" { return TOK_CELL; } -"connect" { return TOK_CONNECT; } -"switch" { return TOK_SWITCH; } -"case" { return TOK_CASE; } -"assign" { return TOK_ASSIGN; } -"sync" { return TOK_SYNC; } -"low" { return TOK_LOW; } -"high" { return TOK_HIGH; } -"posedge" { return TOK_POSEDGE; } -"negedge" { return TOK_NEGEDGE; } -"edge" { return TOK_EDGE; } -"always" { return TOK_ALWAYS; } -"global" { return TOK_GLOBAL; } -"init" { return TOK_INIT; } -"update" { return TOK_UPDATE; } -"process" { return TOK_PROCESS; } -"end" { return TOK_END; } - -[a-z]+ { return TOK_INVALID; } - -"\\"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; } -"$"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; } -"."[0-9]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; } - -[0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; } --?[0-9]+ { rtlil_frontend_ilang_yylval.integer = atoi(yytext); return TOK_INT; } - -\" { BEGIN(STRING); } -\\. { yymore(); } -\" { - BEGIN(0); - char *yystr = strdup(yytext); - yystr[strlen(yytext) - 1] = 0; - int i = 0, j = 0; - while (yystr[i]) { - if (yystr[i] == '\\' && yystr[i + 1]) { - i++; - if (yystr[i] == 'n') - yystr[i] = '\n'; - else if (yystr[i] == 't') - yystr[i] = '\t'; - else if ('0' <= yystr[i] && yystr[i] <= '7') { - yystr[i] = yystr[i] - '0'; - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - } - } - yystr[j++] = yystr[i++]; - } - yystr[j] = 0; - rtlil_frontend_ilang_yylval.string = yystr; - return TOK_STRING; -} -. { yymore(); } - -"#"[^\n]* /* ignore comments */ -[ \t] /* ignore non-newline whitespaces */ -[\r\n]+ { return TOK_EOL; } - -. { return *yytext; } - -%% - -// this is a hack to avoid the 'yyinput defined but not used' error msgs -void *rtlil_frontend_ilang_avoid_input_warnings() { - return (void*)&yyinput; -} - diff --git a/yosys/frontends/ilang/ilang_parser.y b/yosys/frontends/ilang/ilang_parser.y deleted file mode 100644 index b4b9693da..000000000 --- a/yosys/frontends/ilang/ilang_parser.y +++ /dev/null @@ -1,467 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation (as generated by the 'ilang' backend). - * - */ - -%{ -#include -#include "frontends/ilang/ilang_frontend.h" -YOSYS_NAMESPACE_BEGIN -namespace ILANG_FRONTEND { - std::istream *lexin; - RTLIL::Design *current_design; - RTLIL::Module *current_module; - RTLIL::Wire *current_wire; - RTLIL::Memory *current_memory; - RTLIL::Cell *current_cell; - RTLIL::Process *current_process; - std::vector*> switch_stack; - std::vector case_stack; - dict attrbuf; - bool flag_nooverwrite, flag_overwrite, flag_lib; - bool delete_current_module; -} -using namespace ILANG_FRONTEND; -YOSYS_NAMESPACE_END -USING_YOSYS_NAMESPACE -%} - -%define api.prefix {rtlil_frontend_ilang_yy} - -/* The union is defined in the header, so we need to provide all the - * includes it requires - */ -%code requires { -#include -#include -#include "frontends/ilang/ilang_frontend.h" -} - -%union { - char *string; - int integer; - YOSYS_NAMESPACE_PREFIX RTLIL::Const *data; - YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec; - std::vector *rsigspec; -} - -%token TOK_ID TOK_VALUE TOK_STRING -%token TOK_INT -%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT -%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC -%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT -%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET -%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO - -%type sigspec_list_reversed -%type sigspec sigspec_list -%type sync_type -%type constant - -%expect 0 -%debug - -%% - -input: - optional_eol { - attrbuf.clear(); - } design { - if (attrbuf.size() != 0) - rtlil_frontend_ilang_yyerror("dangling attribute"); - }; - -EOL: - optional_eol TOK_EOL; - -optional_eol: - optional_eol TOK_EOL | /* empty */; - -design: - design module | - design attr_stmt | - design autoidx_stmt | - /* empty */; - -module: - TOK_MODULE TOK_ID EOL { - delete_current_module = false; - if (current_design->has($2)) { - RTLIL::Module *existing_mod = current_design->module($2); - if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) { - log("Ignoring blackbox re-definition of module %s.\n", $2); - delete_current_module = true; - } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { - rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str()); - } else if (flag_nooverwrite) { - log("Ignoring re-definition of module %s.\n", $2); - delete_current_module = true; - } else { - log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2); - current_design->remove(existing_mod); - } - } - current_module = new RTLIL::Module; - current_module->name = $2; - current_module->attributes = attrbuf; - if (!delete_current_module) - current_design->add(current_module); - attrbuf.clear(); - free($2); - } module_body TOK_END { - if (attrbuf.size() != 0) - rtlil_frontend_ilang_yyerror("dangling attribute"); - current_module->fixup_ports(); - if (delete_current_module) - delete current_module; - else if (flag_lib) - current_module->makeblackbox(); - current_module = nullptr; - } EOL; - -module_body: - module_body module_stmt | - /* empty */; - -module_stmt: - param_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; - -param_stmt: - TOK_PARAMETER TOK_ID EOL { - current_module->avail_parameters.insert($2); - free($2); - }; - -attr_stmt: - TOK_ATTRIBUTE TOK_ID constant EOL { - attrbuf[$2] = *$3; - delete $3; - free($2); - }; - -autoidx_stmt: - TOK_AUTOIDX TOK_INT EOL { - autoidx = max(autoidx, $2); - }; - -wire_stmt: - TOK_WIRE { - current_wire = current_module->addWire("$__ilang_frontend_tmp__"); - current_wire->attributes = attrbuf; - attrbuf.clear(); - } wire_options TOK_ID EOL { - if (current_module->wires_.count($4) != 0) - rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of wire %s.", $4).c_str()); - current_module->rename(current_wire, $4); - free($4); - }; - -wire_options: - wire_options TOK_WIDTH TOK_INT { - current_wire->width = $3; - } | - wire_options TOK_UPTO { - current_wire->upto = true; - } | - wire_options TOK_OFFSET TOK_INT { - current_wire->start_offset = $3; - } | - wire_options TOK_INPUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = true; - current_wire->port_output = false; - } | - wire_options TOK_OUTPUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = false; - current_wire->port_output = true; - } | - wire_options TOK_INOUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = true; - current_wire->port_output = true; - } | - /* empty */; - -memory_stmt: - TOK_MEMORY { - current_memory = new RTLIL::Memory; - current_memory->attributes = attrbuf; - attrbuf.clear(); - } memory_options TOK_ID EOL { - if (current_module->memories.count($4) != 0) - rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of memory %s.", $4).c_str()); - current_memory->name = $4; - current_module->memories[$4] = current_memory; - free($4); - }; - -memory_options: - memory_options TOK_WIDTH TOK_INT { - current_memory->width = $3; - } | - memory_options TOK_SIZE TOK_INT { - current_memory->size = $3; - } | - memory_options TOK_OFFSET TOK_INT { - current_memory->start_offset = $3; - } | - /* empty */; - -cell_stmt: - TOK_CELL TOK_ID TOK_ID EOL { - if (current_module->cells_.count($3) != 0) - rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell %s.", $3).c_str()); - current_cell = current_module->addCell($3, $2); - current_cell->attributes = attrbuf; - attrbuf.clear(); - free($2); - free($3); - } cell_body TOK_END EOL; - -cell_body: - cell_body TOK_PARAMETER TOK_ID constant EOL { - current_cell->parameters[$3] = *$4; - free($3); - delete $4; - } | - cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL { - current_cell->parameters[$4] = *$5; - current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED; - free($4); - delete $5; - } | - cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL { - current_cell->parameters[$4] = *$5; - current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL; - free($4); - delete $5; - } | - cell_body TOK_CONNECT TOK_ID sigspec EOL { - if (current_cell->hasPort($3)) - rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str()); - current_cell->setPort($3, *$4); - delete $4; - free($3); - } | - /* empty */; - -proc_stmt: - TOK_PROCESS TOK_ID EOL { - if (current_module->processes.count($2) != 0) - rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of process %s.", $2).c_str()); - current_process = new RTLIL::Process; - current_process->name = $2; - current_process->attributes = attrbuf; - current_module->processes[$2] = current_process; - switch_stack.clear(); - switch_stack.push_back(¤t_process->root_case.switches); - case_stack.clear(); - case_stack.push_back(¤t_process->root_case); - attrbuf.clear(); - free($2); - } case_body sync_list TOK_END EOL; - -switch_stmt: - TOK_SWITCH sigspec EOL { - RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; - rule->signal = *$2; - rule->attributes = attrbuf; - switch_stack.back()->push_back(rule); - attrbuf.clear(); - delete $2; - } attr_list switch_body TOK_END EOL; - -attr_list: - /* empty */ | - attr_list attr_stmt; - -switch_body: - switch_body TOK_CASE { - RTLIL::CaseRule *rule = new RTLIL::CaseRule; - rule->attributes = attrbuf; - switch_stack.back()->back()->cases.push_back(rule); - switch_stack.push_back(&rule->switches); - case_stack.push_back(rule); - attrbuf.clear(); - } compare_list EOL case_body { - switch_stack.pop_back(); - case_stack.pop_back(); - } | - /* empty */; - -compare_list: - sigspec { - case_stack.back()->compare.push_back(*$1); - delete $1; - } | - compare_list ',' sigspec { - case_stack.back()->compare.push_back(*$3); - delete $3; - } | - /* empty */; - -case_body: - case_body attr_stmt | - case_body switch_stmt | - case_body assign_stmt | - /* empty */; - -assign_stmt: - TOK_ASSIGN sigspec sigspec EOL { - if (attrbuf.size() != 0) - rtlil_frontend_ilang_yyerror("dangling attribute"); - case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3)); - delete $2; - delete $3; - }; - -sync_list: - sync_list TOK_SYNC sync_type sigspec EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType($3); - rule->signal = *$4; - current_process->syncs.push_back(rule); - delete $4; - } update_list | - sync_list TOK_SYNC TOK_ALWAYS EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STa; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - sync_list TOK_SYNC TOK_GLOBAL EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STg; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - sync_list TOK_SYNC TOK_INIT EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STi; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - /* empty */; - -sync_type: - TOK_LOW { $$ = RTLIL::ST0; } | - TOK_HIGH { $$ = RTLIL::ST1; } | - TOK_POSEDGE { $$ = RTLIL::STp; } | - TOK_NEGEDGE { $$ = RTLIL::STn; } | - TOK_EDGE { $$ = RTLIL::STe; }; - -update_list: - update_list TOK_UPDATE sigspec sigspec EOL { - current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4)); - delete $3; - delete $4; - } | - /* empty */; - -constant: - TOK_VALUE { - char *ep; - int width = strtol($1, &ep, 10); - std::list bits; - while (*(++ep) != 0) { - RTLIL::State bit = RTLIL::Sx; - switch (*ep) { - case '0': bit = RTLIL::S0; break; - case '1': bit = RTLIL::S1; break; - case 'x': bit = RTLIL::Sx; break; - case 'z': bit = RTLIL::Sz; break; - case '-': bit = RTLIL::Sa; break; - case 'm': bit = RTLIL::Sm; break; - } - bits.push_front(bit); - } - if (bits.size() == 0) - bits.push_back(RTLIL::Sx); - while ((int)bits.size() < width) { - RTLIL::State bit = bits.back(); - if (bit == RTLIL::S1) - bit = RTLIL::S0; - bits.push_back(bit); - } - while ((int)bits.size() > width) - bits.pop_back(); - $$ = new RTLIL::Const; - for (auto it = bits.begin(); it != bits.end(); it++) - $$->bits.push_back(*it); - free($1); - } | - TOK_INT { - $$ = new RTLIL::Const($1, 32); - } | - TOK_STRING { - $$ = new RTLIL::Const($1); - free($1); - }; - -sigspec: - constant { - $$ = new RTLIL::SigSpec(*$1); - delete $1; - } | - TOK_ID { - if (current_module->wires_.count($1) == 0) - rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str()); - $$ = new RTLIL::SigSpec(current_module->wires_[$1]); - free($1); - } | - sigspec '[' TOK_INT ']' { - $$ = new RTLIL::SigSpec($1->extract($3)); - delete $1; - } | - sigspec '[' TOK_INT ':' TOK_INT ']' { - $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1)); - delete $1; - } | - '{' sigspec_list '}' { - $$ = $2; - }; - -sigspec_list_reversed: - sigspec_list_reversed sigspec { - $$->push_back(*$2); - delete $2; - } | - /* empty */ { - $$ = new std::vector; - }; - -sigspec_list: sigspec_list_reversed { - $$ = new RTLIL::SigSpec; - for (auto it = $1->rbegin(); it != $1->rend(); it++) - $$->append(*it); - delete $1; - }; - -conn_stmt: - TOK_CONNECT sigspec sigspec EOL { - if (attrbuf.size() != 0) - rtlil_frontend_ilang_yyerror("dangling attribute"); - current_module->connect(*$2, *$3); - delete $2; - delete $3; - }; diff --git a/yosys/frontends/json/Makefile.inc b/yosys/frontends/json/Makefile.inc deleted file mode 100644 index 0fe1b3722..000000000 --- a/yosys/frontends/json/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += frontends/json/jsonparse.o - diff --git a/yosys/frontends/json/jsonparse.cc b/yosys/frontends/json/jsonparse.cc deleted file mode 100644 index f5ae8eb72..000000000 --- a/yosys/frontends/json/jsonparse.cc +++ /dev/null @@ -1,565 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -struct JsonNode -{ - char type; // S=String, N=Number, A=Array, D=Dict - string data_string; - int data_number; - vector data_array; - dict data_dict; - vector data_dict_keys; - - JsonNode(std::istream &f) - { - type = 0; - data_number = 0; - - while (1) - { - int ch = f.get(); - - if (ch == EOF) - log_error("Unexpected EOF in JSON file.\n"); - - if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') - continue; - - if (ch == '"') - { - type = 'S'; - - while (1) - { - ch = f.get(); - - if (ch == EOF) - log_error("Unexpected EOF in JSON string.\n"); - - if (ch == '"') - break; - - if (ch == '\\') { - int ch = f.get(); - - if (ch == EOF) - log_error("Unexpected EOF in JSON string.\n"); - } - - data_string += ch; - } - - break; - } - - if ('0' <= ch && ch <= '9') - { - type = 'N'; - data_number = ch - '0'; - data_string += ch; - - while (1) - { - ch = f.get(); - - if (ch == EOF) - break; - - if (ch == '.') - goto parse_real; - - if (ch < '0' || '9' < ch) { - f.unget(); - break; - } - - data_number = data_number*10 + (ch - '0'); - data_string += ch; - } - - data_string = ""; - break; - - parse_real: - type = 'S'; - data_number = 0; - data_string += ch; - - while (1) - { - ch = f.get(); - - if (ch == EOF) - break; - - if (ch < '0' || '9' < ch) { - f.unget(); - break; - } - - data_string += ch; - } - - break; - } - - if (ch == '[') - { - type = 'A'; - - while (1) - { - ch = f.get(); - - if (ch == EOF) - log_error("Unexpected EOF in JSON file.\n"); - - if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',') - continue; - - if (ch == ']') - break; - - f.unget(); - data_array.push_back(new JsonNode(f)); - } - - break; - } - - if (ch == '{') - { - type = 'D'; - - while (1) - { - ch = f.get(); - - if (ch == EOF) - log_error("Unexpected EOF in JSON file.\n"); - - if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',') - continue; - - if (ch == '}') - break; - - f.unget(); - JsonNode key(f); - - while (1) - { - ch = f.get(); - - if (ch == EOF) - log_error("Unexpected EOF in JSON file.\n"); - - if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ':') - continue; - - f.unget(); - break; - } - - JsonNode *value = new JsonNode(f); - - if (key.type != 'S') - log_error("Unexpected non-string key in JSON dict.\n"); - - data_dict[key.data_string] = value; - data_dict_keys.push_back(key.data_string); - } - - break; - } - - log_error("Unexpected character in JSON file: '%c'\n", ch); - } - } - - ~JsonNode() - { - for (auto it : data_array) - delete it; - for (auto &it : data_dict) - delete it.second; - } -}; - -void json_parse_attr_param(dict &results, JsonNode *node) -{ - if (node->type != 'D') - log_error("JSON attributes or parameters node is not a dictionary.\n"); - - for (auto it : node->data_dict) - { - IdString key = RTLIL::escape_id(it.first.c_str()); - JsonNode *value_node = it.second; - Const value; - - if (value_node->type == 'S') { - string &s = value_node->data_string; - if (s.find_first_not_of("01xz") == string::npos) - value = Const::from_string(s); - else - value = Const(s); - } else - if (value_node->type == 'N') { - value = Const(value_node->data_number, 32); - } else - if (value_node->type == 'A') { - log_error("JSON attribute or parameter value is an array.\n"); - } else - if (value_node->type == 'D') { - log_error("JSON attribute or parameter value is a dict.\n"); - } else { - log_abort(); - } - - results[key] = value; - } -} - -void json_import(Design *design, string &modname, JsonNode *node) -{ - log("Importing module %s from JSON tree.\n", modname.c_str()); - - Module *module = new RTLIL::Module; - module->name = RTLIL::escape_id(modname.c_str()); - - if (design->module(module->name)) - log_error("Re-definition of module %s.\n", log_id(module->name)); - - design->add(module); - - if (node->data_dict.count("attributes")) - json_parse_attr_param(module->attributes, node->data_dict.at("attributes")); - - dict signal_bits; - - if (node->data_dict.count("ports")) - { - JsonNode *ports_node = node->data_dict.at("ports"); - - if (ports_node->type != 'D') - log_error("JSON ports node is not a dictionary.\n"); - - for (int port_id = 1; port_id <= GetSize(ports_node->data_dict_keys); port_id++) - { - IdString port_name = RTLIL::escape_id(ports_node->data_dict_keys[port_id-1].c_str()); - JsonNode *port_node = ports_node->data_dict.at(ports_node->data_dict_keys[port_id-1]); - - if (port_node->type != 'D') - log_error("JSON port node '%s' is not a dictionary.\n", log_id(port_name)); - - if (port_node->data_dict.count("direction") == 0) - log_error("JSON port node '%s' has no direction attribute.\n", log_id(port_name)); - - if (port_node->data_dict.count("bits") == 0) - log_error("JSON port node '%s' has no bits attribute.\n", log_id(port_name)); - - JsonNode *port_direction_node = port_node->data_dict.at("direction"); - JsonNode *port_bits_node = port_node->data_dict.at("bits"); - - if (port_direction_node->type != 'S') - log_error("JSON port node '%s' has non-string direction attribute.\n", log_id(port_name)); - - if (port_bits_node->type != 'A') - log_error("JSON port node '%s' has non-array bits attribute.\n", log_id(port_name)); - - Wire *port_wire = module->wire(port_name); - - if (port_wire == nullptr) - port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array)); - - if (port_node->data_dict.count("upto") != 0) { - JsonNode *val = port_node->data_dict.at("upto"); - if (val->type == 'N') - port_wire->upto = val->data_number != 0; - } - - if (port_node->data_dict.count("offset") != 0) { - JsonNode *val = port_node->data_dict.at("offset"); - if (val->type == 'N') - port_wire->start_offset = val->data_number; - } - - if (port_direction_node->data_string == "input") { - port_wire->port_input = true; - } else - if (port_direction_node->data_string == "output") { - port_wire->port_output = true; - } else - if (port_direction_node->data_string == "inout") { - port_wire->port_input = true; - port_wire->port_output = true; - } else - log_error("JSON port node '%s' has invalid '%s' direction attribute.\n", log_id(port_name), port_direction_node->data_string.c_str()); - - port_wire->port_id = port_id; - - for (int i = 0; i < GetSize(port_bits_node->data_array); i++) - { - JsonNode *bitval_node = port_bits_node->data_array.at(i); - SigBit sigbit(port_wire, i); - - if (bitval_node->type == 'S') { - if (bitval_node->data_string == "0") - module->connect(sigbit, State::S0); - else if (bitval_node->data_string == "1") - module->connect(sigbit, State::S1); - else if (bitval_node->data_string == "x") - module->connect(sigbit, State::Sx); - else if (bitval_node->data_string == "z") - module->connect(sigbit, State::Sz); - else - log_error("JSON port node '%s' has invalid '%s' bit string value on bit %d.\n", - log_id(port_name), bitval_node->data_string.c_str(), i); - } else - if (bitval_node->type == 'N') { - int bitidx = bitval_node->data_number; - if (signal_bits.count(bitidx)) { - if (port_wire->port_output) { - module->connect(sigbit, signal_bits.at(bitidx)); - } else { - module->connect(signal_bits.at(bitidx), sigbit); - signal_bits[bitidx] = sigbit; - } - } else { - signal_bits[bitidx] = sigbit; - } - } else - log_error("JSON port node '%s' has invalid bit value on bit %d.\n", log_id(port_name), i); - } - } - - module->fixup_ports(); - } - - if (node->data_dict.count("netnames")) - { - JsonNode *netnames_node = node->data_dict.at("netnames"); - - if (netnames_node->type != 'D') - log_error("JSON netnames node is not a dictionary.\n"); - - for (auto &net : netnames_node->data_dict) - { - IdString net_name = RTLIL::escape_id(net.first.c_str()); - JsonNode *net_node = net.second; - - if (net_node->type != 'D') - log_error("JSON netname node '%s' is not a dictionary.\n", log_id(net_name)); - - if (net_node->data_dict.count("bits") == 0) - log_error("JSON netname node '%s' has no bits attribute.\n", log_id(net_name)); - - JsonNode *bits_node = net_node->data_dict.at("bits"); - - if (bits_node->type != 'A') - log_error("JSON netname node '%s' has non-array bits attribute.\n", log_id(net_name)); - - Wire *wire = module->wire(net_name); - - if (wire == nullptr) - wire = module->addWire(net_name, GetSize(bits_node->data_array)); - - if (net_node->data_dict.count("upto") != 0) { - JsonNode *val = net_node->data_dict.at("upto"); - if (val->type == 'N') - wire->upto = val->data_number != 0; - } - - if (net_node->data_dict.count("offset") != 0) { - JsonNode *val = net_node->data_dict.at("offset"); - if (val->type == 'N') - wire->start_offset = val->data_number; - } - - for (int i = 0; i < GetSize(bits_node->data_array); i++) - { - JsonNode *bitval_node = bits_node->data_array.at(i); - SigBit sigbit(wire, i); - - if (bitval_node->type == 'S') { - if (bitval_node->data_string == "0") - module->connect(sigbit, State::S0); - else if (bitval_node->data_string == "1") - module->connect(sigbit, State::S1); - else if (bitval_node->data_string == "x") - module->connect(sigbit, State::Sx); - else if (bitval_node->data_string == "z") - module->connect(sigbit, State::Sz); - else - log_error("JSON netname node '%s' has invalid '%s' bit string value on bit %d.\n", - log_id(net_name), bitval_node->data_string.c_str(), i); - } else - if (bitval_node->type == 'N') { - int bitidx = bitval_node->data_number; - if (signal_bits.count(bitidx)) { - if (sigbit != signal_bits.at(bitidx)) - module->connect(sigbit, signal_bits.at(bitidx)); - } else { - signal_bits[bitidx] = sigbit; - } - } else - log_error("JSON netname node '%s' has invalid bit value on bit %d.\n", log_id(net_name), i); - } - - if (net_node->data_dict.count("attributes")) - json_parse_attr_param(wire->attributes, net_node->data_dict.at("attributes")); - } - } - - if (node->data_dict.count("cells")) - { - JsonNode *cells_node = node->data_dict.at("cells"); - - if (cells_node->type != 'D') - log_error("JSON cells node is not a dictionary.\n"); - - for (auto &cell_node_it : cells_node->data_dict) - { - IdString cell_name = RTLIL::escape_id(cell_node_it.first.c_str()); - JsonNode *cell_node = cell_node_it.second; - - if (cell_node->type != 'D') - log_error("JSON cells node '%s' is not a dictionary.\n", log_id(cell_name)); - - if (cell_node->data_dict.count("type") == 0) - log_error("JSON cells node '%s' has no type attribute.\n", log_id(cell_name)); - - JsonNode *type_node = cell_node->data_dict.at("type"); - - if (type_node->type != 'S') - log_error("JSON cells node '%s' has a non-string type.\n", log_id(cell_name)); - - IdString cell_type = RTLIL::escape_id(type_node->data_string.c_str()); - - Cell *cell = module->addCell(cell_name, cell_type); - - if (cell_node->data_dict.count("connections") == 0) - log_error("JSON cells node '%s' has no connections attribute.\n", log_id(cell_name)); - - JsonNode *connections_node = cell_node->data_dict.at("connections"); - - if (connections_node->type != 'D') - log_error("JSON cells node '%s' has non-dictionary connections attribute.\n", log_id(cell_name)); - - for (auto &conn_it : connections_node->data_dict) - { - IdString conn_name = RTLIL::escape_id(conn_it.first.c_str()); - JsonNode *conn_node = conn_it.second; - - if (conn_node->type != 'A') - log_error("JSON cells node '%s' connection '%s' is not an array.\n", log_id(cell_name), log_id(conn_name)); - - SigSpec sig; - - for (int i = 0; i < GetSize(conn_node->data_array); i++) - { - JsonNode *bitval_node = conn_node->data_array.at(i); - - if (bitval_node->type == 'S') { - if (bitval_node->data_string == "0") - sig.append(State::S0); - else if (bitval_node->data_string == "1") - sig.append(State::S1); - else if (bitval_node->data_string == "x") - sig.append(State::Sx); - else if (bitval_node->data_string == "z") - sig.append(State::Sz); - else - log_error("JSON cells node '%s' connection '%s' has invalid '%s' bit string value on bit %d.\n", - log_id(cell_name), log_id(conn_name), bitval_node->data_string.c_str(), i); - } else - if (bitval_node->type == 'N') { - int bitidx = bitval_node->data_number; - if (signal_bits.count(bitidx) == 0) - signal_bits[bitidx] = module->addWire(NEW_ID); - sig.append(signal_bits.at(bitidx)); - } else - log_error("JSON cells node '%s' connection '%s' has invalid bit value on bit %d.\n", - log_id(cell_name), log_id(conn_name), i); - - } - - cell->setPort(conn_name, sig); - } - - if (cell_node->data_dict.count("attributes")) - json_parse_attr_param(cell->attributes, cell_node->data_dict.at("attributes")); - - if (cell_node->data_dict.count("parameters")) - json_parse_attr_param(cell->parameters, cell_node->data_dict.at("parameters")); - } - } -} - -struct JsonFrontend : public Frontend { - JsonFrontend() : Frontend("json", "read JSON file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_json [filename]\n"); - log("\n"); - log("Load modules from a JSON file into the current design See \"help write_json\"\n"); - log("for a description of the file format.\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing JSON frontend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - // std::string arg = args[argidx]; - // if (arg == "-sop") { - // sop_mode = true; - // continue; - // } - break; - } - extra_args(f, filename, args, argidx); - - JsonNode root(*f); - - if (root.type != 'D') - log_error("JSON root node is not a dictionary.\n"); - - if (root.data_dict.count("modules") != 0) - { - JsonNode *modules = root.data_dict.at("modules"); - - if (modules->type != 'D') - log_error("JSON modules node is not a dictionary.\n"); - - for (auto &it : modules->data_dict) - json_import(design, it.first, it.second); - } - } -} JsonFrontend; - -YOSYS_NAMESPACE_END - diff --git a/yosys/frontends/liberty/Makefile.inc b/yosys/frontends/liberty/Makefile.inc deleted file mode 100644 index a02ef5e45..000000000 --- a/yosys/frontends/liberty/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += frontends/liberty/liberty.o - diff --git a/yosys/frontends/liberty/liberty.cc b/yosys/frontends/liberty/liberty.cc deleted file mode 100644 index 6e3cffaca..000000000 --- a/yosys/frontends/liberty/liberty.cc +++ /dev/null @@ -1,710 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "passes/techmap/libparse.h" -#include "kernel/register.h" -#include "kernel/log.h" - -YOSYS_NAMESPACE_BEGIN - -struct token_t { - char type; - RTLIL::SigSpec sig; - token_t (char t) : type(t) { } - token_t (char t, RTLIL::SigSpec s) : type(t), sig(s) { } -}; - -static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&expr) -{ - log_assert(*expr != 0); - - int id_len = 0; - while (('a' <= expr[id_len] && expr[id_len] <= 'z') || ('A' <= expr[id_len] && expr[id_len] <= 'Z') || - ('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' || - expr[id_len] == '_' || expr[id_len] == '[' || expr[id_len] == ']') id_len++; - - if (id_len == 0) - log_error("Expected identifier at `%s'.\n", expr); - - if (id_len == 1 && (*expr == '0' || *expr == '1')) - return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1; - - std::string id = RTLIL::escape_id(std::string(expr, id_len)); - if (!module->wires_.count(id)) - log_error("Can't resolve wire name %s.\n", RTLIL::unescape_id(id).c_str()); - - expr += id_len; - return module->wires_.at(id); -} - -static RTLIL::SigSpec create_inv_cell(RTLIL::Module *module, RTLIL::SigSpec A) -{ - RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_"); - cell->setPort("\\A", A); - cell->setPort("\\Y", module->addWire(NEW_ID)); - return cell->getPort("\\Y"); -} - -static RTLIL::SigSpec create_xor_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B) -{ - RTLIL::Cell *cell = module->addCell(NEW_ID, "$_XOR_"); - cell->setPort("\\A", A); - cell->setPort("\\B", B); - cell->setPort("\\Y", module->addWire(NEW_ID)); - return cell->getPort("\\Y"); -} - -static RTLIL::SigSpec create_and_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B) -{ - RTLIL::Cell *cell = module->addCell(NEW_ID, "$_AND_"); - cell->setPort("\\A", A); - cell->setPort("\\B", B); - cell->setPort("\\Y", module->addWire(NEW_ID)); - return cell->getPort("\\Y"); -} - -static RTLIL::SigSpec create_or_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B) -{ - RTLIL::Cell *cell = module->addCell(NEW_ID, "$_OR_"); - cell->setPort("\\A", A); - cell->setPort("\\B", B); - cell->setPort("\\Y", module->addWire(NEW_ID)); - return cell->getPort("\\Y"); -} - -static bool parse_func_reduce(RTLIL::Module *module, std::vector &stack, token_t next_token) -{ - int top = int(stack.size())-1; - - if (0 <= top-1 && stack[top].type == 0 && stack[top-1].type == '!') { - token_t t = token_t(0, create_inv_cell(module, stack[top].sig)); - stack.pop_back(); - stack.pop_back(); - stack.push_back(t); - return true; - } - - if (0 <= top-1 && stack[top].type == '\'' && stack[top-1].type == 0) { - token_t t = token_t(0, create_inv_cell(module, stack[top-1].sig)); - stack.pop_back(); - stack.pop_back(); - stack.push_back(t); - return true; - } - - if (0 <= top && stack[top].type == 0) { - if (next_token.type == '\'') - return false; - stack[top].type = 1; - return true; - } - - if (0 <= top-2 && stack[top-2].type == 1 && stack[top-1].type == '^' && stack[top].type == 1) { - token_t t = token_t(1, create_xor_cell(module, stack[top-2].sig, stack[top].sig)); - stack.pop_back(); - stack.pop_back(); - stack.pop_back(); - stack.push_back(t); - return true; - } - - if (0 <= top && stack[top].type == 1) { - if (next_token.type == '^') - return false; - stack[top].type = 2; - return true; - } - - if (0 <= top-1 && stack[top-1].type == 2 && stack[top].type == 2) { - token_t t = token_t(2, create_and_cell(module, stack[top-1].sig, stack[top].sig)); - stack.pop_back(); - stack.pop_back(); - stack.push_back(t); - return true; - } - - if (0 <= top-2 && stack[top-2].type == 2 && (stack[top-1].type == '*' || stack[top-1].type == '&') && stack[top].type == 2) { - token_t t = token_t(2, create_and_cell(module, stack[top-2].sig, stack[top].sig)); - stack.pop_back(); - stack.pop_back(); - stack.pop_back(); - stack.push_back(t); - return true; - } - - if (0 <= top && stack[top].type == 2) { - if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(' || next_token.type == '!') - return false; - stack[top].type = 3; - return true; - } - - if (0 <= top-2 && stack[top-2].type == 3 && (stack[top-1].type == '+' || stack[top-1].type == '|') && stack[top].type == 3) { - token_t t = token_t(3, create_or_cell(module, stack[top-2].sig, stack[top].sig)); - stack.pop_back(); - stack.pop_back(); - stack.pop_back(); - stack.push_back(t); - return true; - } - - if (0 <= top-2 && stack[top-2].type == '(' && stack[top-1].type == 3 && stack[top].type == ')') { - token_t t = token_t(0, stack[top-1].sig); - stack.pop_back(); - stack.pop_back(); - stack.pop_back(); - stack.push_back(t); - return true; - } - - return false; -} - -static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr) -{ - const char *orig_expr = expr; - std::vector stack; - - while (*expr) - { - if (*expr == ' ' || *expr == '\t' || *expr == '\r' || *expr == '\n' || *expr == '"') { - expr++; - continue; - } - - token_t next_token(0); - if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|' || *expr == '&') - next_token = token_t(*(expr++)); - else - next_token = token_t(0, parse_func_identifier(module, expr)); - - while (parse_func_reduce(module, stack, next_token)) {} - stack.push_back(next_token); - } - - while (parse_func_reduce(module, stack, token_t('.'))) {} - -#if 0 - for (size_t i = 0; i < stack.size(); i++) - if (stack[i].type < 16) - log("%3d: %d %s\n", int(i), stack[i].type, log_signal(stack[i].sig)); - else - log("%3d: %c\n", int(i), stack[i].type); -#endif - - if (stack.size() != 1 || stack.back().type != 3) - log_error("Parser error in function expr `%s'.\n", orig_expr); - - return stack.back().sig; -} - -static void create_ff(RTLIL::Module *module, LibertyAst *node) -{ - RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0)))); - RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1)))); - - RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig; - bool clk_polarity = true, clear_polarity = true, preset_polarity = true; - - for (auto child : node->children) { - if (child->id == "clocked_on") - clk_sig = parse_func_expr(module, child->value.c_str()); - if (child->id == "next_state") - data_sig = parse_func_expr(module, child->value.c_str()); - if (child->id == "clear") - clear_sig = parse_func_expr(module, child->value.c_str()); - if (child->id == "preset") - preset_sig = parse_func_expr(module, child->value.c_str()); - } - - if (clk_sig.size() == 0 || data_sig.size() == 0) - log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", log_id(module->name)); - - for (bool rerun_invert_rollback = true; rerun_invert_rollback;) - { - rerun_invert_rollback = false; - - for (auto &it : module->cells_) { - if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clk_sig) { - clk_sig = it.second->getPort("\\A"); - clk_polarity = !clk_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) { - clear_sig = it.second->getPort("\\A"); - clear_polarity = !clear_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) { - preset_sig = it.second->getPort("\\A"); - preset_polarity = !preset_polarity; - rerun_invert_rollback = true; - } - } - } - - RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_"); - cell->setPort("\\A", iq_sig); - cell->setPort("\\Y", iqn_sig); - - cell = module->addCell(NEW_ID, ""); - cell->setPort("\\D", data_sig); - cell->setPort("\\Q", iq_sig); - cell->setPort("\\C", clk_sig); - - if (clear_sig.size() == 0 && preset_sig.size() == 0) { - cell->type = stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N'); - } - - if (clear_sig.size() == 1 && preset_sig.size() == 0) { - cell->type = stringf("$_DFF_%c%c0_", clk_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N'); - cell->setPort("\\R", clear_sig); - } - - if (clear_sig.size() == 0 && preset_sig.size() == 1) { - cell->type = stringf("$_DFF_%c%c1_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N'); - cell->setPort("\\R", preset_sig); - } - - if (clear_sig.size() == 1 && preset_sig.size() == 1) { - cell->type = stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N'); - cell->setPort("\\S", preset_sig); - cell->setPort("\\R", clear_sig); - } - - log_assert(!cell->type.empty()); -} - -static bool create_latch(RTLIL::Module *module, LibertyAst *node, bool flag_ignore_miss_data_latch) -{ - RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0)))); - RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1)))); - - RTLIL::SigSpec enable_sig, data_sig, clear_sig, preset_sig; - bool enable_polarity = true, clear_polarity = true, preset_polarity = true; - - for (auto child : node->children) { - if (child->id == "enable") - enable_sig = parse_func_expr(module, child->value.c_str()); - if (child->id == "data_in") - data_sig = parse_func_expr(module, child->value.c_str()); - if (child->id == "clear") - clear_sig = parse_func_expr(module, child->value.c_str()); - if (child->id == "preset") - preset_sig = parse_func_expr(module, child->value.c_str()); - } - - if (enable_sig.size() == 0 || data_sig.size() == 0) { - if (!flag_ignore_miss_data_latch) - log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name)); - else - log("Ignored latch cell %s with no data_in and/or enable attribute.\n", log_id(module->name)); - - return false; - } - - for (bool rerun_invert_rollback = true; rerun_invert_rollback;) - { - rerun_invert_rollback = false; - - for (auto &it : module->cells_) { - if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == enable_sig) { - enable_sig = it.second->getPort("\\A"); - enable_polarity = !enable_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) { - clear_sig = it.second->getPort("\\A"); - clear_polarity = !clear_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) { - preset_sig = it.second->getPort("\\A"); - preset_polarity = !preset_polarity; - rerun_invert_rollback = true; - } - } - } - - RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_"); - cell->setPort("\\A", iq_sig); - cell->setPort("\\Y", iqn_sig); - - if (clear_sig.size() == 1) - { - RTLIL::SigSpec clear_negative = clear_sig; - RTLIL::SigSpec clear_enable = clear_sig; - - if (clear_polarity == true || clear_polarity != enable_polarity) - { - RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_"); - inv->setPort("\\A", clear_sig); - inv->setPort("\\Y", module->addWire(NEW_ID)); - - if (clear_polarity == true) - clear_negative = inv->getPort("\\Y"); - if (clear_polarity != enable_polarity) - clear_enable = inv->getPort("\\Y"); - } - - RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_AND_"); - data_gate->setPort("\\A", data_sig); - data_gate->setPort("\\B", clear_negative); - data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID)); - - RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_"); - enable_gate->setPort("\\A", enable_sig); - enable_gate->setPort("\\B", clear_enable); - enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID)); - } - - if (preset_sig.size() == 1) - { - RTLIL::SigSpec preset_positive = preset_sig; - RTLIL::SigSpec preset_enable = preset_sig; - - if (preset_polarity == false || preset_polarity != enable_polarity) - { - RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_"); - inv->setPort("\\A", preset_sig); - inv->setPort("\\Y", module->addWire(NEW_ID)); - - if (preset_polarity == false) - preset_positive = inv->getPort("\\Y"); - if (preset_polarity != enable_polarity) - preset_enable = inv->getPort("\\Y"); - } - - RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_OR_"); - data_gate->setPort("\\A", data_sig); - data_gate->setPort("\\B", preset_positive); - data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID)); - - RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_"); - enable_gate->setPort("\\A", enable_sig); - enable_gate->setPort("\\B", preset_enable); - enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID)); - } - - cell = module->addCell(NEW_ID, stringf("$_DLATCH_%c_", enable_polarity ? 'P' : 'N')); - cell->setPort("\\D", data_sig); - cell->setPort("\\Q", iq_sig); - cell->setPort("\\E", enable_sig); - - return true; -} - -void parse_type_map(std::map> &type_map, LibertyAst *ast) -{ - for (auto type_node : ast->children) - { - if (type_node->id != "type" || type_node->args.size() != 1) - continue; - - std::string type_name = type_node->args.at(0); - int bit_width = -1, bit_from = -1, bit_to = -1; - bool upto = false; - - for (auto child : type_node->children) - { - if (child->id == "base_type" && child->value != "array") - goto next_type; - - if (child->id == "data_type" && child->value != "bit") - goto next_type; - - if (child->id == "bit_width") - bit_width = atoi(child->value.c_str()); - - if (child->id == "bit_from") - bit_from = atoi(child->value.c_str()); - - if (child->id == "bit_to") - bit_to = atoi(child->value.c_str()); - - if (child->id == "downto" && (child->value == "0" || child->value == "false" || child->value == "FALSE")) - upto = true; - } - - if (bit_width != (std::max(bit_from, bit_to) - std::min(bit_from, bit_to) + 1)) - log_error("Incompatible array type '%s': bit_width=%d, bit_from=%d, bit_to=%d.\n", - type_name.c_str(), bit_width, bit_from, bit_to); - - type_map[type_name] = std::tuple(bit_width, std::min(bit_from, bit_to), upto); - next_type:; - } -} - -struct LibertyFrontend : public Frontend { - LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_liberty [filename]\n"); - log("\n"); - log("Read cells from liberty file as modules into current design.\n"); - log("\n"); - log(" -lib\n"); - log(" only create empty blackbox modules\n"); - log("\n"); - log(" -nooverwrite\n"); - log(" ignore re-definitions of modules. (the default behavior is to\n"); - log(" create an error message if the existing module is not a blackbox\n"); - log(" module, and overwrite the existing module if it is a blackbox module.)\n"); - log("\n"); - log(" -overwrite\n"); - log(" overwrite existing modules with the same name\n"); - log("\n"); - log(" -ignore_miss_func\n"); - log(" ignore cells with missing function specification of outputs\n"); - log("\n"); - log(" -ignore_miss_dir\n"); - log(" ignore cells with a missing or invalid direction\n"); - log(" specification on a pin\n"); - log("\n"); - log(" -ignore_miss_data_latch\n"); - log(" ignore latches with missing data and/or enable pins\n"); - log("\n"); - log(" -setattr \n"); - log(" set the specified attribute (to the value 1) on all loaded modules\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - bool flag_lib = false; - bool flag_nooverwrite = false; - bool flag_overwrite = false; - bool flag_ignore_miss_func = false; - bool flag_ignore_miss_dir = false; - bool flag_ignore_miss_data_latch = false; - std::vector attributes; - - log_header(design, "Executing Liberty frontend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-lib") { - flag_lib = true; - continue; - } - if (arg == "-ignore_redef" || arg == "-nooverwrite") { - flag_nooverwrite = true; - flag_overwrite = false; - continue; - } - if (arg == "-overwrite") { - flag_nooverwrite = false; - flag_overwrite = true; - continue; - } - if (arg == "-ignore_miss_func") { - flag_ignore_miss_func = true; - continue; - } - if (arg == "-ignore_miss_dir") { - flag_ignore_miss_dir = true; - continue; - } - if (arg == "-ignore_miss_data_latch") { - flag_ignore_miss_data_latch = true; - continue; - } - if (arg == "-setattr" && argidx+1 < args.size()) { - attributes.push_back(RTLIL::escape_id(args[++argidx])); - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - LibertyParser parser(*f); - int cell_count = 0; - - std::map> global_type_map; - parse_type_map(global_type_map, parser.ast); - - for (auto cell : parser.ast->children) - { - if (cell->id != "cell" || cell->args.size() != 1) - continue; - - std::string cell_name = RTLIL::escape_id(cell->args.at(0)); - - if (design->has(cell_name)) { - Module *existing_mod = design->module(cell_name); - if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { - log_error("Re-definition of of cell/module %s!\n", log_id(cell_name)); - } else if (flag_nooverwrite) { - log("Ignoring re-definition of module %s.\n", log_id(cell_name)); - continue; - } else { - log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", log_id(cell_name)); - design->remove(existing_mod); - } - } - - // log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str()); - - std::map> type_map = global_type_map; - parse_type_map(type_map, cell); - - RTLIL::Module *module = new RTLIL::Module; - module->name = cell_name; - - if (flag_lib) - module->set_bool_attribute("\\blackbox"); - - for (auto &attr : attributes) - module->attributes[attr] = 1; - - for (auto node : cell->children) - { - if (node->id == "pin" && node->args.size() == 1) { - LibertyAst *dir = node->find("direction"); - if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal")) - { - if (!flag_ignore_miss_dir) - { - log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name)); - } else { - log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0).c_str()); - delete module; - goto skip_cell; - } - } - if (!flag_lib || dir->value != "internal") - module->addWire(RTLIL::escape_id(node->args.at(0))); - } - - if (node->id == "bus" && node->args.size() == 1) - { - if (!flag_lib) - log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name)); - - LibertyAst *dir = node->find("direction"); - - if (dir == nullptr) { - LibertyAst *pin = node->find("pin"); - if (pin != nullptr) - dir = pin->find("direction"); - } - - if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal")) - log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name)); - - if (dir->value == "internal") - continue; - - LibertyAst *bus_type_node = node->find("bus_type"); - - if (!bus_type_node || !type_map.count(bus_type_node->value)) - log_error("Unknown or unsupported type for bus interface %s on cell %s.\n", - node->args.at(0).c_str(), log_id(cell_name)); - - int bus_type_width = std::get<0>(type_map.at(bus_type_node->value)); - int bus_type_offset = std::get<1>(type_map.at(bus_type_node->value)); - bool bus_type_upto = std::get<2>(type_map.at(bus_type_node->value)); - - Wire *wire = module->addWire(RTLIL::escape_id(node->args.at(0)), bus_type_width); - wire->start_offset = bus_type_offset; - wire->upto = bus_type_upto; - - if (dir->value == "input" || dir->value == "inout") - wire->port_input = true; - - if (dir->value == "output" || dir->value == "inout") - wire->port_output = true; - } - } - - if (!flag_lib) - { - // some liberty files do not put ff/latch at the beginning of a cell - // try to find "ff" or "latch" and create FF/latch _before_ processing all other nodes - for (auto node : cell->children) - { - if (node->id == "ff" && node->args.size() == 2) - create_ff(module, node); - if (node->id == "latch" && node->args.size() == 2) - if (!create_latch(module, node, flag_ignore_miss_data_latch)) { - delete module; - goto skip_cell; - } - } - } - - for (auto node : cell->children) - { - if (node->id == "pin" && node->args.size() == 1) - { - LibertyAst *dir = node->find("direction"); - - if (flag_lib && dir->value == "internal") - continue; - - RTLIL::Wire *wire = module->wires_.at(RTLIL::escape_id(node->args.at(0))); - - if (dir && dir->value == "inout") { - wire->port_input = true; - wire->port_output = true; - } - - if (dir && dir->value == "input") { - wire->port_input = true; - continue; - } - - if (dir && dir->value == "output") - wire->port_output = true; - - if (flag_lib) - continue; - - LibertyAst *func = node->find("function"); - if (func == NULL) - { - if (!flag_ignore_miss_func) - { - log_error("Missing function on output %s of cell %s.\n", log_id(wire->name), log_id(module->name)); - } else { - log("Ignoring cell %s with missing function on output %s.\n", log_id(module->name), log_id(wire->name)); - delete module; - goto skip_cell; - } - } - - RTLIL::SigSpec out_sig = parse_func_expr(module, func->value.c_str()); - module->connect(RTLIL::SigSig(wire, out_sig)); - } - } - - module->fixup_ports(); - design->add(module); - cell_count++; -skip_cell:; - } - - log("Imported %d cell types from liberty file.\n", cell_count); - } -} LibertyFrontend; - -YOSYS_NAMESPACE_END - diff --git a/yosys/frontends/verific/Makefile.inc b/yosys/frontends/verific/Makefile.inc deleted file mode 100644 index 972f4f9f1..000000000 --- a/yosys/frontends/verific/Makefile.inc +++ /dev/null @@ -1,20 +0,0 @@ - -OBJS += frontends/verific/verific.o - -ifeq ($(ENABLE_VERIFIC),1) - -OBJS += frontends/verific/verificsva.o - -EXTRA_TARGETS += share/verific - -share/verific: - $(P) rm -rf share/verific.new - $(Q) mkdir -p share/verific.new - $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987 - $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993 - $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008 - $(Q) chmod -R a+rX share/verific.new - $(Q) mv share/verific.new share/verific - -endif - diff --git a/yosys/frontends/verific/README b/yosys/frontends/verific/README deleted file mode 100644 index 89584f2e8..000000000 --- a/yosys/frontends/verific/README +++ /dev/null @@ -1,33 +0,0 @@ - - -This directory contains Verific bindings for Yosys. -See http://www.verific.com/ for details. - - -Verific Features that should be enabled in your Verific library -=============================================================== - -database/DBCompileFlags.h: - DB_PRESERVE_INITIAL_VALUE - - -Testing Verific+Yosys+SymbiYosys for formal verification -======================================================== - -Install Yosys+Verific, SymbiYosys, and Yices2. Install instructions: -http://symbiyosys.readthedocs.io/en/latest/quickstart.html#installing - -Then run in the following command in this directory: - - sby -f example.sby - -This will generate approximately one page of text output. The last lines -should be something like this: - - SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0) - SBY [example] summary: Elapsed process time [H:MM:SS (secs)]: 0:00:00 (0) - SBY [example] summary: engine_0 (smtbmc yices) returned PASS for basecase - SBY [example] summary: engine_0 (smtbmc yices) returned PASS for induction - SBY [example] summary: successful proof by k-induction. - SBY [example] DONE (PASS, rc=0) - diff --git a/yosys/frontends/verific/example.sby b/yosys/frontends/verific/example.sby deleted file mode 100644 index ffbf33cab..000000000 --- a/yosys/frontends/verific/example.sby +++ /dev/null @@ -1,16 +0,0 @@ -# Simple SymbiYosys example job utilizing Verific - -[options] -mode prove -depth 10 - -[engines] -smtbmc yices - -[script] -verific -sv example.sv -verific -import top -prep -top top - -[files] -example.sv diff --git a/yosys/frontends/verific/example.sv b/yosys/frontends/verific/example.sv deleted file mode 100644 index 21a5d42c8..000000000 --- a/yosys/frontends/verific/example.sv +++ /dev/null @@ -1,18 +0,0 @@ -module top ( - input clk, rst, - output reg [3:0] cnt -); - initial cnt = 0; - - always @(posedge clk) begin - if (rst) - cnt <= 0; - else - cnt <= cnt + 4'd 1; - end - - always @(posedge clk) begin - assume (cnt != 10); - assert (cnt != 15); - end -endmodule diff --git a/yosys/frontends/verific/verific.cc b/yosys/frontends/verific/verific.cc deleted file mode 100644 index 2bf99e58e..000000000 --- a/yosys/frontends/verific/verific.cc +++ /dev/null @@ -1,2562 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" -#include "kernel/log.h" -#include -#include -#include - -#ifndef _WIN32 -# include -# include -#endif - -#include "frontends/verific/verific.h" - -USING_YOSYS_NAMESPACE - -#ifdef YOSYS_ENABLE_VERIFIC - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Woverloaded-virtual" -#endif - -#include "veri_file.h" -#include "vhdl_file.h" -#include "hier_tree.h" -#include "VeriModule.h" -#include "VeriWrite.h" -#include "VhdlUnits.h" -#include "VeriLibrary.h" - -#ifndef SYMBIOTIC_VERIFIC_API_VERSION -# error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific." -#endif - -#if SYMBIOTIC_VERIFIC_API_VERSION < 1 -# error "Please update your version of Symbiotic EDA flavored Verific." -#endif - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#ifdef VERIFIC_NAMESPACE -using namespace Verific; -#endif - -#endif - -#ifdef YOSYS_ENABLE_VERIFIC -YOSYS_NAMESPACE_BEGIN - -int verific_verbose; -bool verific_import_pending; -string verific_error_msg; -int verific_sva_fsm_limit; - -vector verific_incdirs, verific_libdirs; - -void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args) -{ - string message_prefix = stringf("VERIFIC-%s [%s] ", - msg_type == VERIFIC_NONE ? "NONE" : - msg_type == VERIFIC_ERROR ? "ERROR" : - msg_type == VERIFIC_WARNING ? "WARNING" : - msg_type == VERIFIC_IGNORE ? "IGNORE" : - msg_type == VERIFIC_INFO ? "INFO" : - msg_type == VERIFIC_COMMENT ? "COMMENT" : - msg_type == VERIFIC_PROGRAM_ERROR ? "PROGRAM_ERROR" : "UNKNOWN", message_id); - - string message = linefile ? stringf("%s:%d: ", LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile)) : ""; - message += vstringf(msg, args); - - if (msg_type == VERIFIC_ERROR || msg_type == VERIFIC_WARNING || msg_type == VERIFIC_PROGRAM_ERROR) - log_warning_noprefix("%s%s\n", message_prefix.c_str(), message.c_str()); - else - log("%s%s\n", message_prefix.c_str(), message.c_str()); - - if (verific_error_msg.empty() && (msg_type == VERIFIC_ERROR || msg_type == VERIFIC_PROGRAM_ERROR)) - verific_error_msg = message; -} - -string get_full_netlist_name(Netlist *nl) -{ - if (nl->NumOfRefs() == 1) { - Instance *inst = (Instance*)nl->GetReferences()->GetLast(); - return get_full_netlist_name(inst->Owner()) + "." + inst->Name(); - } - - return nl->CellBaseName(); -} - -// ================================================================== - -VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover) : - mode_gates(mode_gates), mode_keep(mode_keep), mode_nosva(mode_nosva), - mode_names(mode_names), mode_verific(mode_verific), mode_autocover(mode_autocover) -{ -} - -RTLIL::SigBit VerificImporter::net_map_at(Net *net) -{ - if (net->IsExternalTo(netlist)) - log_error("Found external reference to '%s.%s' in netlist '%s', please use -flatten or -extnets.\n", - get_full_netlist_name(net->Owner()).c_str(), net->Name(), get_full_netlist_name(netlist).c_str()); - - return net_map.at(net); -} - -bool is_blackbox(Netlist *nl) -{ - if (nl->IsBlackBox()) - return true; - - const char *attr = nl->GetAttValue("blackbox"); - if (attr != nullptr && strcmp(attr, "0")) - return true; - - return false; -} - -RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) -{ - std::string s = stringf("$verific$%s", obj->Name()); - if (obj->Linefile()) - s += stringf("$%s:%d", Verific::LineFile::GetFileName(obj->Linefile()), Verific::LineFile::GetLineNo(obj->Linefile())); - s += stringf("$%d", autoidx++); - return s; -} - -void VerificImporter::import_attributes(dict &attributes, DesignObj *obj) -{ - MapIter mi; - Att *attr; - - if (obj->Linefile()) - attributes["\\src"] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); - - // FIXME: Parse numeric attributes - FOREACH_ATTRIBUTE(obj, mi, attr) { - if (attr->Key()[0] == ' ' || attr->Value() == nullptr) - continue; - attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(std::string(attr->Value())); - } -} - -RTLIL::SigSpec VerificImporter::operatorInput(Instance *inst) -{ - RTLIL::SigSpec sig; - for (int i = int(inst->InputSize())-1; i >= 0; i--) - if (inst->GetInputBit(i)) - sig.append(net_map_at(inst->GetInputBit(i))); - else - sig.append(RTLIL::State::Sz); - return sig; -} - -RTLIL::SigSpec VerificImporter::operatorInput1(Instance *inst) -{ - RTLIL::SigSpec sig; - for (int i = int(inst->Input1Size())-1; i >= 0; i--) - if (inst->GetInput1Bit(i)) - sig.append(net_map_at(inst->GetInput1Bit(i))); - else - sig.append(RTLIL::State::Sz); - return sig; -} - -RTLIL::SigSpec VerificImporter::operatorInput2(Instance *inst) -{ - RTLIL::SigSpec sig; - for (int i = int(inst->Input2Size())-1; i >= 0; i--) - if (inst->GetInput2Bit(i)) - sig.append(net_map_at(inst->GetInput2Bit(i))); - else - sig.append(RTLIL::State::Sz); - return sig; -} - -RTLIL::SigSpec VerificImporter::operatorInport(Instance *inst, const char *portname) -{ - PortBus *portbus = inst->View()->GetPortBus(portname); - if (portbus) { - RTLIL::SigSpec sig; - for (unsigned i = 0; i < portbus->Size(); i++) { - Net *net = inst->GetNet(portbus->ElementAtIndex(i)); - if (net) { - if (net->IsGnd()) - sig.append(RTLIL::State::S0); - else if (net->IsPwr()) - sig.append(RTLIL::State::S1); - else - sig.append(net_map_at(net)); - } else - sig.append(RTLIL::State::Sz); - } - return sig; - } else { - Port *port = inst->View()->GetPort(portname); - log_assert(port != NULL); - Net *net = inst->GetNet(port); - return net_map_at(net); - } -} - -RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool *any_all_nets) -{ - RTLIL::SigSpec sig; - RTLIL::Wire *dummy_wire = NULL; - for (int i = int(inst->OutputSize())-1; i >= 0; i--) - if (inst->GetOutputBit(i) && (!any_all_nets || !any_all_nets->count(inst->GetOutputBit(i)))) { - sig.append(net_map_at(inst->GetOutputBit(i))); - dummy_wire = NULL; - } else { - if (dummy_wire == NULL) - dummy_wire = module->addWire(new_verific_id(inst)); - else - dummy_wire->width++; - sig.append(RTLIL::SigSpec(dummy_wire, dummy_wire->width - 1)); - } - return sig; -} - -bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdString inst_name) -{ - if (inst->Type() == PRIM_AND) { - module->addAndGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_NAND) { - RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); - module->addAndGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); - module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_OR) { - module->addOrGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_NOR) { - RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); - module->addOrGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); - module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_XOR) { - module->addXorGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_XNOR) { - module->addXnorGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_BUF) { - auto outnet = inst->GetOutput(); - if (!any_all_nets.count(outnet)) - module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(outnet)); - return true; - } - - if (inst->Type() == PRIM_INV) { - module->addNotGate(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_MUX) { - module->addMuxGate(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_TRI) { - module->addMuxGate(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); - return true; - } - - if (inst->Type() == PRIM_FADD) - { - RTLIL::SigSpec a = net_map_at(inst->GetInput1()), b = net_map_at(inst->GetInput2()), c = net_map_at(inst->GetCin()); - RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(new_verific_id(inst)); - RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst)); - RTLIL::SigSpec tmp1 = module->addWire(new_verific_id(inst)); - RTLIL::SigSpec tmp2 = module->addWire(new_verific_id(inst)); - RTLIL::SigSpec tmp3 = module->addWire(new_verific_id(inst)); - module->addXorGate(new_verific_id(inst), a, b, tmp1); - module->addXorGate(inst_name, tmp1, c, y); - module->addAndGate(new_verific_id(inst), tmp1, c, tmp2); - module->addAndGate(new_verific_id(inst), a, b, tmp3); - module->addOrGate(new_verific_id(inst), tmp2, tmp3, x); - return true; - } - - if (inst->Type() == PRIM_DFFRS) - { - VerificClocking clocking(this, inst->GetClock()); - log_assert(clocking.disable_sig == State::S0); - log_assert(clocking.body_net == nullptr); - - if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) - clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); - else if (inst->GetSet()->IsGnd()) - clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), State::S0); - else if (inst->GetReset()->IsGnd()) - clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), State::S1); - else - clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), - net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); - return true; - } - - return false; -} - -bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdString inst_name) -{ - RTLIL::Cell *cell = nullptr; - - if (inst->Type() == PRIM_AND) { - cell = module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_NAND) { - RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); - cell = module->addAnd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); - import_attributes(cell->attributes, inst); - cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_OR) { - cell = module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_NOR) { - RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); - cell = module->addOr(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); - import_attributes(cell->attributes, inst); - cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_XOR) { - cell = module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_XNOR) { - cell = module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_INV) { - cell = module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_MUX) { - cell = module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_TRI) { - cell = module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_FADD) - { - RTLIL::SigSpec a_plus_b = module->addWire(new_verific_id(inst), 2); - RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst)); - if (inst->GetCout()) - y.append(net_map_at(inst->GetCout())); - cell = module->addAdd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b); - import_attributes(cell->attributes, inst); - cell = module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_DFFRS) - { - VerificClocking clocking(this, inst->GetClock()); - log_assert(clocking.disable_sig == State::S0); - log_assert(clocking.body_net == nullptr); - - if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) - cell = clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); - else if (inst->GetSet()->IsGnd()) - cell = clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0); - else if (inst->GetReset()->IsGnd()) - cell = clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1); - else - cell = clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), - net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == PRIM_DLATCHRS) - { - if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) - cell = module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); - else - cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), - net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - #define IN operatorInput(inst) - #define IN1 operatorInput1(inst) - #define IN2 operatorInput2(inst) - #define OUT operatorOutput(inst) - #define FILTERED_OUT operatorOutput(inst, &any_all_nets) - #define SIGNED inst->View()->IsSigned() - - if (inst->Type() == OPER_ADDER) { - RTLIL::SigSpec out = OUT; - if (inst->GetCout() != NULL) - out.append(net_map_at(inst->GetCout())); - if (inst->GetCin()->IsGnd()) { - cell = module->addAdd(inst_name, IN1, IN2, out, SIGNED); - import_attributes(cell->attributes, inst); - } else { - RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst), GetSize(out)); - cell = module->addAdd(new_verific_id(inst), IN1, IN2, tmp, SIGNED); - import_attributes(cell->attributes, inst); - cell = module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false); - import_attributes(cell->attributes, inst); - } - return true; - } - - if (inst->Type() == OPER_MULTIPLIER) { - cell = module->addMul(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_DIVIDER) { - cell = module->addDiv(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_MODULO) { - cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_REMAINDER) { - cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_SHIFT_LEFT) { - cell = module->addShl(inst_name, IN1, IN2, OUT, false); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_ENABLED_DECODER) { - RTLIL::SigSpec vec; - vec.append(net_map_at(inst->GetControl())); - for (unsigned i = 1; i < inst->OutputSize(); i++) { - vec.append(RTLIL::State::S0); - } - cell = module->addShl(inst_name, vec, IN, OUT, false); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_DECODER) { - RTLIL::SigSpec vec; - vec.append(RTLIL::State::S1); - for (unsigned i = 1; i < inst->OutputSize(); i++) { - vec.append(RTLIL::State::S0); - } - cell = module->addShl(inst_name, vec, IN, OUT, false); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_SHIFT_RIGHT) { - Net *net_cin = inst->GetCin(); - Net *net_a_msb = inst->GetInput1Bit(0); - if (net_cin->IsGnd()) - cell = module->addShr(inst_name, IN1, IN2, OUT, false); - else if (net_cin == net_a_msb) - cell = module->addSshr(inst_name, IN1, IN2, OUT, true); - else - log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name()); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_REDUCE_AND) { - cell = module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_REDUCE_OR) { - cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_REDUCE_XOR) { - cell = module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_REDUCE_XNOR) { - cell = module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_REDUCE_NOR) { - SigSpec t = module->ReduceOr(new_verific_id(inst), IN, SIGNED); - cell = module->addNot(inst_name, t, net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_LESSTHAN) { - Net *net_cin = inst->GetCin(); - if (net_cin->IsGnd()) - cell = module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); - else if (net_cin->IsPwr()) - cell = module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); - else - log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name()); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_AND) { - cell = module->addAnd(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_OR) { - cell = module->addOr(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_XOR) { - cell = module->addXor(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_XNOR) { - cell = module->addXnor(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_BUF) { - cell = module->addPos(inst_name, IN, FILTERED_OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_INV) { - cell = module->addNot(inst_name, IN, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_MINUS) { - cell = module->addSub(inst_name, IN1, IN2, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_UMINUS) { - cell = module->addNeg(inst_name, IN, OUT, SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_EQUAL) { - cell = module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_NEQUAL) { - cell = module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_MUX) { - cell = module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_NTO1MUX) { - cell = module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_NTO1MUX) - { - SigSpec data = IN2, out = OUT; - - int wordsize_bits = ceil_log2(GetSize(out)); - int wordsize = 1 << wordsize_bits; - - SigSpec sel = {IN1, SigSpec(State::S0, wordsize_bits)}; - - SigSpec padded_data; - for (int i = 0; i < GetSize(data); i += GetSize(out)) { - SigSpec d = data.extract(i, GetSize(out)); - d.extend_u0(wordsize); - padded_data.append(d); - } - - cell = module->addShr(inst_name, padded_data, sel, out); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_SELECTOR) - { - cell = module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput())); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_SELECTOR) - { - SigSpec out = OUT; - cell = module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_TRI) { - cell = module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT); - import_attributes(cell->attributes, inst); - return true; - } - - if (inst->Type() == OPER_WIDE_DFFRS) - { - VerificClocking clocking(this, inst->GetClock()); - log_assert(clocking.disable_sig == State::S0); - log_assert(clocking.body_net == nullptr); - - RTLIL::SigSpec sig_set = operatorInport(inst, "set"); - RTLIL::SigSpec sig_reset = operatorInport(inst, "reset"); - - if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool()) - cell = clocking.addDff(inst_name, IN, OUT); - else - cell = clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT); - import_attributes(cell->attributes, inst); - - return true; - } - - #undef IN - #undef IN1 - #undef IN2 - #undef OUT - #undef SIGNED - - return false; -} - -void VerificImporter::merge_past_ffs_clock(pool &candidates, SigBit clock, bool clock_pol) -{ - bool keep_running = true; - SigMap sigmap; - - while (keep_running) - { - keep_running = false; - - dict> dbits_db; - SigSpec dbits; - - for (auto cell : candidates) { - SigBit bit = sigmap(cell->getPort("\\D")); - dbits_db[bit].insert(cell); - dbits.append(bit); - } - - dbits.sort_and_unify(); - - for (auto chunk : dbits.chunks()) - { - SigSpec sig_d = chunk; - - if (chunk.wire == nullptr || GetSize(sig_d) == 1) - continue; - - SigSpec sig_q = module->addWire(NEW_ID, GetSize(sig_d)); - RTLIL::Cell *new_ff = module->addDff(NEW_ID, clock, sig_d, sig_q, clock_pol); - - if (verific_verbose) - log(" merging single-bit past_ffs into new %d-bit ff %s.\n", GetSize(sig_d), log_id(new_ff)); - - for (int i = 0; i < GetSize(sig_d); i++) - for (auto old_ff : dbits_db[sig_d[i]]) - { - if (verific_verbose) - log(" replacing old ff %s on bit %d.\n", log_id(old_ff), i); - - SigBit old_q = old_ff->getPort("\\Q"); - SigBit new_q = sig_q[i]; - - sigmap.add(old_q, new_q); - module->connect(old_q, new_q); - candidates.erase(old_ff); - module->remove(old_ff); - keep_running = true; - } - } - } -} - -void VerificImporter::merge_past_ffs(pool &candidates) -{ - dict, pool> database; - - for (auto cell : candidates) - { - SigBit clock = cell->getPort("\\CLK"); - bool clock_pol = cell->getParam("\\CLK_POLARITY").as_bool(); - database[make_pair(clock, int(clock_pol))].insert(cell); - } - - for (auto it : database) - merge_past_ffs_clock(it.second, it.first.first, it.first.second); -} - -void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set &nl_todo) -{ - std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name(); - std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name); - - netlist = nl; - - if (design->has(module_name)) { - if (!nl->IsOperator() && !is_blackbox(nl)) - log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str()); - return; - } - - module = new RTLIL::Module; - module->name = module_name; - design->add(module); - - if (is_blackbox(nl)) { - log("Importing blackbox module %s.\n", RTLIL::id2cstr(module->name)); - module->set_bool_attribute("\\blackbox"); - } else { - log("Importing module %s.\n", RTLIL::id2cstr(module->name)); - } - - SetIter si; - MapIter mi, mi2; - Port *port; - PortBus *portbus; - Net *net; - NetBus *netbus; - Instance *inst; - PortRef *pr; - - FOREACH_PORT_OF_NETLIST(nl, mi, port) - { - if (port->Bus()) - continue; - - if (verific_verbose) - log(" importing port %s.\n", port->Name()); - - RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name())); - import_attributes(wire->attributes, port); - - wire->port_id = nl->IndexOf(port) + 1; - - if (port->GetDir() == DIR_INOUT || port->GetDir() == DIR_IN) - wire->port_input = true; - if (port->GetDir() == DIR_INOUT || port->GetDir() == DIR_OUT) - wire->port_output = true; - - if (port->GetNet()) { - net = port->GetNet(); - if (net_map.count(net) == 0) - net_map[net] = wire; - else if (wire->port_input) - module->connect(net_map_at(net), wire); - else - module->connect(wire, net_map_at(net)); - } - } - - FOREACH_PORTBUS_OF_NETLIST(nl, mi, portbus) - { - if (verific_verbose) - log(" importing portbus %s.\n", portbus->Name()); - - RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size()); - wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex()); - import_attributes(wire->attributes, portbus); - - if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN) - wire->port_input = true; - if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_OUT) - wire->port_output = true; - - for (int i = portbus->LeftIndex();; i += portbus->IsUp() ? +1 : -1) { - if (portbus->ElementAtIndex(i) && portbus->ElementAtIndex(i)->GetNet()) { - net = portbus->ElementAtIndex(i)->GetNet(); - RTLIL::SigBit bit(wire, i - wire->start_offset); - if (net_map.count(net) == 0) - net_map[net] = bit; - else if (wire->port_input) - module->connect(net_map_at(net), bit); - else - module->connect(bit, net_map_at(net)); - } - if (i == portbus->RightIndex()) - break; - } - } - - module->fixup_ports(); - - dict init_nets; - pool anyconst_nets, anyseq_nets; - pool allconst_nets, allseq_nets; - any_all_nets.clear(); - - FOREACH_NET_OF_NETLIST(nl, mi, net) - { - if (net->IsRamNet()) - { - RTLIL::Memory *memory = new RTLIL::Memory; - memory->name = RTLIL::escape_id(net->Name()); - log_assert(module->count_id(memory->name) == 0); - module->memories[memory->name] = memory; - - int number_of_bits = net->Size(); - int bits_in_word = number_of_bits; - FOREACH_PORTREF_OF_NET(net, si, pr) { - if (pr->GetInst()->Type() == OPER_READ_PORT) { - bits_in_word = min(bits_in_word, pr->GetInst()->OutputSize()); - continue; - } - if (pr->GetInst()->Type() == OPER_WRITE_PORT || pr->GetInst()->Type() == OPER_CLOCKED_WRITE_PORT) { - bits_in_word = min(bits_in_word, pr->GetInst()->Input2Size()); - continue; - } - log_error("Verific RamNet %s is connected to unsupported instance type %s (%s).\n", - net->Name(), pr->GetInst()->View()->Owner()->Name(), pr->GetInst()->Name()); - } - - memory->width = bits_in_word; - memory->size = number_of_bits / bits_in_word; - - const char *ascii_initdata = net->GetWideInitialValue(); - if (ascii_initdata) { - while (*ascii_initdata != 0 && *ascii_initdata != '\'') - ascii_initdata++; - if (*ascii_initdata == '\'') - ascii_initdata++; - if (*ascii_initdata != 0) { - log_assert(*ascii_initdata == 'b'); - ascii_initdata++; - } - for (int word_idx = 0; word_idx < memory->size; word_idx++) { - Const initval = Const(State::Sx, memory->width); - bool initval_valid = false; - for (int bit_idx = memory->width-1; bit_idx >= 0; bit_idx--) { - if (*ascii_initdata == 0) - break; - if (*ascii_initdata == '0' || *ascii_initdata == '1') { - initval[bit_idx] = (*ascii_initdata == '0') ? State::S0 : State::S1; - initval_valid = true; - } - ascii_initdata++; - } - if (initval_valid) { - RTLIL::Cell *cell = module->addCell(new_verific_id(net), "$meminit"); - cell->parameters["\\WORDS"] = 1; - if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound()) - cell->setPort("\\ADDR", word_idx); - else - cell->setPort("\\ADDR", memory->size - word_idx - 1); - cell->setPort("\\DATA", initval); - cell->parameters["\\MEMID"] = RTLIL::Const(memory->name.str()); - cell->parameters["\\ABITS"] = 32; - cell->parameters["\\WIDTH"] = memory->width; - cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1); - } - } - } - continue; - } - - if (net->GetInitialValue()) - init_nets[net] = net->GetInitialValue(); - - const char *rand_const_attr = net->GetAttValue(" rand_const"); - const char *rand_attr = net->GetAttValue(" rand"); - - const char *anyconst_attr = net->GetAttValue("anyconst"); - const char *anyseq_attr = net->GetAttValue("anyseq"); - - const char *allconst_attr = net->GetAttValue("allconst"); - const char *allseq_attr = net->GetAttValue("allseq"); - - if (rand_const_attr != nullptr && (!strcmp(rand_const_attr, "1") || !strcmp(rand_const_attr, "'1'"))) { - anyconst_nets.insert(net); - any_all_nets.insert(net); - } - else if (rand_attr != nullptr && (!strcmp(rand_attr, "1") || !strcmp(rand_attr, "'1'"))) { - anyseq_nets.insert(net); - any_all_nets.insert(net); - } - else if (anyconst_attr != nullptr && (!strcmp(anyconst_attr, "1") || !strcmp(anyconst_attr, "'1'"))) { - anyconst_nets.insert(net); - any_all_nets.insert(net); - } - else if (anyseq_attr != nullptr && (!strcmp(anyseq_attr, "1") || !strcmp(anyseq_attr, "'1'"))) { - anyseq_nets.insert(net); - any_all_nets.insert(net); - } - else if (allconst_attr != nullptr && (!strcmp(allconst_attr, "1") || !strcmp(allconst_attr, "'1'"))) { - allconst_nets.insert(net); - any_all_nets.insert(net); - } - else if (allseq_attr != nullptr && (!strcmp(allseq_attr, "1") || !strcmp(allseq_attr, "'1'"))) { - allseq_nets.insert(net); - any_all_nets.insert(net); - } - - if (net_map.count(net)) { - if (verific_verbose) - log(" skipping net %s.\n", net->Name()); - continue; - } - - if (net->Bus()) - continue; - - RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : new_verific_id(net)); - - if (verific_verbose) - 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); - - net_map[net] = wire; - } - - FOREACH_NETBUS_OF_NETLIST(nl, mi, netbus) - { - bool found_new_net = false; - for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) { - net = netbus->ElementAtIndex(i); - if (net_map.count(net) == 0) - found_new_net = true; - if (i == netbus->RightIndex()) - break; - } - - if (found_new_net) - { - RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : new_verific_id(netbus)); - - if (verific_verbose) - log(" importing netbus %s as %s.\n", netbus->Name(), log_id(wire_name)); - - RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size()); - wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex()); - import_attributes(wire->attributes, netbus); - - RTLIL::Const initval = Const(State::Sx, GetSize(wire)); - bool initval_valid = false; - - for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) - { - if (netbus->ElementAtIndex(i)) - { - int bitidx = i - wire->start_offset; - net = netbus->ElementAtIndex(i); - RTLIL::SigBit bit(wire, bitidx); - - if (init_nets.count(net)) { - if (init_nets.at(net) == '0') - initval.bits.at(bitidx) = State::S0; - if (init_nets.at(net) == '1') - initval.bits.at(bitidx) = State::S1; - initval_valid = true; - init_nets.erase(net); - } - - if (net_map.count(net) == 0) - net_map[net] = bit; - else - module->connect(bit, net_map_at(net)); - } - - if (i == netbus->RightIndex()) - break; - } - - if (initval_valid) - wire->attributes["\\init"] = initval; - } - else - { - if (verific_verbose) - log(" skipping netbus %s.\n", netbus->Name()); - } - - SigSpec anyconst_sig; - SigSpec anyseq_sig; - SigSpec allconst_sig; - SigSpec allseq_sig; - - for (int i = netbus->RightIndex();; i += netbus->IsUp() ? -1 : +1) { - net = netbus->ElementAtIndex(i); - if (net != nullptr && anyconst_nets.count(net)) { - anyconst_sig.append(net_map_at(net)); - anyconst_nets.erase(net); - } - if (net != nullptr && anyseq_nets.count(net)) { - anyseq_sig.append(net_map_at(net)); - anyseq_nets.erase(net); - } - if (net != nullptr && allconst_nets.count(net)) { - allconst_sig.append(net_map_at(net)); - allconst_nets.erase(net); - } - if (net != nullptr && allseq_nets.count(net)) { - allseq_sig.append(net_map_at(net)); - allseq_nets.erase(net); - } - if (i == netbus->LeftIndex()) - break; - } - - if (GetSize(anyconst_sig)) - module->connect(anyconst_sig, module->Anyconst(new_verific_id(netbus), GetSize(anyconst_sig))); - - if (GetSize(anyseq_sig)) - module->connect(anyseq_sig, module->Anyseq(new_verific_id(netbus), GetSize(anyseq_sig))); - - if (GetSize(allconst_sig)) - module->connect(allconst_sig, module->Allconst(new_verific_id(netbus), GetSize(allconst_sig))); - - if (GetSize(allseq_sig)) - module->connect(allseq_sig, module->Allseq(new_verific_id(netbus), GetSize(allseq_sig))); - } - - for (auto it : init_nets) - { - Const initval; - SigBit bit = net_map_at(it.first); - log_assert(bit.wire); - - if (bit.wire->attributes.count("\\init")) - initval = bit.wire->attributes.at("\\init"); - - while (GetSize(initval) < GetSize(bit.wire)) - initval.bits.push_back(State::Sx); - - if (it.second == '0') - initval.bits.at(bit.offset) = State::S0; - if (it.second == '1') - initval.bits.at(bit.offset) = State::S1; - - bit.wire->attributes["\\init"] = initval; - } - - for (auto net : anyconst_nets) - module->connect(net_map_at(net), module->Anyconst(new_verific_id(net))); - - for (auto net : anyseq_nets) - module->connect(net_map_at(net), module->Anyseq(new_verific_id(net))); - - pool sva_asserts; - pool sva_assumes; - pool sva_covers; - pool sva_triggers; - - pool past_ffs; - - FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst) - { - RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : new_verific_id(inst)); - - if (verific_verbose) - log(" importing cell %s (%s) as %s.\n", inst->Name(), inst->View()->Owner()->Name(), log_id(inst_name)); - - if (mode_verific) - goto import_verific_cells; - - if (inst->Type() == PRIM_PWR) { - module->connect(net_map_at(inst->GetOutput()), RTLIL::State::S1); - continue; - } - - if (inst->Type() == PRIM_GND) { - module->connect(net_map_at(inst->GetOutput()), RTLIL::State::S0); - continue; - } - - if (inst->Type() == PRIM_BUF) { - auto outnet = inst->GetOutput(); - if (!any_all_nets.count(outnet)) - module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(outnet)); - continue; - } - - if (inst->Type() == PRIM_X) { - module->connect(net_map_at(inst->GetOutput()), RTLIL::State::Sx); - continue; - } - - if (inst->Type() == PRIM_Z) { - module->connect(net_map_at(inst->GetOutput()), RTLIL::State::Sz); - continue; - } - - if (inst->Type() == OPER_READ_PORT) - { - RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetInput()->Name())); - int numchunks = int(inst->OutputSize()) / memory->width; - int chunksbits = ceil_log2(numchunks); - - if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0) - log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); - - for (int i = 0; i < numchunks; i++) - { - RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; - RTLIL::SigSpec data = operatorOutput(inst).extract(i * memory->width, memory->width); - - RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : - RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memrd"); - cell->parameters["\\MEMID"] = memory->name.str(); - cell->parameters["\\CLK_ENABLE"] = false; - cell->parameters["\\CLK_POLARITY"] = true; - cell->parameters["\\TRANSPARENT"] = false; - cell->parameters["\\ABITS"] = GetSize(addr); - cell->parameters["\\WIDTH"] = GetSize(data); - cell->setPort("\\CLK", RTLIL::State::Sx); - cell->setPort("\\EN", RTLIL::State::Sx); - cell->setPort("\\ADDR", addr); - cell->setPort("\\DATA", data); - } - continue; - } - - if (inst->Type() == OPER_WRITE_PORT || inst->Type() == OPER_CLOCKED_WRITE_PORT) - { - RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name())); - int numchunks = int(inst->Input2Size()) / memory->width; - int chunksbits = ceil_log2(numchunks); - - if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0) - log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name()); - - for (int i = 0; i < numchunks; i++) - { - RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; - RTLIL::SigSpec data = operatorInput2(inst).extract(i * memory->width, memory->width); - - RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : - RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memwr"); - cell->parameters["\\MEMID"] = memory->name.str(); - cell->parameters["\\CLK_ENABLE"] = false; - cell->parameters["\\CLK_POLARITY"] = true; - cell->parameters["\\PRIORITY"] = 0; - cell->parameters["\\ABITS"] = GetSize(addr); - cell->parameters["\\WIDTH"] = GetSize(data); - cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data))); - cell->setPort("\\CLK", RTLIL::State::S0); - cell->setPort("\\ADDR", addr); - cell->setPort("\\DATA", data); - - if (inst->Type() == OPER_CLOCKED_WRITE_PORT) { - cell->parameters["\\CLK_ENABLE"] = true; - cell->setPort("\\CLK", net_map_at(inst->GetClock())); - } - } - continue; - } - - if (!mode_gates) { - if (import_netlist_instance_cells(inst, inst_name)) - continue; - if (inst->IsOperator() && !verific_sva_prims.count(inst->Type())) - log_warning("Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name()); - } else { - if (import_netlist_instance_gates(inst, inst_name)) - continue; - } - - if (inst->Type() == PRIM_SVA_ASSERT || inst->Type() == PRIM_SVA_IMMEDIATE_ASSERT) - sva_asserts.insert(inst); - - if (inst->Type() == PRIM_SVA_ASSUME || inst->Type() == PRIM_SVA_IMMEDIATE_ASSUME) - sva_assumes.insert(inst); - - if (inst->Type() == PRIM_SVA_COVER || inst->Type() == PRIM_SVA_IMMEDIATE_COVER) - sva_covers.insert(inst); - - if (inst->Type() == PRIM_SVA_TRIGGERED) - sva_triggers.insert(inst); - - if (inst->Type() == OPER_SVA_STABLE) - { - VerificClocking clocking(this, inst->GetInput2Bit(0)); - log_assert(clocking.disable_sig == State::S0); - log_assert(clocking.body_net == nullptr); - - log_assert(inst->Input1Size() == inst->OutputSize()); - - SigSpec sig_d, sig_q, sig_o; - sig_q = module->addWire(new_verific_id(inst), inst->Input1Size()); - - for (int i = int(inst->Input1Size())-1; i >= 0; i--){ - sig_d.append(net_map_at(inst->GetInput1Bit(i))); - sig_o.append(net_map_at(inst->GetOutputBit(i))); - } - - if (verific_verbose) { - log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", - log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig)); - log(" XNOR with A=%s, B=%s, Y=%s.\n", - log_signal(sig_d), log_signal(sig_q), log_signal(sig_o)); - } - - clocking.addDff(new_verific_id(inst), sig_d, sig_q); - module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o); - - if (!mode_keep) - continue; - } - - if (inst->Type() == PRIM_SVA_STABLE) - { - VerificClocking clocking(this, inst->GetInput2()); - log_assert(clocking.disable_sig == State::S0); - log_assert(clocking.body_net == nullptr); - - SigSpec sig_d = net_map_at(inst->GetInput1()); - SigSpec sig_o = net_map_at(inst->GetOutput()); - SigSpec sig_q = module->addWire(new_verific_id(inst)); - - if (verific_verbose) { - log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", - log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig)); - log(" XNOR with A=%s, B=%s, Y=%s.\n", - log_signal(sig_d), log_signal(sig_q), log_signal(sig_o)); - } - - clocking.addDff(new_verific_id(inst), sig_d, sig_q); - module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o); - - if (!mode_keep) - continue; - } - - if (inst->Type() == PRIM_SVA_PAST) - { - VerificClocking clocking(this, inst->GetInput2()); - log_assert(clocking.disable_sig == State::S0); - log_assert(clocking.body_net == nullptr); - - SigBit sig_d = net_map_at(inst->GetInput1()); - SigBit sig_q = net_map_at(inst->GetOutput()); - - if (verific_verbose) - log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", - log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig)); - - past_ffs.insert(clocking.addDff(new_verific_id(inst), sig_d, sig_q)); - - if (!mode_keep) - continue; - } - - if ((inst->Type() == PRIM_SVA_ROSE || inst->Type() == PRIM_SVA_FELL)) - { - VerificClocking clocking(this, inst->GetInput2()); - log_assert(clocking.disable_sig == State::S0); - log_assert(clocking.body_net == nullptr); - - SigBit sig_d = net_map_at(inst->GetInput1()); - SigBit sig_o = net_map_at(inst->GetOutput()); - SigBit sig_q = module->addWire(new_verific_id(inst)); - - if (verific_verbose) - log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", - log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig)); - - clocking.addDff(new_verific_id(inst), sig_d, sig_q); - module->addEq(new_verific_id(inst), {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o); - - if (!mode_keep) - continue; - } - - if (!mode_keep && verific_sva_prims.count(inst->Type())) { - if (verific_verbose) - log(" skipping SVA cell in non k-mode\n"); - continue; - } - - if (inst->Type() == PRIM_HDL_ASSERTION) - { - SigBit cond = net_map_at(inst->GetInput()); - - if (verific_verbose) - log(" assert condition %s.\n", log_signal(cond)); - - const char *assume_attr = nullptr; // inst->GetAttValue("assume"); - - Cell *cell = nullptr; - if (assume_attr != nullptr && !strcmp(assume_attr, "1")) - cell = module->addAssume(new_verific_id(inst), cond, State::S1); - else - cell = module->addAssert(new_verific_id(inst), cond, State::S1); - - import_attributes(cell->attributes, inst); - continue; - } - - if (inst->IsPrimitive()) - { - if (!mode_keep) - log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name()); - - if (!verific_sva_prims.count(inst->Type())) - log_warning("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name()); - } - - import_verific_cells: - nl_todo.insert(inst->View()); - - RTLIL::Cell *cell = module->addCell(inst_name, inst->IsOperator() ? - std::string("$verific$") + inst->View()->Owner()->Name() : RTLIL::escape_id(inst->View()->Owner()->Name())); - - if (inst->IsPrimitive() && mode_keep) - cell->attributes["\\keep"] = 1; - - dict> cell_port_conns; - - if (verific_verbose) - log(" ports in verific db:\n"); - - FOREACH_PORTREF_OF_INST(inst, mi2, pr) { - if (verific_verbose) - log(" .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name()); - const char *port_name = pr->GetPort()->Name(); - int port_offset = 0; - if (pr->GetPort()->Bus()) { - port_name = pr->GetPort()->Bus()->Name(); - port_offset = pr->GetPort()->Bus()->IndexOf(pr->GetPort()) - - min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex()); - } - IdString port_name_id = RTLIL::escape_id(port_name); - auto &sigvec = cell_port_conns[port_name_id]; - if (GetSize(sigvec) <= port_offset) { - SigSpec zwires = module->addWire(new_verific_id(inst), port_offset+1-GetSize(sigvec)); - for (auto bit : zwires) - sigvec.push_back(bit); - } - sigvec[port_offset] = net_map_at(pr->GetNet()); - } - - if (verific_verbose) - log(" ports in yosys db:\n"); - - for (auto &it : cell_port_conns) { - if (verific_verbose) - log(" .%s(%s)\n", log_id(it.first), log_signal(it.second)); - cell->setPort(it.first, it.second); - } - } - - if (!mode_nosva) - { - for (auto inst : sva_asserts) { - if (mode_autocover) - verific_import_sva_cover(this, inst); - verific_import_sva_assert(this, inst); - } - - for (auto inst : sva_assumes) - verific_import_sva_assume(this, inst); - - for (auto inst : sva_covers) - verific_import_sva_cover(this, inst); - - for (auto inst : sva_triggers) - verific_import_sva_trigger(this, inst); - - merge_past_ffs(past_ffs); - } -} - -// ================================================================== - -VerificClocking::VerificClocking(VerificImporter *importer, Net *net, bool sva_at_only) -{ - module = importer->module; - - log_assert(importer != nullptr); - log_assert(net != nullptr); - - Instance *inst = net->Driver(); - - if (inst != nullptr && inst->Type() == PRIM_SVA_AT) - { - net = inst->GetInput1(); - body_net = inst->GetInput2(); - - inst = net->Driver(); - - Instance *body_inst = body_net->Driver(); - if (body_inst != nullptr && body_inst->Type() == PRIM_SVA_DISABLE_IFF) { - disable_net = body_inst->GetInput1(); - disable_sig = importer->net_map_at(disable_net); - body_net = body_inst->GetInput2(); - } - } - else - { - if (sva_at_only) - return; - } - - // Use while() instead of if() to work around VIPER #13453 - while (inst != nullptr && inst->Type() == PRIM_SVA_POSEDGE) - { - net = inst->GetInput(); - inst = net->Driver();; - } - - if (inst != nullptr && inst->Type() == PRIM_INV) - { - net = inst->GetInput(); - inst = net->Driver();; - posedge = false; - } - - // Detect clock-enable circuit - do { - if (inst == nullptr || inst->Type() != PRIM_AND) - break; - - Net *net_dlatch = inst->GetInput1(); - Instance *inst_dlatch = net_dlatch->Driver(); - - if (inst_dlatch == nullptr || inst_dlatch->Type() != PRIM_DLATCHRS) - break; - - if (!inst_dlatch->GetSet()->IsGnd() || !inst_dlatch->GetReset()->IsGnd()) - break; - - Net *net_enable = inst_dlatch->GetInput(); - Net *net_not_clock = inst_dlatch->GetControl(); - - if (net_enable == nullptr || net_not_clock == nullptr) - break; - - Instance *inst_not_clock = net_not_clock->Driver(); - - if (inst_not_clock == nullptr || inst_not_clock->Type() != PRIM_INV) - break; - - Net *net_clock1 = inst_not_clock->GetInput(); - Net *net_clock2 = inst->GetInput2(); - - if (net_clock1 == nullptr || net_clock1 != net_clock2) - break; - - enable_net = net_enable; - enable_sig = importer->net_map_at(enable_net); - - net = net_clock1; - inst = net->Driver();; - } while (0); - - // Detect condition expression - do { - if (body_net == nullptr) - break; - - Instance *inst_mux = body_net->Driver(); - - if (inst_mux == nullptr || inst_mux->Type() != PRIM_MUX) - break; - - if (!inst_mux->GetInput1()->IsPwr()) - break; - - Net *sva_net = inst_mux->GetInput2(); - if (!verific_is_sva_net(importer, sva_net)) - break; - - body_net = sva_net; - cond_net = inst_mux->GetControl(); - } while (0); - - clock_net = net; - clock_sig = importer->net_map_at(clock_net); - - const char *gclk_attr = clock_net->GetAttValue("gclk"); - if (gclk_attr != nullptr && (!strcmp(gclk_attr, "1") || !strcmp(gclk_attr, "'1'"))) - gclk = true; -} - -Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value) -{ - log_assert(GetSize(sig_d) == GetSize(sig_q)); - - if (GetSize(init_value) != 0) { - log_assert(GetSize(sig_q) == GetSize(init_value)); - if (sig_q.is_wire()) { - sig_q.as_wire()->attributes["\\init"] = init_value; - } else { - Wire *w = module->addWire(NEW_ID, GetSize(sig_q)); - w->attributes["\\init"] = init_value; - module->connect(sig_q, w); - sig_q = w; - } - } - - if (enable_sig != State::S1) - sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); - - if (disable_sig != State::S0) { - log_assert(gclk == false); - log_assert(GetSize(sig_q) == GetSize(init_value)); - return module->addAdff(name, clock_sig, disable_sig, sig_d, sig_q, init_value, posedge); - } - - if (gclk) - return module->addFf(name, sig_d, sig_q); - - return module->addDff(name, clock_sig, sig_d, sig_q, posedge); -} - -Cell *VerificClocking::addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value) -{ - log_assert(gclk == false); - log_assert(disable_sig == State::S0); - - if (enable_sig != State::S1) - sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); - - return module->addAdff(name, clock_sig, sig_arst, sig_d, sig_q, arst_value, posedge); -} - -Cell *VerificClocking::addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q) -{ - log_assert(gclk == false); - log_assert(disable_sig == State::S0); - - if (enable_sig != State::S1) - sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); - - return module->addDffsr(name, clock_sig, sig_set, sig_clr, sig_d, sig_q, posedge); -} - -// ================================================================== - -struct VerificExtNets -{ - int portname_cnt = 0; - - // a map from Net to the same Net one level up in the design hierarchy - std::map net_level_up_drive_up; - std::map net_level_up_drive_down; - - Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr) - { - auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down; - - if (net_level_up.count(net) == 0) - { - Netlist *nl = net->Owner(); - - // Simply return if Netlist is not unique - log_assert(nl->NumOfRefs() == 1); - - Instance *up_inst = (Instance*)nl->GetReferences()->GetLast(); - Netlist *up_nl = up_inst->Owner(); - - // create new Port - string name = stringf("___extnets_%d", portname_cnt++); - Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN); - nl->Add(new_port); - net->Connect(new_port); - - // create new Net in up Netlist - Net *new_net = final_net; - if (new_net == nullptr || new_net->Owner() != up_nl) { - new_net = new Net(name.c_str()); - up_nl->Add(new_net); - } - up_inst->Connect(new_port, new_net); - - net_level_up[net] = new_net; - } - - return net_level_up.at(net); - } - - Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr) - { - while (net->Owner() != dest) - net = route_up(net, drive_up, final_net); - if (final_net != nullptr) - log_assert(net == final_net); - return net; - } - - Netlist *find_common_ancestor(Netlist *A, Netlist *B) - { - std::set ancestors_of_A; - - Netlist *cursor = A; - while (1) { - ancestors_of_A.insert(cursor); - if (cursor->NumOfRefs() != 1) - break; - cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner(); - } - - cursor = B; - while (1) { - if (ancestors_of_A.count(cursor)) - return cursor; - if (cursor->NumOfRefs() != 1) - break; - cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner(); - } - - log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str()); - } - - void run(Netlist *nl) - { - MapIter mi, mi2; - Instance *inst; - PortRef *pr; - - vector> todo_connect; - - FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst) - run(inst->View()); - - FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst) - FOREACH_PORTREF_OF_INST(inst, mi2, pr) - { - Port *port = pr->GetPort(); - Net *net = pr->GetNet(); - - if (!net->IsExternalTo(nl)) - continue; - - if (verific_verbose) - log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name()); - - Netlist *ext_nl = net->Owner(); - - if (verific_verbose) - log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str()); - - Netlist *ca_nl = find_common_ancestor(nl, ext_nl); - - if (verific_verbose) - log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str()); - - Net *ca_net = route_up(net, !port->IsOutput(), ca_nl); - Net *new_net = ca_net; - - if (ca_nl != nl) - { - if (verific_verbose) - log(" net in common ancestor: %s\n", ca_net->Name()); - - string name = stringf("___extnets_%d", portname_cnt++); - new_net = new Net(name.c_str()); - nl->Add(new_net); - - Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net); - log_assert(n == ca_net); - } - - if (verific_verbose) - log(" new local net: %s\n", new_net->Name()); - - log_assert(!new_net->IsExternalTo(nl)); - todo_connect.push_back(tuple(inst, port, new_net)); - } - - for (auto it : todo_connect) { - get<0>(it)->Disconnect(get<1>(it)); - get<0>(it)->Connect(get<1>(it), get<2>(it)); - } - } -}; - -void verific_import(Design *design, const std::map ¶meters, std::string top) -{ - verific_sva_fsm_limit = 16; - - std::set nl_todo, nl_done; - - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); - VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); - Array *netlists = NULL; - Array veri_libs, vhdl_libs; - if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); - if (veri_lib) veri_libs.InsertLast(veri_lib); - - Map verific_params(STRING_HASH); - for (const auto &i : parameters) - verific_params.Insert(i.first.c_str(), i.second.c_str()); - - if (top.empty()) { - netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params); - } - else { - Array veri_modules, vhdl_units; - - if (veri_lib) { - VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1); - if (veri_module) { - veri_modules.InsertLast(veri_module); - } - - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); - } - } - - if (vhdl_lib) { - VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); - if (vhdl_unit) - vhdl_units.InsertLast(vhdl_unit); - } - - netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); - } - - Netlist *nl; - int i; - - FOREACH_ARRAY_ITEM(netlists, i, nl) { - if (top.empty() && nl->CellBaseName() != top) - continue; - nl->AddAtt(new Att(" \\top", NULL)); - nl_todo.insert(nl); - } - - delete netlists; - - if (!verific_error_msg.empty()) - log_error("%s\n", verific_error_msg.c_str()); - - VerificExtNets worker; - for (auto nl : nl_todo) - worker.run(nl); - - while (!nl_todo.empty()) { - Netlist *nl = *nl_todo.begin(); - if (nl_done.count(nl) == 0) { - VerificImporter importer(false, false, false, false, false, false); - importer.import_netlist(design, nl, nl_todo); - } - nl_todo.erase(nl); - nl_done.insert(nl); - } - - veri_file::Reset(); - vhdl_file::Reset(); - Libset::Reset(); - verific_incdirs.clear(); - verific_libdirs.clear(); - verific_import_pending = false; - - if (!verific_error_msg.empty()) - log_error("%s\n", verific_error_msg.c_str()); -} - -YOSYS_NAMESPACE_END -#endif /* YOSYS_ENABLE_VERIFIC */ - -PRIVATE_NAMESPACE_BEGIN - -#ifdef YOSYS_ENABLE_VERIFIC -bool check_noverific_env() -{ - const char *e = getenv("YOSYS_NOVERIFIC"); - if (e == nullptr) - return false; - if (atoi(e) == 0) - return false; - return true; -} -#endif - -struct VerificPass : public Pass { - VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv} ..\n"); - log("\n"); - log("Load the specified Verilog/SystemVerilog files into Verific.\n"); - log("\n"); - log("All files specified in one call to this command are one compilation unit.\n"); - log("Files passed to different calls to this command are treated as belonging to\n"); - log("different compilation units.\n"); - log("\n"); - log("Additional -D[=] options may be added after the option indicating\n"); - log("the language version (and before file names) to set additional verilog defines.\n"); - log("The macros SYNTHESIS and VERIFIC are defined implicitly.\n"); - log("\n"); - log("\n"); - log(" verific -formal ..\n"); - log("\n"); - log("Like -sv, but define FORMAL instead of SYNTHESIS.\n"); - log("\n"); - log("\n"); - log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} ..\n"); - log("\n"); - log("Load the specified VHDL files into Verific.\n"); - log("\n"); - log("\n"); - log(" verific -work {-sv|-vhdl|...} \n"); - log("\n"); - log("Load the specified Verilog/SystemVerilog/VHDL file into the specified library.\n"); - log("(default library when -work is not present: \"work\")\n"); - log("\n"); - log("\n"); - log(" verific -vlog-incdir ..\n"); - log("\n"); - log("Add Verilog include directories.\n"); - log("\n"); - log("\n"); - log(" verific -vlog-libdir ..\n"); - log("\n"); - log("Add Verilog library directories. Verific will search in this directories to\n"); - log("find undefined modules.\n"); - log("\n"); - log("\n"); - log(" verific -vlog-define [=]..\n"); - log("\n"); - log("Add Verilog defines.\n"); - log("\n"); - log("\n"); - log(" verific -vlog-undef ..\n"); - log("\n"); - log("Remove Verilog defines previously set with -vlog-define.\n"); - log("\n"); - log("\n"); - log(" verific -set-error ..\n"); - log(" verific -set-warning ..\n"); - log(" verific -set-info ..\n"); - log(" verific -set-ignore ..\n"); - log("\n"); - log("Set message severity. is the string in square brackets when a message\n"); - log("is printed, such as VERI-1209.\n"); - log("\n"); - log("\n"); - log(" verific -import [options] ..\n"); - log("\n"); - log("Elaborate the design for the specified top modules, import to Yosys and\n"); - log("reset the internal state of Verific.\n"); - log("\n"); - log("Import options:\n"); - log("\n"); - log(" -all\n"); - log(" Elaborate all modules, not just the hierarchy below the given top\n"); - log(" modules. With this option the list of modules to import is optional.\n"); - log("\n"); - log(" -gates\n"); - log(" Create a gate-level netlist.\n"); - log("\n"); - log(" -flatten\n"); - log(" Flatten the design in Verific before importing.\n"); - log("\n"); - log(" -extnets\n"); - log(" Resolve references to external nets by adding module ports as needed.\n"); - log("\n"); - log(" -autocover\n"); - log(" Generate automatic cover statements for all asserts\n"); - log("\n"); - log(" -chparam name value \n"); - log(" Elaborate the specified top modules (all modules when -all given) using\n"); - log(" this parameter value. Modules on which this parameter does not exist will\n"); - log(" cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n"); - log(" can be specified multiple times to override multiple parameters.\n"); - log(" String values must be passed in double quotes (\").\n"); - log("\n"); - log(" -v, -vv\n"); - log(" Verbose log messages. (-vv is even more verbose than -v.)\n"); - log("\n"); - log("The following additional import options are useful for debugging the Verific\n"); - log("bindings (for Yosys and/or Verific developers):\n"); - log("\n"); - log(" -k\n"); - log(" Keep going after an unsupported verific primitive is found. The\n"); - log(" unsupported primitive is added as blockbox module to the design.\n"); - log(" This will also add all SVA related cells to the design parallel to\n"); - log(" the checker logic inferred by it.\n"); - log("\n"); - log(" -V\n"); - log(" Import Verific netlist as-is without translating to Yosys cell types. \n"); - log("\n"); - log(" -nosva\n"); - log(" Ignore SVA properties, do not infer checker logic.\n"); - log("\n"); - log(" -L \n"); - log(" Maximum number of ctrl bits for SVA checker FSMs (default=16).\n"); - log("\n"); - log(" -n\n"); - log(" Keep all Verific names on instances and nets. By default only\n"); - log(" user-declared names are preserved.\n"); - log("\n"); - log(" -d \n"); - log(" Dump the Verific netlist as a verilog file.\n"); - log("\n"); - log("Visit http://verific.com/ for more information on Verific.\n"); - log("\n"); - } -#ifdef YOSYS_ENABLE_VERIFIC - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - static bool set_verific_global_flags = true; - - if (check_noverific_env()) - log_cmd_error("This version of Yosys is built without Verific support.\n"); - - log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n"); - - if (set_verific_global_flags) - { - Message::SetConsoleOutput(0); - Message::RegisterCallBackMsg(msg_func); - - RuntimeFlags::SetVar("db_preserve_user_nets", 1); - RuntimeFlags::SetVar("db_allow_external_nets", 1); - RuntimeFlags::SetVar("db_infer_wide_operators", 1); - - RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); - RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); - - RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0); - RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1); - - RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); - RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); - - // Workaround for VIPER #13851 - RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); - - // WARNING: instantiating unknown module 'XYZ' (VERI-1063) - Message::SetMessageType("VERI-1063", VERIFIC_ERROR); - - // https://github.com/YosysHQ/yosys/issues/1055 - RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ; - -#ifndef DB_PRESERVE_INITIAL_VALUE -# warning Verific was built without DB_PRESERVE_INITIAL_VALUE. -#endif - - set_verific_global_flags = false; - } - - verific_verbose = 0; - verific_sva_fsm_limit = 16; - - const char *release_str = Message::ReleaseString(); - time_t release_time = Message::ReleaseDate(); - char *release_tmstr = ctime(&release_time); - - if (release_str == nullptr) - release_str = "(no release string)"; - - for (char *p = release_tmstr; *p; p++) - if (*p == '\n') *p = 0; - - log("Built with Verific %s, released at %s.\n", release_str, release_tmstr); - - int argidx = 1; - std::string work = "work"; - - if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || - args[argidx] == "-set-info" || args[argidx] == "-set-ignore")) - { - msg_type_t new_type; - - if (args[argidx] == "-set-error") - new_type = VERIFIC_ERROR; - else if (args[argidx] == "-set-warning") - new_type = VERIFIC_WARNING; - else if (args[argidx] == "-set-info") - new_type = VERIFIC_INFO; - else if (args[argidx] == "-set-ignore") - new_type = VERIFIC_IGNORE; - else - log_abort(); - - for (argidx++; argidx < GetSize(args); argidx++) - Message::SetMessageType(args[argidx].c_str(), new_type); - - goto check_error; - } - - if (GetSize(args) > argidx && args[argidx] == "-vlog-incdir") { - for (argidx++; argidx < GetSize(args); argidx++) - verific_incdirs.push_back(args[argidx]); - goto check_error; - } - - if (GetSize(args) > argidx && args[argidx] == "-vlog-libdir") { - for (argidx++; argidx < GetSize(args); argidx++) - verific_libdirs.push_back(args[argidx]); - goto check_error; - } - - if (GetSize(args) > argidx && args[argidx] == "-vlog-define") { - for (argidx++; argidx < GetSize(args); argidx++) { - string name = args[argidx]; - size_t equal = name.find('='); - if (equal != std::string::npos) { - string value = name.substr(equal+1); - name = name.substr(0, equal); - veri_file::DefineCmdLineMacro(name.c_str(), value.c_str()); - } else { - veri_file::DefineCmdLineMacro(name.c_str()); - } - } - goto check_error; - } - - if (GetSize(args) > argidx && args[argidx] == "-vlog-undef") { - for (argidx++; argidx < GetSize(args); argidx++) { - string name = args[argidx]; - veri_file::UndefineMacro(name.c_str()); - } - goto check_error; - } - - for (; argidx < GetSize(args); argidx++) - { - if (args[argidx] == "-work" && argidx+1 < GetSize(args)) { - work = args[++argidx]; - continue; - } - break; - } - - if (GetSize(args) > argidx && (args[argidx] == "-vlog95" || args[argidx] == "-vlog2k" || args[argidx] == "-sv2005" || - args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal")) - { - Array file_names; - unsigned verilog_mode; - - if (args[argidx] == "-vlog95") - verilog_mode = veri_file::VERILOG_95; - else if (args[argidx] == "-vlog2k") - verilog_mode = veri_file::VERILOG_2K; - else if (args[argidx] == "-sv2005") - verilog_mode = veri_file::SYSTEM_VERILOG_2005; - else if (args[argidx] == "-sv2009") - verilog_mode = veri_file::SYSTEM_VERILOG_2009; - else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal") - verilog_mode = veri_file::SYSTEM_VERILOG; - else - log_abort(); - - veri_file::DefineMacro("VERIFIC"); - veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS"); - - for (argidx++; argidx < GetSize(args) && GetSize(args[argidx]) >= 2 && args[argidx].substr(0, 2) == "-D"; argidx++) { - std::string name = args[argidx].substr(2); - if (args[argidx] == "-D") { - if (++argidx >= GetSize(args)) - break; - name = args[argidx]; - } - size_t equal = name.find('='); - if (equal != std::string::npos) { - string value = name.substr(equal+1); - name = name.substr(0, equal); - veri_file::DefineMacro(name.c_str(), value.c_str()); - } else { - veri_file::DefineMacro(name.c_str()); - } - } - - for (auto &dir : verific_incdirs) - veri_file::AddIncludeDir(dir.c_str()); - for (auto &dir : verific_libdirs) - veri_file::AddYDir(dir.c_str()); - - while (argidx < GetSize(args)) - file_names.Insert(args[argidx++].c_str()); - - if (!veri_file::AnalyzeMultipleFiles(&file_names, verilog_mode, work.c_str(), veri_file::MFCU)) - log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n"); - - verific_import_pending = true; - goto check_error; - } - - if (GetSize(args) > argidx && args[argidx] == "-vhdl87") { - vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str()); - for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_87)) - log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str()); - verific_import_pending = true; - goto check_error; - } - - if (GetSize(args) > argidx && args[argidx] == "-vhdl93") { - vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); - for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_93)) - log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str()); - verific_import_pending = true; - goto check_error; - } - - if (GetSize(args) > argidx && args[argidx] == "-vhdl2k") { - vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); - for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2K)) - log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str()); - verific_import_pending = true; - goto check_error; - } - - if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) { - vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str()); - for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2008)) - log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str()); - verific_import_pending = true; - goto check_error; - } - - if (GetSize(args) > argidx && args[argidx] == "-import") - { - std::set nl_todo, nl_done; - bool mode_all = false, mode_gates = false, mode_keep = false; - bool mode_nosva = false, mode_names = false, mode_verific = false; - bool mode_autocover = false; - bool flatten = false, extnets = false; - string dumpfile; - Map parameters(STRING_HASH); - - for (argidx++; argidx < GetSize(args); argidx++) { - if (args[argidx] == "-all") { - mode_all = true; - continue; - } - if (args[argidx] == "-gates") { - mode_gates = true; - continue; - } - if (args[argidx] == "-flatten") { - flatten = true; - continue; - } - if (args[argidx] == "-extnets") { - extnets = true; - continue; - } - if (args[argidx] == "-k") { - mode_keep = true; - continue; - } - if (args[argidx] == "-nosva") { - mode_nosva = true; - continue; - } - if (args[argidx] == "-L" && argidx+1 < GetSize(args)) { - verific_sva_fsm_limit = atoi(args[++argidx].c_str()); - continue; - } - if (args[argidx] == "-n") { - mode_names = true; - continue; - } - if (args[argidx] == "-autocover") { - mode_autocover = true; - continue; - } - if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) { - const std::string &key = args[++argidx]; - const std::string &value = args[++argidx]; - unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(), - 1 /* force_overwrite */); - if (!new_insertion) - log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str()); - continue; - } - if (args[argidx] == "-V") { - mode_verific = true; - continue; - } - if (args[argidx] == "-v") { - verific_verbose = 1; - continue; - } - if (args[argidx] == "-vv") { - verific_verbose = 2; - continue; - } - if (args[argidx] == "-d" && argidx+1 < GetSize(args)) { - dumpfile = args[++argidx]; - continue; - } - break; - } - - if (argidx > GetSize(args) && args[argidx].substr(0, 1) == "-") - cmd_error(args, argidx, "unknown option"); - - if (mode_all) - { - log("Running hier_tree::ElaborateAll().\n"); - - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); - VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); - - Array veri_libs, vhdl_libs; - if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); - if (veri_lib) veri_libs.InsertLast(veri_lib); - - Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, ¶meters); - Netlist *nl; - int i; - - FOREACH_ARRAY_ITEM(netlists, i, nl) - nl_todo.insert(nl); - delete netlists; - } - else - { - if (argidx == GetSize(args)) - log_cmd_error("No top module specified.\n"); - - Array veri_modules, vhdl_units; - for (; argidx < GetSize(args); argidx++) - { - const char *name = args[argidx].c_str(); - VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); - - if (veri_lib) { - VeriModule *veri_module = veri_lib->GetModule(name, 1); - if (veri_module) { - log("Adding Verilog module '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); - continue; - } - - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); - } - } - - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); - VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(name); - if (vhdl_unit) { - log("Adding VHDL unit '%s' to elaboration queue.\n", name); - vhdl_units.InsertLast(vhdl_unit); - continue; - } - - log_error("Can't find module/unit '%s'.\n", name); - } - - log("Running hier_tree::Elaborate().\n"); - Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); - Netlist *nl; - int i; - - FOREACH_ARRAY_ITEM(netlists, i, nl) { - nl->AddAtt(new Att(" \\top", NULL)); - nl_todo.insert(nl); - } - delete netlists; - } - - if (!verific_error_msg.empty()) - goto check_error; - - if (flatten) { - for (auto nl : nl_todo) - nl->Flatten(); - } - - if (extnets) { - VerificExtNets worker; - for (auto nl : nl_todo) - worker.run(nl); - } - - if (!dumpfile.empty()) { - VeriWrite veri_writer; - veri_writer.WriteFile(dumpfile.c_str(), Netlist::PresentDesign()); - } - - while (!nl_todo.empty()) { - Netlist *nl = *nl_todo.begin(); - if (nl_done.count(nl) == 0) { - VerificImporter importer(mode_gates, mode_keep, mode_nosva, - mode_names, mode_verific, mode_autocover); - importer.import_netlist(design, nl, nl_todo); - } - nl_todo.erase(nl); - nl_done.insert(nl); - } - - veri_file::Reset(); - vhdl_file::Reset(); - Libset::Reset(); - verific_incdirs.clear(); - verific_libdirs.clear(); - verific_import_pending = false; - goto check_error; - } - - log_cmd_error("Missing or unsupported mode parameter.\n"); - - check_error: - if (!verific_error_msg.empty()) - log_error("%s\n", verific_error_msg.c_str()); - - } -#else /* YOSYS_ENABLE_VERIFIC */ - void execute(std::vector, RTLIL::Design *) YS_OVERRIDE { - log_cmd_error("This version of Yosys is built without Verific support.\n"); - } -#endif -} VerificPass; - -struct ReadPass : public Pass { - ReadPass() : Pass("read", "load HDL designs") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv|-formal} ..\n"); - log("\n"); - log("Load the specified Verilog/SystemVerilog files. (Full SystemVerilog support\n"); - log("is only available via Verific.)\n"); - log("\n"); - log("Additional -D[=] options may be added after the option indicating\n"); - log("the language version (and before file names) to set additional verilog defines.\n"); - log("\n"); - log("\n"); - log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} ..\n"); - log("\n"); - log("Load the specified VHDL files. (Requires Verific.)\n"); - log("\n"); - log("\n"); - log(" read -define [=]..\n"); - log("\n"); - log("Set global Verilog/SystemVerilog defines.\n"); - log("\n"); - log("\n"); - log(" read -undef ..\n"); - log("\n"); - log("Unset global Verilog/SystemVerilog defines.\n"); - log("\n"); - log("\n"); - log(" read -incdir \n"); - log("\n"); - log("Add directory to global Verilog/SystemVerilog include directories.\n"); - log("\n"); - log("\n"); - log(" read -verific\n"); - log(" read -noverific\n"); - log("\n"); - log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n"); - log("with -verific will result in an error on Yosys binaries that are built without\n"); - log("Verific support. The default is to use Verific if it is available.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { -#ifdef YOSYS_ENABLE_VERIFIC - static bool verific_available = !check_noverific_env(); -#else - static bool verific_available = false; -#endif - static bool use_verific = verific_available; - - if (args.size() < 2 || args[1][0] != '-') - log_cmd_error("Missing mode parameter.\n"); - - if (args[1] == "-verific" || args[1] == "-noverific") { - if (args.size() != 2) - log_cmd_error("Additional arguments to -verific/-noverific.\n"); - if (args[1] == "-verific") { - if (!verific_available) - log_cmd_error("This version of Yosys is built without Verific support.\n"); - use_verific = true; - } else { - use_verific = false; - } - return; - } - - if (args.size() < 3) - log_cmd_error("Missing file name parameter.\n"); - - if (args[1] == "-vlog95" || args[1] == "-vlog2k") { - if (use_verific) { - args[0] = "verific"; - } else { - args[0] = "read_verilog"; - args.erase(args.begin()+1, args.begin()+2); - } - Pass::call(design, args); - return; - } - - if (args[1] == "-sv2005" || args[1] == "-sv2009" || args[1] == "-sv2012" || args[1] == "-sv" || args[1] == "-formal") { - if (use_verific) { - args[0] = "verific"; - } else { - args[0] = "read_verilog"; - if (args[1] == "-formal") - args.insert(args.begin()+1, std::string()); - args[1] = "-sv"; - } - Pass::call(design, args); - return; - } - - if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl") { - if (use_verific) { - args[0] = "verific"; - Pass::call(design, args); - } else { - log_cmd_error("This version of Yosys is built without Verific support.\n"); - } - return; - } - - if (args[1] == "-define") { - if (use_verific) { - args[0] = "verific"; - args[1] = "-vlog-define"; - Pass::call(design, args); - } - args[0] = "verilog_defines"; - args.erase(args.begin()+1, args.begin()+2); - for (int i = 1; i < GetSize(args); i++) - args[i] = "-D" + args[i]; - Pass::call(design, args); - return; - } - - if (args[1] == "-undef") { - if (use_verific) { - args[0] = "verific"; - args[1] = "-vlog-undef"; - Pass::call(design, args); - } - args[0] = "verilog_defines"; - args.erase(args.begin()+1, args.begin()+2); - for (int i = 1; i < GetSize(args); i++) - args[i] = "-U" + args[i]; - Pass::call(design, args); - return; - } - - if (args[1] == "-incdir") { - if (use_verific) { - args[0] = "verific"; - args[1] = "-vlog-incdir"; - Pass::call(design, args); - } - args[0] = "verilog_defaults"; - args[1] = "-add"; - for (int i = 2; i < GetSize(args); i++) - args[i] = "-I" + args[i]; - Pass::call(design, args); - return; - } - - log_cmd_error("Missing or unsupported mode parameter.\n"); - } -} ReadPass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/frontends/verific/verific.h b/yosys/frontends/verific/verific.h deleted file mode 100644 index 88a6cc0ba..000000000 --- a/yosys/frontends/verific/verific.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifdef YOSYS_ENABLE_VERIFIC - -#include "DataBase.h" - -YOSYS_NAMESPACE_BEGIN - -extern int verific_verbose; - -extern bool verific_import_pending; -extern void verific_import(Design *design, const std::map ¶meters, std::string top = std::string()); - -extern pool verific_sva_prims; - -struct VerificImporter; - -struct VerificClocking { - RTLIL::Module *module = nullptr; - Verific::Net *clock_net = nullptr; - Verific::Net *enable_net = nullptr; - Verific::Net *disable_net = nullptr; - Verific::Net *body_net = nullptr; - Verific::Net *cond_net = nullptr; - SigBit clock_sig = State::Sx; - SigBit enable_sig = State::S1; - SigBit disable_sig = State::S0; - bool posedge = true; - bool gclk = false; - - VerificClocking() { } - VerificClocking(VerificImporter *importer, Verific::Net *net, bool sva_at_only = false); - RTLIL::Cell *addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value = Const()); - RTLIL::Cell *addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value); - RTLIL::Cell *addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q); - - bool property_matches_sequence(const VerificClocking &seq) const { - if (clock_net != seq.clock_net) - return false; - if (enable_net != seq.enable_net) - return false; - if (posedge != seq.posedge) - return false; - return true; - } -}; - -struct VerificImporter -{ - RTLIL::Module *module; - Verific::Netlist *netlist; - - std::map net_map; - std::map sva_posedge_map; - pool any_all_nets; - - bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific; - bool mode_autocover; - - VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover); - - RTLIL::SigBit net_map_at(Verific::Net *net); - - RTLIL::IdString new_verific_id(Verific::DesignObj *obj); - void import_attributes(dict &attributes, Verific::DesignObj *obj); - - RTLIL::SigSpec operatorInput(Verific::Instance *inst); - RTLIL::SigSpec operatorInput1(Verific::Instance *inst); - RTLIL::SigSpec operatorInput2(Verific::Instance *inst); - RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname); - RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool *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); - - void merge_past_ffs_clock(pool &candidates, SigBit clock, bool clock_pol); - void merge_past_ffs(pool &candidates); - - void import_netlist(RTLIL::Design *design, Verific::Netlist *nl, std::set &nl_todo); -}; - -void verific_import_sva_assert(VerificImporter *importer, Verific::Instance *inst); -void verific_import_sva_assume(VerificImporter *importer, Verific::Instance *inst); -void verific_import_sva_cover(VerificImporter *importer, Verific::Instance *inst); -void verific_import_sva_trigger(VerificImporter *importer, Verific::Instance *inst); -bool verific_is_sva_net(VerificImporter *importer, Verific::Net *net); - -extern int verific_sva_fsm_limit; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/verific/verificsva.cc b/yosys/frontends/verific/verificsva.cc deleted file mode 100644 index 8ea8372d3..000000000 --- a/yosys/frontends/verific/verificsva.cc +++ /dev/null @@ -1,1828 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - - -// Currently supported SVA sequence and property syntax: -// http://symbiyosys.readthedocs.io/en/latest/verific.html -// -// Next gen property syntax: -// basic_property -// [antecedent_condition] property -// [antecedent_condition] always.. property -// [antecedent_condition] eventually.. basic_property -// [antecedent_condition] property until.. expression -// [antecedent_condition] basic_property until.. basic_property (assert/assume only) -// -// antecedent_condition: -// sequence |-> -// sequence |=> -// -// basic_property: -// sequence -// not basic_property -// sequence #-# basic_property -// sequence #=# basic_property -// basic_property or basic_property (cover only) -// basic_property and basic_property (assert/assume only) -// basic_property implies basic_property -// basic_property iff basic_property -// -// sequence: -// expression -// sequence ##N sequence -// sequence ##[*] sequence -// sequence ##[+] sequence -// sequence ##[N:M] sequence -// sequence ##[N:$] sequence -// expression [*] -// expression [+] -// expression [*N] -// expression [*N:M] -// expression [*N:$] -// sequence or sequence -// sequence and sequence -// expression throughout sequence -// sequence intersect sequence -// sequence within sequence -// first_match( sequence ) -// expression [=N] -// expression [=N:M] -// expression [=N:$] -// expression [->N] -// expression [->N:M] -// expression [->N:$] - - -#include "kernel/yosys.h" -#include "frontends/verific/verific.h" - -USING_YOSYS_NAMESPACE - -#ifdef VERIFIC_NAMESPACE -using namespace Verific; -#endif - -PRIVATE_NAMESPACE_BEGIN - -// Non-deterministic FSM -struct SvaNFsmNode -{ - // Edge: Activate the target node if ctrl signal is true, consumes clock cycle - // Link: Activate the target node if ctrl signal is true, doesn't consume clock cycle - vector> edges, links; - bool is_cond_node; -}; - -// Non-deterministic FSM after resolving links -struct SvaUFsmNode -{ - // Edge: Activate the target node if all bits in ctrl signal are true, consumes clock cycle - // Accept: This node functions as an accept node if all bits in ctrl signal are true - vector> edges; - vector accept, cond; - bool reachable; -}; - -// Deterministic FSM -struct SvaDFsmNode -{ - // A DFSM state corresponds to a set of NFSM states. We represent DFSM states as sorted vectors - // of NFSM state node ids. Edge/accept controls are constants matched against the ctrl sigspec. - SigSpec ctrl; - vector, Const>> edges; - vector accept, reject; - - // additional temp data for getReject() - Wire *ffoutwire; - SigBit statesig; - SigSpec nextstate; - - // additional temp data for getDFsm() - int outnode; -}; - -struct SvaFsm -{ - Module *module; - VerificClocking clocking; - - SigBit trigger_sig = State::S1, disable_sig; - SigBit throughout_sig = State::S1; - bool in_cond_mode = false; - - vector disable_stack; - vector throughout_stack; - - int startNode, acceptNode, condNode; - vector nodes; - - vector unodes; - dict, SvaDFsmNode> dnodes; - dict, SigBit> cond_eq_cache; - bool materialized = false; - - SigBit final_accept_sig = State::Sx; - SigBit final_reject_sig = State::Sx; - - SvaFsm(const VerificClocking &clking, SigBit trig = State::S1) - { - module = clking.module; - clocking = clking; - trigger_sig = trig; - - startNode = createNode(); - acceptNode = createNode(); - - in_cond_mode = true; - condNode = createNode(); - in_cond_mode = false; - } - - void pushDisable(SigBit sig) - { - log_assert(!materialized); - - disable_stack.push_back(disable_sig); - - if (disable_sig == State::S0) - disable_sig = sig; - else - disable_sig = module->Or(NEW_ID, disable_sig, sig); - } - - void popDisable() - { - log_assert(!materialized); - log_assert(!disable_stack.empty()); - - disable_sig = disable_stack.back(); - disable_stack.pop_back(); - } - - void pushThroughout(SigBit sig) - { - log_assert(!materialized); - - throughout_stack.push_back(throughout_sig); - - if (throughout_sig == State::S1) - throughout_sig = sig; - else - throughout_sig = module->And(NEW_ID, throughout_sig, sig); - } - - void popThroughout() - { - log_assert(!materialized); - log_assert(!throughout_stack.empty()); - - throughout_sig = throughout_stack.back(); - throughout_stack.pop_back(); - } - - int createNode(int link_node = -1) - { - log_assert(!materialized); - - int idx = GetSize(nodes); - nodes.push_back(SvaNFsmNode()); - nodes.back().is_cond_node = in_cond_mode; - if (link_node >= 0) - createLink(link_node, idx); - return idx; - } - - int createStartNode() - { - return createNode(startNode); - } - - void createEdge(int from_node, int to_node, SigBit ctrl = State::S1) - { - log_assert(!materialized); - log_assert(0 <= from_node && from_node < GetSize(nodes)); - log_assert(0 <= to_node && to_node < GetSize(nodes)); - log_assert(from_node != acceptNode); - log_assert(to_node != acceptNode); - log_assert(from_node != condNode); - log_assert(to_node != condNode); - log_assert(to_node != startNode); - - if (from_node != startNode) - log_assert(nodes.at(from_node).is_cond_node == nodes.at(to_node).is_cond_node); - - if (throughout_sig != State::S1) { - if (ctrl != State::S1) - ctrl = module->And(NEW_ID, throughout_sig, ctrl); - else - ctrl = throughout_sig; - } - - nodes[from_node].edges.push_back(make_pair(to_node, ctrl)); - } - - void createLink(int from_node, int to_node, SigBit ctrl = State::S1) - { - log_assert(!materialized); - log_assert(0 <= from_node && from_node < GetSize(nodes)); - log_assert(0 <= to_node && to_node < GetSize(nodes)); - log_assert(from_node != acceptNode); - log_assert(from_node != condNode); - log_assert(to_node != startNode); - - if (from_node != startNode) - log_assert(nodes.at(from_node).is_cond_node == nodes.at(to_node).is_cond_node); - - if (throughout_sig != State::S1) { - if (ctrl != State::S1) - ctrl = module->And(NEW_ID, throughout_sig, ctrl); - else - ctrl = throughout_sig; - } - - nodes[from_node].links.push_back(make_pair(to_node, ctrl)); - } - - void make_link_order(vector &order, int node, int min) - { - order[node] = std::max(order[node], min); - for (auto &it : nodes[node].links) - make_link_order(order, it.first, order[node]+1); - } - - // ---------------------------------------------------- - // Generating NFSM circuit to acquire accept signal - - SigBit getAccept() - { - log_assert(!materialized); - materialized = true; - - vector state_wire(GetSize(nodes)); - vector state_sig(GetSize(nodes)); - vector next_state_sig(GetSize(nodes)); - - // Create state signals - - { - SigBit not_disable = State::S1; - - if (disable_sig != State::S0) - not_disable = module->Not(NEW_ID, disable_sig); - - for (int i = 0; i < GetSize(nodes); i++) - { - Wire *w = module->addWire(NEW_ID); - state_wire[i] = w; - state_sig[i] = w; - - if (i == startNode) - state_sig[i] = module->Or(NEW_ID, state_sig[i], trigger_sig); - - if (disable_sig != State::S0) - state_sig[i] = module->And(NEW_ID, state_sig[i], not_disable); - } - } - - // Follow Links - - { - vector node_order(GetSize(nodes)); - vector> order_to_nodes; - - for (int i = 0; i < GetSize(nodes); i++) - make_link_order(node_order, i, 0); - - for (int i = 0; i < GetSize(nodes); i++) { - if (node_order[i] >= GetSize(order_to_nodes)) - order_to_nodes.resize(node_order[i]+1); - order_to_nodes[node_order[i]].push_back(i); - } - - for (int order = 0; order < GetSize(order_to_nodes); order++) - for (int node : order_to_nodes[order]) - { - for (auto &it : nodes[node].links) - { - int target = it.first; - SigBit ctrl = state_sig[node]; - - if (it.second != State::S1) - ctrl = module->And(NEW_ID, ctrl, it.second); - - state_sig[target] = module->Or(NEW_ID, state_sig[target], ctrl); - } - } - } - - // Construct activations - - { - vector activate_sig(GetSize(nodes)); - vector activate_bit(GetSize(nodes)); - - for (int i = 0; i < GetSize(nodes); i++) { - for (auto &it : nodes[i].edges) - activate_sig[it.first].append(module->And(NEW_ID, state_sig[i], it.second)); - } - - for (int i = 0; i < GetSize(nodes); i++) { - if (GetSize(activate_sig[i]) == 0) - next_state_sig[i] = State::S0; - else if (GetSize(activate_sig[i]) == 1) - next_state_sig[i] = activate_sig[i]; - else - next_state_sig[i] = module->ReduceOr(NEW_ID, activate_sig[i]); - } - } - - // Create state FFs - - for (int i = 0; i < GetSize(nodes); i++) - { - if (next_state_sig[i] != State::S0) { - clocking.addDff(NEW_ID, next_state_sig[i], state_wire[i], Const(0, 1)); - } else { - module->connect(state_wire[i], State::S0); - } - } - - final_accept_sig = state_sig[acceptNode]; - return final_accept_sig; - } - - // ---------------------------------------------------- - // Generating quantifier-based NFSM circuit to acquire reject signal - - SigBit getAnyAllRejectWorker(bool /* allMode */) - { - // FIXME - log_abort(); - } - - SigBit getAnyReject() - { - return getAnyAllRejectWorker(false); - } - - SigBit getAllReject() - { - return getAnyAllRejectWorker(true); - } - - // ---------------------------------------------------- - // Generating DFSM circuit to acquire reject signal - - void node_to_unode(int node, int unode, SigSpec ctrl) - { - if (node == acceptNode) - unodes[unode].accept.push_back(ctrl); - - if (node == condNode) - unodes[unode].cond.push_back(ctrl); - - for (auto &it : nodes[node].edges) { - if (it.second != State::S1) { - SigSpec s = {ctrl, it.second}; - s.sort_and_unify(); - unodes[unode].edges.push_back(make_pair(it.first, s)); - } else { - unodes[unode].edges.push_back(make_pair(it.first, ctrl)); - } - } - - for (auto &it : nodes[node].links) { - if (it.second != State::S1) { - SigSpec s = {ctrl, it.second}; - s.sort_and_unify(); - node_to_unode(it.first, unode, s); - } else { - node_to_unode(it.first, unode, ctrl); - } - } - } - - void mark_reachable_unode(int unode) - { - if (unodes[unode].reachable) - return; - - unodes[unode].reachable = true; - for (auto &it : unodes[unode].edges) - mark_reachable_unode(it.first); - } - - void usortint(vector &vec) - { - vector newvec; - std::sort(vec.begin(), vec.end()); - for (int i = 0; i < GetSize(vec); i++) - if (i == GetSize(vec)-1 || vec[i] != vec[i+1]) - newvec.push_back(vec[i]); - vec.swap(newvec); - } - - bool cmp_ctrl(const pool &ctrl_bits, const SigSpec &ctrl) - { - for (int i = 0; i < GetSize(ctrl); i++) - if (ctrl_bits.count(ctrl[i]) == 0) - return false; - return true; - } - - void create_dnode(const vector &state, bool firstmatch, bool condaccept) - { - if (dnodes.count(state) != 0) - return; - - SvaDFsmNode dnode; - dnodes[state] = SvaDFsmNode(); - - for (int unode : state) { - log_assert(unodes[unode].reachable); - for (auto &it : unodes[unode].edges) - dnode.ctrl.append(it.second); - for (auto &it : unodes[unode].accept) - dnode.ctrl.append(it); - for (auto &it : unodes[unode].cond) - dnode.ctrl.append(it); - } - - dnode.ctrl.sort_and_unify(); - - if (GetSize(dnode.ctrl) > verific_sva_fsm_limit) { - if (verific_verbose >= 2) { - log(" detected state explosion in DFSM generation:\n"); - dump(); - log(" ctrl signal: %s\n", log_signal(dnode.ctrl)); - } - log_error("SVA DFSM state ctrl signal has %d (>%d) bits. Stopping to prevent exponential design size explosion.\n", - GetSize(dnode.ctrl), verific_sva_fsm_limit); - } - - for (int i = 0; i < (1 << GetSize(dnode.ctrl)); i++) - { - Const ctrl_val(i, GetSize(dnode.ctrl)); - pool ctrl_bits; - - for (int i = 0; i < GetSize(dnode.ctrl); i++) - if (ctrl_val[i] == State::S1) - ctrl_bits.insert(dnode.ctrl[i]); - - vector new_state; - bool accept = false, cond = false; - - for (int unode : state) { - for (auto &it : unodes[unode].accept) - if (cmp_ctrl(ctrl_bits, it)) - accept = true; - for (auto &it : unodes[unode].cond) - if (cmp_ctrl(ctrl_bits, it)) - cond = true; - } - - bool new_state_cond = false; - bool new_state_noncond = false; - - if (accept && condaccept) - accept = cond; - - if (!accept || !firstmatch) { - for (int unode : state) - for (auto &it : unodes[unode].edges) - if (cmp_ctrl(ctrl_bits, it.second)) { - if (nodes.at(it.first).is_cond_node) - new_state_cond = true; - else - new_state_noncond = true; - new_state.push_back(it.first); - } - } - - if (accept) - dnode.accept.push_back(ctrl_val); - - if (condaccept && (!new_state_cond || !new_state_noncond)) - new_state.clear(); - - if (new_state.empty()) { - if (!accept) - dnode.reject.push_back(ctrl_val); - } else { - usortint(new_state); - dnode.edges.push_back(make_pair(new_state, ctrl_val)); - create_dnode(new_state, firstmatch, condaccept); - } - } - - dnodes[state] = dnode; - } - - void optimize_cond(vector &values) - { - bool did_something = true; - - while (did_something) - { - did_something = false; - - for (int i = 0; i < GetSize(values); i++) - for (int j = 0; j < GetSize(values); j++) - { - if (i == j) - continue; - - log_assert(GetSize(values[i]) == GetSize(values[j])); - - int delta_pos = -1; - bool i_within_j = true; - bool j_within_i = true; - - for (int k = 0; k < GetSize(values[i]); k++) { - if (values[i][k] == State::Sa && values[j][k] != State::Sa) { - i_within_j = false; - continue; - } - if (values[i][k] != State::Sa && values[j][k] == State::Sa) { - j_within_i = false; - continue; - } - if (values[i][k] == values[j][k]) - continue; - if (delta_pos >= 0) - goto next_pair; - delta_pos = k; - } - - if (delta_pos >= 0 && i_within_j && j_within_i) { - did_something = true; - values[i][delta_pos] = State::Sa; - values[j] = values.back(); - values.pop_back(); - goto next_pair; - } - - if (delta_pos < 0 && i_within_j) { - did_something = true; - values[i] = values.back(); - values.pop_back(); - goto next_pair; - } - - if (delta_pos < 0 && j_within_i) { - did_something = true; - values[j] = values.back(); - values.pop_back(); - goto next_pair; - } - next_pair:; - } - } - } - - SigBit make_cond_eq(const SigSpec &ctrl, const Const &value, SigBit enable = State::S1) - { - SigSpec sig_a, sig_b; - - log_assert(GetSize(ctrl) == GetSize(value)); - - for (int i = 0; i < GetSize(ctrl); i++) - if (value[i] != State::Sa) { - sig_a.append(ctrl[i]); - sig_b.append(value[i]); - } - - if (GetSize(sig_a) == 0) - return enable; - - if (enable != State::S1) { - sig_a.append(enable); - sig_b.append(State::S1); - } - - auto key = make_pair(sig_a, sig_b); - - if (cond_eq_cache.count(key) == 0) - { - if (sig_b == State::S1) - cond_eq_cache[key] = sig_a; - else if (sig_b == State::S0) - cond_eq_cache[key] = module->Not(NEW_ID, sig_a); - else - cond_eq_cache[key] = module->Eq(NEW_ID, sig_a, sig_b); - - if (verific_verbose >= 2) { - log(" Cond: %s := %s == %s\n", log_signal(cond_eq_cache[key]), - log_signal(sig_a), log_signal(sig_b)); - } - } - - return cond_eq_cache.at(key); - } - - void getFirstAcceptReject(SigBit *accept_p, SigBit *reject_p) - { - log_assert(!materialized); - materialized = true; - - // Create unlinked NFSM - - unodes.resize(GetSize(nodes)); - - for (int node = 0; node < GetSize(nodes); node++) - node_to_unode(node, node, SigSpec()); - - mark_reachable_unode(startNode); - - // Create DFSM - - create_dnode(vector{startNode}, true, false); - dnodes.sort(); - - // Create DFSM Circuit - - SigSpec accept_sig, reject_sig; - - for (auto &it : dnodes) - { - SvaDFsmNode &dnode = it.second; - dnode.ffoutwire = module->addWire(NEW_ID); - dnode.statesig = dnode.ffoutwire; - - if (it.first == vector{startNode}) - dnode.statesig = module->Or(NEW_ID, dnode.statesig, trigger_sig); - } - - for (auto &it : dnodes) - { - SvaDFsmNode &dnode = it.second; - dict, vector> edge_cond; - - for (auto &edge : dnode.edges) - edge_cond[edge.first].push_back(edge.second); - - for (auto &it : edge_cond) { - optimize_cond(it.second); - for (auto &value : it.second) - dnodes.at(it.first).nextstate.append(make_cond_eq(dnode.ctrl, value, dnode.statesig)); - } - - if (accept_p) { - vector accept_cond = dnode.accept; - optimize_cond(accept_cond); - for (auto &value : accept_cond) - accept_sig.append(make_cond_eq(dnode.ctrl, value, dnode.statesig)); - } - - if (reject_p) { - vector reject_cond = dnode.reject; - optimize_cond(reject_cond); - for (auto &value : reject_cond) - reject_sig.append(make_cond_eq(dnode.ctrl, value, dnode.statesig)); - } - } - - for (auto &it : dnodes) - { - SvaDFsmNode &dnode = it.second; - if (GetSize(dnode.nextstate) == 0) { - module->connect(dnode.ffoutwire, State::S0); - } else - if (GetSize(dnode.nextstate) == 1) { - clocking.addDff(NEW_ID, dnode.nextstate, dnode.ffoutwire, State::S0); - } else { - SigSpec nextstate = module->ReduceOr(NEW_ID, dnode.nextstate); - clocking.addDff(NEW_ID, nextstate, dnode.ffoutwire, State::S0); - } - } - - if (accept_p) - { - if (GetSize(accept_sig) == 0) - final_accept_sig = State::S0; - else if (GetSize(accept_sig) == 1) - final_accept_sig = accept_sig; - else - final_accept_sig = module->ReduceOr(NEW_ID, accept_sig); - *accept_p = final_accept_sig; - } - - if (reject_p) - { - if (GetSize(reject_sig) == 0) - final_reject_sig = State::S0; - else if (GetSize(reject_sig) == 1) - final_reject_sig = reject_sig; - else - final_reject_sig = module->ReduceOr(NEW_ID, reject_sig); - *reject_p = final_reject_sig; - } - } - - SigBit getFirstAccept() - { - SigBit accept; - getFirstAcceptReject(&accept, nullptr); - return accept; - } - - SigBit getReject() - { - SigBit reject; - getFirstAcceptReject(nullptr, &reject); - return reject; - } - - void getDFsm(SvaFsm &output_fsm, int output_start_node, int output_accept_node, int output_reject_node = -1, bool firstmatch = true, bool condaccept = false) - { - log_assert(!materialized); - materialized = true; - - // Create unlinked NFSM - - unodes.resize(GetSize(nodes)); - - for (int node = 0; node < GetSize(nodes); node++) - node_to_unode(node, node, SigSpec()); - - mark_reachable_unode(startNode); - - // Create DFSM - - create_dnode(vector{startNode}, firstmatch, condaccept); - dnodes.sort(); - - // Create DFSM Graph - - for (auto &it : dnodes) - { - SvaDFsmNode &dnode = it.second; - dnode.outnode = output_fsm.createNode(); - - if (it.first == vector{startNode}) - output_fsm.createLink(output_start_node, dnode.outnode); - - if (output_accept_node >= 0) { - vector accept_cond = dnode.accept; - optimize_cond(accept_cond); - for (auto &value : accept_cond) - output_fsm.createLink(it.second.outnode, output_accept_node, make_cond_eq(dnode.ctrl, value)); - } - - if (output_reject_node >= 0) { - vector reject_cond = dnode.reject; - optimize_cond(reject_cond); - for (auto &value : reject_cond) - output_fsm.createLink(it.second.outnode, output_reject_node, make_cond_eq(dnode.ctrl, value)); - } - } - - for (auto &it : dnodes) - { - SvaDFsmNode &dnode = it.second; - dict, vector> edge_cond; - - for (auto &edge : dnode.edges) - edge_cond[edge.first].push_back(edge.second); - - for (auto &it : edge_cond) { - optimize_cond(it.second); - for (auto &value : it.second) - output_fsm.createEdge(dnode.outnode, dnodes.at(it.first).outnode, make_cond_eq(dnode.ctrl, value)); - } - } - } - - // ---------------------------------------------------- - // State dump for verbose log messages - - void dump_nodes() - { - if (nodes.empty()) - return; - - log(" non-deterministic encoding:\n"); - for (int i = 0; i < GetSize(nodes); i++) - { - log(" node %d:%s\n", i, - i == startNode ? " [start]" : - i == acceptNode ? " [accept]" : - i == condNode ? " [cond]" : ""); - - for (auto &it : nodes[i].edges) { - if (it.second != State::S1) - log(" edge %s -> %d\n", log_signal(it.second), it.first); - else - log(" edge -> %d\n", it.first); - } - - for (auto &it : nodes[i].links) { - if (it.second != State::S1) - log(" link %s -> %d\n", log_signal(it.second), it.first); - else - log(" link -> %d\n", it.first); - } - } - } - - void dump_unodes() - { - if (unodes.empty()) - return; - - log(" unlinked non-deterministic encoding:\n"); - for (int i = 0; i < GetSize(unodes); i++) - { - if (!unodes[i].reachable) - continue; - - log(" unode %d:%s\n", i, i == startNode ? " [start]" : ""); - - for (auto &it : unodes[i].edges) { - if (!it.second.empty()) - log(" edge %s -> %d\n", log_signal(it.second), it.first); - else - log(" edge -> %d\n", it.first); - } - - for (auto &ctrl : unodes[i].accept) { - if (!ctrl.empty()) - log(" accept %s\n", log_signal(ctrl)); - else - log(" accept\n"); - } - - for (auto &ctrl : unodes[i].cond) { - if (!ctrl.empty()) - log(" cond %s\n", log_signal(ctrl)); - else - log(" cond\n"); - } - } - } - - void dump_dnodes() - { - if (dnodes.empty()) - return; - - log(" deterministic encoding:\n"); - for (auto &it : dnodes) - { - log(" dnode {"); - for (int i = 0; i < GetSize(it.first); i++) - log("%s%d", i ? "," : "", it.first[i]); - log("}:%s\n", GetSize(it.first) == 1 && it.first[0] == startNode ? " [start]" : ""); - - log(" ctrl %s\n", log_signal(it.second.ctrl)); - - for (auto &edge : it.second.edges) { - log(" edge %s -> {", log_signal(edge.second)); - for (int i = 0; i < GetSize(edge.first); i++) - log("%s%d", i ? "," : "", edge.first[i]); - log("}\n"); - } - - for (auto &value : it.second.accept) - log(" accept %s\n", log_signal(value)); - - for (auto &value : it.second.reject) - log(" reject %s\n", log_signal(value)); - } - } - - void dump() - { - if (!nodes.empty()) - log(" number of NFSM states: %d\n", GetSize(nodes)); - - if (!unodes.empty()) { - int count = 0; - for (auto &unode : unodes) - if (unode.reachable) - count++; - log(" number of reachable UFSM states: %d\n", count); - } - - if (!dnodes.empty()) - log(" number of DFSM states: %d\n", GetSize(dnodes)); - - if (verific_verbose >= 2) { - dump_nodes(); - dump_unodes(); - dump_dnodes(); - } - - if (trigger_sig != State::S1) - log(" trigger signal: %s\n", log_signal(trigger_sig)); - - if (final_accept_sig != State::Sx) - log(" accept signal: %s\n", log_signal(final_accept_sig)); - - if (final_reject_sig != State::Sx) - log(" reject signal: %s\n", log_signal(final_reject_sig)); - } -}; - -PRIVATE_NAMESPACE_END - -YOSYS_NAMESPACE_BEGIN - -pool verific_sva_prims = { - // Copy&paste from Verific 3.16_484_32_170630 Netlist.h - PRIM_SVA_IMMEDIATE_ASSERT, PRIM_SVA_ASSERT, PRIM_SVA_COVER, PRIM_SVA_ASSUME, - PRIM_SVA_EXPECT, PRIM_SVA_POSEDGE, PRIM_SVA_NOT, PRIM_SVA_FIRST_MATCH, - PRIM_SVA_ENDED, PRIM_SVA_MATCHED, PRIM_SVA_CONSECUTIVE_REPEAT, - PRIM_SVA_NON_CONSECUTIVE_REPEAT, PRIM_SVA_GOTO_REPEAT, - PRIM_SVA_MATCH_ITEM_TRIGGER, PRIM_SVA_AND, PRIM_SVA_OR, PRIM_SVA_SEQ_AND, - PRIM_SVA_SEQ_OR, PRIM_SVA_EVENT_OR, PRIM_SVA_OVERLAPPED_IMPLICATION, - PRIM_SVA_NON_OVERLAPPED_IMPLICATION, PRIM_SVA_OVERLAPPED_FOLLOWED_BY, - PRIM_SVA_NON_OVERLAPPED_FOLLOWED_BY, PRIM_SVA_INTERSECT, PRIM_SVA_THROUGHOUT, - PRIM_SVA_WITHIN, PRIM_SVA_AT, PRIM_SVA_DISABLE_IFF, PRIM_SVA_SAMPLED, - PRIM_SVA_ROSE, PRIM_SVA_FELL, PRIM_SVA_STABLE, PRIM_SVA_PAST, - PRIM_SVA_MATCH_ITEM_ASSIGN, PRIM_SVA_SEQ_CONCAT, PRIM_SVA_IF, - PRIM_SVA_RESTRICT, PRIM_SVA_TRIGGERED, PRIM_SVA_STRONG, PRIM_SVA_WEAK, - PRIM_SVA_NEXTTIME, PRIM_SVA_S_NEXTTIME, PRIM_SVA_ALWAYS, PRIM_SVA_S_ALWAYS, - PRIM_SVA_S_EVENTUALLY, PRIM_SVA_EVENTUALLY, PRIM_SVA_UNTIL, PRIM_SVA_S_UNTIL, - PRIM_SVA_UNTIL_WITH, PRIM_SVA_S_UNTIL_WITH, PRIM_SVA_IMPLIES, PRIM_SVA_IFF, - PRIM_SVA_ACCEPT_ON, PRIM_SVA_REJECT_ON, PRIM_SVA_SYNC_ACCEPT_ON, - PRIM_SVA_SYNC_REJECT_ON, PRIM_SVA_GLOBAL_CLOCKING_DEF, - PRIM_SVA_GLOBAL_CLOCKING_REF, PRIM_SVA_IMMEDIATE_ASSUME, - PRIM_SVA_IMMEDIATE_COVER, OPER_SVA_SAMPLED, OPER_SVA_STABLE -}; - -struct VerificSvaImporter -{ - VerificImporter *importer = nullptr; - Module *module = nullptr; - - Netlist *netlist = nullptr; - Instance *root = nullptr; - - VerificClocking clocking; - - bool mode_assert = false; - bool mode_assume = false; - bool mode_cover = false; - bool mode_trigger = false; - - Instance *net_to_ast_driver(Net *n) - { - if (n == nullptr) - return nullptr; - - if (n->IsMultipleDriven()) - return nullptr; - - Instance *inst = n->Driver(); - - if (inst == nullptr) - return nullptr; - - if (!verific_sva_prims.count(inst->Type())) - return nullptr; - - if (inst->Type() == PRIM_SVA_ROSE || inst->Type() == PRIM_SVA_FELL || - inst->Type() == PRIM_SVA_STABLE || inst->Type() == OPER_SVA_STABLE || - inst->Type() == PRIM_SVA_PAST || inst->Type() == PRIM_SVA_TRIGGERED) - return nullptr; - - return inst; - } - - Instance *get_ast_input(Instance *inst) { return net_to_ast_driver(inst->GetInput()); } - Instance *get_ast_input1(Instance *inst) { return net_to_ast_driver(inst->GetInput1()); } - Instance *get_ast_input2(Instance *inst) { return net_to_ast_driver(inst->GetInput2()); } - Instance *get_ast_input3(Instance *inst) { return net_to_ast_driver(inst->GetInput3()); } - Instance *get_ast_control(Instance *inst) { return net_to_ast_driver(inst->GetControl()); } - - // ---------------------------------------------------------- - // SVA Importer - - struct ParserErrorException { - }; - - [[noreturn]] void parser_error(std::string errmsg) - { - if (!importer->mode_keep) - log_error("%s", errmsg.c_str()); - log_warning("%s", errmsg.c_str()); - throw ParserErrorException(); - } - - [[noreturn]] void parser_error(std::string errmsg, linefile_type loc) - { - parser_error(stringf("%s at %s:%d.\n", errmsg.c_str(), LineFile::GetFileName(loc), LineFile::GetLineNo(loc))); - } - - [[noreturn]] void parser_error(std::string errmsg, Instance *inst) - { - parser_error(stringf("%s at %s (%s)", errmsg.c_str(), inst->View()->Owner()->Name(), inst->Name()), inst->Linefile()); - } - - [[noreturn]] void parser_error(Instance *inst) - { - parser_error(stringf("Verific SVA primitive %s (%s) is currently unsupported in this context", - inst->View()->Owner()->Name(), inst->Name()), inst->Linefile()); - } - - dict check_expression_cache; - - bool check_expression(Net *net, bool raise_error = false) - { - while (!check_expression_cache.count(net)) - { - Instance *inst = net_to_ast_driver(net); - - if (inst == nullptr) { - check_expression_cache[net] = true; - break; - } - - if (inst->Type() == PRIM_SVA_AT) - { - VerificClocking new_clocking(importer, net); - log_assert(new_clocking.cond_net == nullptr); - if (!clocking.property_matches_sequence(new_clocking)) - parser_error("Mixed clocking is currently not supported", inst); - check_expression_cache[net] = check_expression(new_clocking.body_net, raise_error); - break; - } - - if (inst->Type() == PRIM_SVA_FIRST_MATCH || inst->Type() == PRIM_SVA_NOT) - { - check_expression_cache[net] = check_expression(inst->GetInput(), raise_error); - break; - } - - if (inst->Type() == PRIM_SVA_SEQ_OR || inst->Type() == PRIM_SVA_SEQ_AND || inst->Type() == PRIM_SVA_INTERSECT || - inst->Type() == PRIM_SVA_WITHIN || inst->Type() == PRIM_SVA_THROUGHOUT || - inst->Type() == PRIM_SVA_OR || inst->Type() == PRIM_SVA_AND) - { - check_expression_cache[net] = check_expression(inst->GetInput1(), raise_error) && check_expression(inst->GetInput2(), raise_error); - break; - } - - if (inst->Type() == PRIM_SVA_SEQ_CONCAT) - { - const char *sva_low_s = inst->GetAttValue("sva:low"); - const char *sva_high_s = inst->GetAttValue("sva:high"); - - int sva_low = atoi(sva_low_s); - int sva_high = atoi(sva_high_s); - bool sva_inf = !strcmp(sva_high_s, "$"); - - if (sva_low == 0 && sva_high == 0 && !sva_inf) - check_expression_cache[net] = check_expression(inst->GetInput1(), raise_error) && check_expression(inst->GetInput2(), raise_error); - else - check_expression_cache[net] = false; - break; - } - - check_expression_cache[net] = false; - } - - if (raise_error && !check_expression_cache.at(net)) - parser_error(net_to_ast_driver(net)); - return check_expression_cache.at(net); - } - - SigBit parse_expression(Net *net) - { - check_expression(net, true); - - Instance *inst = net_to_ast_driver(net); - - if (inst == nullptr) { - return importer->net_map_at(net); - } - - if (inst->Type() == PRIM_SVA_AT) - { - VerificClocking new_clocking(importer, net); - log_assert(new_clocking.cond_net == nullptr); - if (!clocking.property_matches_sequence(new_clocking)) - parser_error("Mixed clocking is currently not supported", inst); - return parse_expression(new_clocking.body_net); - } - - if (inst->Type() == PRIM_SVA_FIRST_MATCH) - return parse_expression(inst->GetInput()); - - if (inst->Type() == PRIM_SVA_NOT) - return module->Not(NEW_ID, parse_expression(inst->GetInput())); - - if (inst->Type() == PRIM_SVA_SEQ_OR || inst->Type() == PRIM_SVA_OR) - return module->Or(NEW_ID, parse_expression(inst->GetInput1()), parse_expression(inst->GetInput2())); - - if (inst->Type() == PRIM_SVA_SEQ_AND || inst->Type() == PRIM_SVA_AND || inst->Type() == PRIM_SVA_INTERSECT || - inst->Type() == PRIM_SVA_WITHIN || inst->Type() == PRIM_SVA_THROUGHOUT || inst->Type() == PRIM_SVA_SEQ_CONCAT) - return module->And(NEW_ID, parse_expression(inst->GetInput1()), parse_expression(inst->GetInput2())); - - log_abort(); - } - - bool check_zero_consecutive_repeat(Net *net) - { - Instance *inst = net_to_ast_driver(net); - - if (inst == nullptr) - return false; - - if (inst->Type() != PRIM_SVA_CONSECUTIVE_REPEAT) - return false; - - const char *sva_low_s = inst->GetAttValue("sva:low"); - int sva_low = atoi(sva_low_s); - - return sva_low == 0; - } - - int parse_consecutive_repeat(SvaFsm &fsm, int start_node, Net *net, bool add_pre_delay, bool add_post_delay) - { - Instance *inst = net_to_ast_driver(net); - - log_assert(inst->Type() == PRIM_SVA_CONSECUTIVE_REPEAT); - - const char *sva_low_s = inst->GetAttValue("sva:low"); - const char *sva_high_s = inst->GetAttValue("sva:high"); - - int sva_low = atoi(sva_low_s); - int sva_high = atoi(sva_high_s); - bool sva_inf = !strcmp(sva_high_s, "$"); - - Net *body_net = inst->GetInput(); - - if (add_pre_delay || add_post_delay) - log_assert(sva_low == 0); - - if (sva_low == 0) { - if (!add_pre_delay && !add_post_delay) - parser_error("Possibly zero-length consecutive repeat must follow or precede a delay of at least one cycle", inst); - sva_low++; - } - - int node = fsm.createNode(start_node); - start_node = node; - - if (add_pre_delay) { - node = fsm.createNode(start_node); - fsm.createEdge(start_node, node); - } - - int prev_node = node; - node = parse_sequence(fsm, node, body_net); - - for (int i = 1; i < sva_low; i++) - { - int next_node = fsm.createNode(); - fsm.createEdge(node, next_node); - - prev_node = node; - node = parse_sequence(fsm, next_node, body_net); - } - - if (sva_inf) - { - log_assert(prev_node >= 0); - fsm.createEdge(node, prev_node); - } - else - { - for (int i = sva_low; i < sva_high; i++) - { - int next_node = fsm.createNode(); - fsm.createEdge(node, next_node); - - prev_node = node; - node = parse_sequence(fsm, next_node, body_net); - - fsm.createLink(prev_node, node); - } - } - - if (add_post_delay) { - int next_node = fsm.createNode(); - fsm.createEdge(node, next_node); - node = next_node; - } - - if (add_pre_delay || add_post_delay) - fsm.createLink(start_node, node); - - return node; - } - - int parse_sequence(SvaFsm &fsm, int start_node, Net *net) - { - if (check_expression(net)) { - int node = fsm.createNode(); - fsm.createLink(start_node, node, parse_expression(net)); - return node; - } - - Instance *inst = net_to_ast_driver(net); - - if (inst->Type() == PRIM_SVA_AT) - { - VerificClocking new_clocking(importer, net); - log_assert(new_clocking.cond_net == nullptr); - if (!clocking.property_matches_sequence(new_clocking)) - parser_error("Mixed clocking is currently not supported", inst); - return parse_sequence(fsm, start_node, new_clocking.body_net); - } - - if (inst->Type() == PRIM_SVA_FIRST_MATCH) - { - SvaFsm match_fsm(clocking); - match_fsm.createLink(parse_sequence(match_fsm, match_fsm.createStartNode(), inst->GetInput()), match_fsm.acceptNode); - - int node = fsm.createNode(); - match_fsm.getDFsm(fsm, start_node, node); - - if (verific_verbose) { - log(" First Match FSM:\n"); - match_fsm.dump(); - } - - return node; - } - - if (inst->Type() == PRIM_SVA_SEQ_CONCAT) - { - const char *sva_low_s = inst->GetAttValue("sva:low"); - const char *sva_high_s = inst->GetAttValue("sva:high"); - - int sva_low = atoi(sva_low_s); - int sva_high = atoi(sva_high_s); - bool sva_inf = !strcmp(sva_high_s, "$"); - - int node = -1; - bool past_add_delay = false; - - if (check_zero_consecutive_repeat(inst->GetInput1()) && sva_low > 0) { - node = parse_consecutive_repeat(fsm, start_node, inst->GetInput1(), false, true); - sva_low--, sva_high--; - } else { - node = parse_sequence(fsm, start_node, inst->GetInput1()); - } - - if (check_zero_consecutive_repeat(inst->GetInput2()) && sva_low > 0) { - past_add_delay = true; - sva_low--, sva_high--; - } - - for (int i = 0; i < sva_low; i++) { - int next_node = fsm.createNode(); - fsm.createEdge(node, next_node); - node = next_node; - } - - if (sva_inf) - { - fsm.createEdge(node, node); - } - else - { - for (int i = sva_low; i < sva_high; i++) - { - int next_node = fsm.createNode(); - fsm.createEdge(node, next_node); - fsm.createLink(node, next_node); - node = next_node; - } - } - - if (past_add_delay) - node = parse_consecutive_repeat(fsm, node, inst->GetInput2(), true, false); - else - node = parse_sequence(fsm, node, inst->GetInput2()); - - return node; - } - - if (inst->Type() == PRIM_SVA_CONSECUTIVE_REPEAT) - { - return parse_consecutive_repeat(fsm, start_node, net, false, false); - } - - if (inst->Type() == PRIM_SVA_NON_CONSECUTIVE_REPEAT || inst->Type() == PRIM_SVA_GOTO_REPEAT) - { - const char *sva_low_s = inst->GetAttValue("sva:low"); - const char *sva_high_s = inst->GetAttValue("sva:high"); - - int sva_low = atoi(sva_low_s); - int sva_high = atoi(sva_high_s); - bool sva_inf = !strcmp(sva_high_s, "$"); - - Net *body_net = inst->GetInput(); - int node = fsm.createNode(start_node); - - SigBit cond = parse_expression(body_net); - SigBit not_cond = module->Not(NEW_ID, cond); - - for (int i = 0; i < sva_low; i++) - { - int wait_node = fsm.createNode(); - fsm.createEdge(wait_node, wait_node, not_cond); - - if (i == 0) - fsm.createLink(node, wait_node); - else - fsm.createEdge(node, wait_node); - - int next_node = fsm.createNode(); - fsm.createLink(wait_node, next_node, cond); - - node = next_node; - } - - if (sva_inf) - { - int wait_node = fsm.createNode(); - fsm.createEdge(wait_node, wait_node, not_cond); - fsm.createEdge(node, wait_node); - fsm.createLink(wait_node, node, cond); - } - else - { - for (int i = sva_low; i < sva_high; i++) - { - int wait_node = fsm.createNode(); - fsm.createEdge(wait_node, wait_node, not_cond); - - if (i == 0) - fsm.createLink(node, wait_node); - else - fsm.createEdge(node, wait_node); - - int next_node = fsm.createNode(); - fsm.createLink(wait_node, next_node, cond); - - fsm.createLink(node, next_node); - node = next_node; - } - } - - if (inst->Type() == PRIM_SVA_NON_CONSECUTIVE_REPEAT) - fsm.createEdge(node, node); - - return node; - } - - if (inst->Type() == PRIM_SVA_SEQ_OR || inst->Type() == PRIM_SVA_OR) - { - int node = parse_sequence(fsm, start_node, inst->GetInput1()); - int node2 = parse_sequence(fsm, start_node, inst->GetInput2()); - fsm.createLink(node2, node); - return node; - } - - if (inst->Type() == PRIM_SVA_SEQ_AND || inst->Type() == PRIM_SVA_AND) - { - SvaFsm fsm1(clocking); - fsm1.createLink(parse_sequence(fsm1, fsm1.createStartNode(), inst->GetInput1()), fsm1.acceptNode); - - SvaFsm fsm2(clocking); - fsm2.createLink(parse_sequence(fsm2, fsm2.createStartNode(), inst->GetInput2()), fsm2.acceptNode); - - SvaFsm combined_fsm(clocking); - fsm1.getDFsm(combined_fsm, combined_fsm.createStartNode(), -1, combined_fsm.acceptNode); - fsm2.getDFsm(combined_fsm, combined_fsm.createStartNode(), -1, combined_fsm.acceptNode); - - int node = fsm.createNode(); - combined_fsm.getDFsm(fsm, start_node, -1, node); - - if (verific_verbose) - { - log(" Left And FSM:\n"); - fsm1.dump(); - - log(" Right And FSM:\n"); - fsm1.dump(); - - log(" Combined And FSM:\n"); - combined_fsm.dump(); - } - - return node; - } - - if (inst->Type() == PRIM_SVA_INTERSECT || inst->Type() == PRIM_SVA_WITHIN) - { - SvaFsm intersect_fsm(clocking); - - if (inst->Type() == PRIM_SVA_INTERSECT) - { - intersect_fsm.createLink(parse_sequence(intersect_fsm, intersect_fsm.createStartNode(), inst->GetInput1()), intersect_fsm.acceptNode); - } - else - { - int n = intersect_fsm.createNode(); - intersect_fsm.createLink(intersect_fsm.createStartNode(), n); - intersect_fsm.createEdge(n, n); - - n = parse_sequence(intersect_fsm, n, inst->GetInput1()); - - intersect_fsm.createLink(n, intersect_fsm.acceptNode); - intersect_fsm.createEdge(n, n); - } - - intersect_fsm.in_cond_mode = true; - intersect_fsm.createLink(parse_sequence(intersect_fsm, intersect_fsm.createStartNode(), inst->GetInput2()), intersect_fsm.condNode); - intersect_fsm.in_cond_mode = false; - - int node = fsm.createNode(); - intersect_fsm.getDFsm(fsm, start_node, node, -1, false, true); - - if (verific_verbose) { - log(" Intersect FSM:\n"); - intersect_fsm.dump(); - } - - return node; - } - - if (inst->Type() == PRIM_SVA_THROUGHOUT) - { - SigBit expr = parse_expression(inst->GetInput1()); - - fsm.pushThroughout(expr); - int node = parse_sequence(fsm, start_node, inst->GetInput2()); - fsm.popThroughout(); - - return node; - } - - parser_error(inst); - } - - void get_fsm_accept_reject(SvaFsm &fsm, SigBit *accept_p, SigBit *reject_p, bool swap_accept_reject = false) - { - log_assert(accept_p != nullptr || reject_p != nullptr); - - if (swap_accept_reject) - get_fsm_accept_reject(fsm, reject_p, accept_p); - else if (reject_p == nullptr) - *accept_p = fsm.getAccept(); - else if (accept_p == nullptr) - *reject_p = fsm.getReject(); - else - fsm.getFirstAcceptReject(accept_p, reject_p); - } - - bool eventually_property(Net *&net, SigBit &trig) - { - Instance *inst = net_to_ast_driver(net); - - if (inst == nullptr) - return false; - - if (clocking.cond_net != nullptr) - trig = importer->net_map_at(clocking.cond_net); - else - trig = State::S1; - - if (inst->Type() == PRIM_SVA_S_EVENTUALLY || inst->Type() == PRIM_SVA_EVENTUALLY) - { - if (mode_cover || mode_trigger) - parser_error(inst); - - net = inst->GetInput(); - clocking.cond_net = nullptr; - - return true; - } - - if (inst->Type() == PRIM_SVA_OVERLAPPED_IMPLICATION || - inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) - { - Net *antecedent_net = inst->GetInput1(); - Net *consequent_net = inst->GetInput2(); - - Instance *consequent_inst = net_to_ast_driver(consequent_net); - - if (consequent_inst == nullptr) - return false; - - if (consequent_inst->Type() != PRIM_SVA_S_EVENTUALLY && consequent_inst->Type() != PRIM_SVA_EVENTUALLY) - return false; - - if (mode_cover || mode_trigger) - parser_error(consequent_inst); - - int node; - - SvaFsm antecedent_fsm(clocking, trig); - node = parse_sequence(antecedent_fsm, antecedent_fsm.createStartNode(), antecedent_net); - if (inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) { - int next_node = antecedent_fsm.createNode(); - antecedent_fsm.createEdge(node, next_node); - node = next_node; - } - antecedent_fsm.createLink(node, antecedent_fsm.acceptNode); - - trig = antecedent_fsm.getAccept(); - net = consequent_inst->GetInput(); - clocking.cond_net = nullptr; - - if (verific_verbose) { - log(" Eventually Antecedent FSM:\n"); - antecedent_fsm.dump(); - } - - return true; - } - - return false; - } - - void parse_property(Net *net, SigBit *accept_p, SigBit *reject_p) - { - Instance *inst = net_to_ast_driver(net); - - SigBit trig = State::S1; - - if (clocking.cond_net != nullptr) - trig = importer->net_map_at(clocking.cond_net); - - if (inst == nullptr) - { - log_assert(trig == State::S1); - - if (accept_p != nullptr) - *accept_p = importer->net_map_at(net); - if (reject_p != nullptr) - *reject_p = module->Not(NEW_ID, importer->net_map_at(net)); - } - else - if (inst->Type() == PRIM_SVA_OVERLAPPED_IMPLICATION || - inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) - { - Net *antecedent_net = inst->GetInput1(); - Net *consequent_net = inst->GetInput2(); - int node; - - SvaFsm antecedent_fsm(clocking, trig); - node = parse_sequence(antecedent_fsm, antecedent_fsm.createStartNode(), antecedent_net); - if (inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) { - int next_node = antecedent_fsm.createNode(); - antecedent_fsm.createEdge(node, next_node); - node = next_node; - } - - Instance *consequent_inst = net_to_ast_driver(consequent_net); - - if (consequent_inst && (consequent_inst->Type() == PRIM_SVA_UNTIL || consequent_inst->Type() == PRIM_SVA_S_UNTIL || - consequent_inst->Type() == PRIM_SVA_UNTIL_WITH || consequent_inst->Type() == PRIM_SVA_S_UNTIL_WITH)) - { - bool until_with = consequent_inst->Type() == PRIM_SVA_UNTIL_WITH || consequent_inst->Type() == PRIM_SVA_S_UNTIL_WITH; - - Net *until_net = consequent_inst->GetInput2(); - consequent_net = consequent_inst->GetInput1(); - consequent_inst = net_to_ast_driver(consequent_net); - - SigBit until_sig = parse_expression(until_net); - SigBit not_until_sig = module->Not(NEW_ID, until_sig); - antecedent_fsm.createEdge(node, node, not_until_sig); - - antecedent_fsm.createLink(node, antecedent_fsm.acceptNode, until_with ? State::S1 : not_until_sig); - } - else - { - antecedent_fsm.createLink(node, antecedent_fsm.acceptNode); - } - - SigBit antecedent_match = antecedent_fsm.getAccept(); - - if (verific_verbose) { - log(" Antecedent FSM:\n"); - antecedent_fsm.dump(); - } - - bool consequent_not = false; - if (consequent_inst && consequent_inst->Type() == PRIM_SVA_NOT) { - consequent_not = true; - consequent_net = consequent_inst->GetInput(); - consequent_inst = net_to_ast_driver(consequent_net); - } - - SvaFsm consequent_fsm(clocking, antecedent_match); - node = parse_sequence(consequent_fsm, consequent_fsm.createStartNode(), consequent_net); - consequent_fsm.createLink(node, consequent_fsm.acceptNode); - - get_fsm_accept_reject(consequent_fsm, accept_p, reject_p, consequent_not); - - if (verific_verbose) { - log(" Consequent FSM:\n"); - consequent_fsm.dump(); - } - } - else - { - bool prop_not = inst->Type() == PRIM_SVA_NOT; - if (prop_not) { - net = inst->GetInput(); - inst = net_to_ast_driver(net); - } - - SvaFsm fsm(clocking, trig); - int node = parse_sequence(fsm, fsm.createStartNode(), net); - fsm.createLink(node, fsm.acceptNode); - - get_fsm_accept_reject(fsm, accept_p, reject_p, prop_not); - - if (verific_verbose) { - log(" Sequence FSM:\n"); - fsm.dump(); - } - } - } - - void import() - { - try - { - module = importer->module; - netlist = root->Owner(); - - if (verific_verbose) - log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(), - LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile())); - - bool is_user_declared = root->IsUserDeclared(); - - // FIXME - if (!is_user_declared) { - const char *name = root->Name(); - for (int i = 0; name[i]; i++) { - if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) { - is_user_declared = true; - break; - } - } - } - - RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID); - - // parse SVA sequence into trigger signal - - clocking = VerificClocking(importer, root->GetInput(), true); - SigBit accept_bit = State::S0, reject_bit = State::S0; - - if (clocking.body_net == nullptr) - { - if (clocking.clock_net != nullptr || clocking.enable_net != nullptr || clocking.disable_net != nullptr || clocking.cond_net != nullptr) - parser_error(stringf("Failed to parse SVA clocking"), root); - - if (mode_assert || mode_assume) { - reject_bit = module->Not(NEW_ID, parse_expression(root->GetInput())); - } else { - accept_bit = parse_expression(root->GetInput()); - } - } - else - { - Net *net = clocking.body_net; - SigBit trig; - - if (eventually_property(net, trig)) - { - SigBit sig_a, sig_en = trig; - parse_property(net, &sig_a, nullptr); - - // add final FF stage - - SigBit sig_a_q, sig_en_q; - - if (clocking.body_net == nullptr) { - sig_a_q = sig_a; - sig_en_q = sig_en; - } else { - sig_a_q = module->addWire(NEW_ID); - sig_en_q = module->addWire(NEW_ID); - clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0); - clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0); - } - - // generate fair/live cell - - RTLIL::Cell *c = nullptr; - - if (mode_assert) c = module->addLive(root_name, sig_a_q, sig_en_q); - if (mode_assume) c = module->addFair(root_name, sig_a_q, sig_en_q); - - importer->import_attributes(c->attributes, root); - - return; - } - else - { - if (mode_assert || mode_assume) { - parse_property(net, nullptr, &reject_bit); - } else { - parse_property(net, &accept_bit, nullptr); - } - } - } - - if (mode_trigger) - { - module->connect(importer->net_map_at(root->GetOutput()), accept_bit); - } - else - { - SigBit sig_a = module->Not(NEW_ID, reject_bit); - SigBit sig_en = module->Or(NEW_ID, accept_bit, reject_bit); - - // add final FF stage - - SigBit sig_a_q, sig_en_q; - - if (clocking.body_net == nullptr) { - sig_a_q = sig_a; - sig_en_q = sig_en; - } else { - sig_a_q = module->addWire(NEW_ID); - sig_en_q = module->addWire(NEW_ID); - clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0); - clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0); - } - - // generate assert/assume/cover cell - - RTLIL::Cell *c = nullptr; - - if (mode_assert) c = module->addAssert(root_name, sig_a_q, sig_en_q); - if (mode_assume) c = module->addAssume(root_name, sig_a_q, sig_en_q); - if (mode_cover) c = module->addCover(root_name, sig_a_q, sig_en_q); - - importer->import_attributes(c->attributes, root); - } - } - catch (ParserErrorException) - { - } - } -}; - -void verific_import_sva_assert(VerificImporter *importer, Instance *inst) -{ - VerificSvaImporter worker; - worker.importer = importer; - worker.root = inst; - worker.mode_assert = true; - worker.import(); -} - -void verific_import_sva_assume(VerificImporter *importer, Instance *inst) -{ - VerificSvaImporter worker; - worker.importer = importer; - worker.root = inst; - worker.mode_assume = true; - worker.import(); -} - -void verific_import_sva_cover(VerificImporter *importer, Instance *inst) -{ - VerificSvaImporter worker; - worker.importer = importer; - worker.root = inst; - worker.mode_cover = true; - worker.import(); -} - -void verific_import_sva_trigger(VerificImporter *importer, Instance *inst) -{ - VerificSvaImporter worker; - worker.importer = importer; - worker.root = inst; - worker.mode_trigger = true; - worker.import(); -} - -bool verific_is_sva_net(VerificImporter *importer, Verific::Net *net) -{ - VerificSvaImporter worker; - worker.importer = importer; - return worker.net_to_ast_driver(net) != nullptr; -} - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/verilog/.gitignore b/yosys/frontends/verilog/.gitignore deleted file mode 100644 index aadbcdcdd..000000000 --- a/yosys/frontends/verilog/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -verilog_lexer.cc -verilog_parser.output -verilog_parser.tab.cc -verilog_parser.tab.hh diff --git a/yosys/frontends/verilog/Makefile.inc b/yosys/frontends/verilog/Makefile.inc deleted file mode 100644 index 6a8462b41..000000000 --- a/yosys/frontends/verilog/Makefile.inc +++ /dev/null @@ -1,24 +0,0 @@ - -GENFILES += frontends/verilog/verilog_parser.tab.cc -GENFILES += frontends/verilog/verilog_parser.tab.hh -GENFILES += frontends/verilog/verilog_parser.output -GENFILES += frontends/verilog/verilog_lexer.cc - -frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y - $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -o $@ -d -r all -b frontends/verilog/verilog_parser $< - -frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc - -frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l - $(Q) mkdir -p $(dir $@) - $(P) flex -o frontends/verilog/verilog_lexer.cc $< - -frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000 - -OBJS += frontends/verilog/verilog_parser.tab.o -OBJS += frontends/verilog/verilog_lexer.o -OBJS += frontends/verilog/preproc.o -OBJS += frontends/verilog/verilog_frontend.o -OBJS += frontends/verilog/const2ast.o - diff --git a/yosys/frontends/verilog/const2ast.cc b/yosys/frontends/verilog/const2ast.cc deleted file mode 100644 index f6a17b242..000000000 --- a/yosys/frontends/verilog/const2ast.cc +++ /dev/null @@ -1,249 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * The Verilog frontend. - * - * This frontend is using the AST frontend library (see frontends/ast/). - * Thus this frontend does not generate RTLIL code directly but creates an - * AST directly from the Verilog parse tree and then passes this AST to - * the AST frontend library. - * - * --- - * - * This file contains an ad-hoc parser for Verilog constants. The Verilog - * lexer does only recognize a constant but does not actually split it to its - * components. I.e. it just passes the Verilog code for the constant to the - * bison parser. The parser then uses the function const2ast() from this file - * to create an AST node for the constant. - * - */ - -#include "verilog_frontend.h" -#include "kernel/log.h" -#include -#include - -YOSYS_NAMESPACE_BEGIN - -using namespace AST; - -// divide an arbitrary length decimal number by two and return the rest -static int my_decimal_div_by_two(std::vector &digits) -{ - int carry = 0; - for (size_t i = 0; i < digits.size(); i++) { - if (digits[i] >= 10) - log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n"); - digits[i] += carry * 10; - carry = digits[i] % 2; - digits[i] /= 2; - } - while (!digits.empty() && !digits.front()) - digits.erase(digits.begin()); - return carry; -} - -// find the number of significant bits in a binary number (not including the sign bit) -static int my_ilog2(int x) -{ - int ret = 0; - while (x != 0 && x != -1) { - x = x >> 1; - ret++; - } - return ret; -} - -// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?') -static void my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized) -{ - // all digits in string (MSB at index 0) - std::vector digits; - - while (*str) { - if ('0' <= *str && *str <= '9') - digits.push_back(*str - '0'); - else if ('a' <= *str && *str <= 'f') - digits.push_back(10 + *str - 'a'); - else if ('A' <= *str && *str <= 'F') - digits.push_back(10 + *str - 'A'); - else if (*str == 'x' || *str == 'X') - digits.push_back(0xf0); - else if (*str == 'z' || *str == 'Z') - digits.push_back(0xf1); - else if (*str == '?') - digits.push_back(0xf2); - str++; - } - - if (base == 10 && GetSize(digits) == 1 && digits.front() >= 0xf0) - base = 2; - - data.clear(); - - if (base == 10) { - while (!digits.empty()) - data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0); - } else { - int bits_per_digit = my_ilog2(base-1); - for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) { - if (*it > (base-1) && *it < 0xf0) - log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n", - base-1, base); - for (int i = 0; i < bits_per_digit; i++) { - int bitmask = 1 << i; - if (*it == 0xf0) - data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx); - else if (*it == 0xf1) - data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz); - else if (*it == 0xf2) - data.push_back(RTLIL::Sa); - else - data.push_back((*it & bitmask) ? RTLIL::S1 : RTLIL::S0); - } - } - } - - int len = GetSize(data); - RTLIL::State msb = data.empty() ? RTLIL::S0 : data.back(); - - if (len_in_bits < 0) { - if (len < 32) - data.resize(32, msb == RTLIL::S0 || msb == RTLIL::S1 ? RTLIL::S0 : msb); - return; - } - - if (is_unsized && (len > len_in_bits)) - log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len); - - for (len = len - 1; len >= 0; len--) - if (data[len] == RTLIL::S1) - break; - if (msb == RTLIL::S0 || msb == RTLIL::S1) { - len += 1; - data.resize(len_in_bits, RTLIL::S0); - } else { - len += 2; - data.resize(len_in_bits, msb); - } - - if (len > len_in_bits) - log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n", - len_in_bits, len, current_filename.c_str(), get_line_num()); -} - -// convert the Verilog code for a constant to an AST node -AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z) -{ - if (warn_z) { - AstNode *ret = const2ast(code, case_type); - if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) - log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n", - current_filename.c_str(), get_line_num()); - return ret; - } - - const char *str = code.c_str(); - - // Strings - if (*str == '"') { - int len = strlen(str) - 2; - std::vector data; - data.reserve(len * 8); - for (int i = 0; i < len; i++) { - unsigned char ch = str[len - i]; - for (int j = 0; j < 8; j++) { - data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0); - ch = ch >> 1; - } - } - AstNode *ast = AstNode::mkconst_bits(data, false); - ast->str = code; - return ast; - } - - for (size_t i = 0; i < code.size(); i++) - if (code[i] == '_' || code[i] == ' ' || code[i] == '\t' || code[i] == '\r' || code[i] == '\n') - code.erase(code.begin()+(i--)); - str = code.c_str(); - - char *endptr; - long len_in_bits = strtol(str, &endptr, 10); - - // Simple base-10 integer - if (*endptr == 0) { - std::vector data; - my_strtobin(data, str, -1, 10, case_type, false); - if (data.back() == RTLIL::S1) - data.push_back(RTLIL::S0); - return AstNode::mkconst_bits(data, true); - } - - // unsized constant - if (str == endptr) - len_in_bits = -1; - - // The "'s?[bodhBODH]" syntax - if (*endptr == '\'') - { - std::vector data; - bool is_signed = false; - bool is_unsized = len_in_bits < 0; - if (*(endptr+1) == 's') { - is_signed = true; - endptr++; - } - switch (*(endptr+1)) - { - case 'b': - case 'B': - my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized); - break; - case 'o': - case 'O': - my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized); - break; - case 'd': - case 'D': - my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized); - break; - case 'h': - case 'H': - my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized); - break; - default: - char next_char = char(tolower(*(endptr+1))); - if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') { - is_unsized = true; - my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized); - } else { - return NULL; - } - } - if (len_in_bits < 0) { - if (is_signed && data.back() == RTLIL::S1) - data.push_back(RTLIL::S0); - } - return AstNode::mkconst_bits(data, is_signed, is_unsized); - } - - return NULL; -} - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/verilog/preproc.cc b/yosys/frontends/verilog/preproc.cc deleted file mode 100644 index dea22ee8a..000000000 --- a/yosys/frontends/verilog/preproc.cc +++ /dev/null @@ -1,547 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * The Verilog frontend. - * - * This frontend is using the AST frontend library (see frontends/ast/). - * Thus this frontend does not generate RTLIL code directly but creates an - * AST directly from the Verilog parse tree and then passes this AST to - * the AST frontend library. - * - * --- - * - * Ad-hoc implementation of a Verilog preprocessor. The directives `define, - * `include, `ifdef, `ifndef, `else and `endif are handled here. All other - * directives are handled by the lexer (see lexer.l). - * - */ - -#include "verilog_frontend.h" -#include "kernel/log.h" -#include -#include -#include - -YOSYS_NAMESPACE_BEGIN -using namespace VERILOG_FRONTEND; - -static std::list output_code; -static std::list input_buffer; -static size_t input_buffer_charp; - -static void return_char(char ch) -{ - if (input_buffer_charp == 0) - input_buffer.push_front(std::string() + ch); - else - input_buffer.front()[--input_buffer_charp] = ch; -} - -static void insert_input(std::string str) -{ - if (input_buffer_charp != 0) { - input_buffer.front() = input_buffer.front().substr(input_buffer_charp); - input_buffer_charp = 0; - } - input_buffer.push_front(str); -} - -static char next_char() -{ - if (input_buffer.empty()) - return 0; - - log_assert(input_buffer_charp <= input_buffer.front().size()); - if (input_buffer_charp == input_buffer.front().size()) { - input_buffer_charp = 0; - input_buffer.pop_front(); - return next_char(); - } - - char ch = input_buffer.front()[input_buffer_charp++]; - return ch == '\r' ? next_char() : ch; -} - -static std::string skip_spaces() -{ - std::string spaces; - while (1) { - char ch = next_char(); - if (ch == 0) - break; - if (ch != ' ' && ch != '\t') { - return_char(ch); - break; - } - spaces += ch; - } - return spaces; -} - -static std::string next_token(bool pass_newline = false) -{ - std::string token; - - char ch = next_char(); - if (ch == 0) - return token; - - token += ch; - if (ch == '\n') { - if (pass_newline) { - output_code.push_back(token); - return ""; - } - return token; - } - - if (ch == ' ' || ch == '\t') - { - while ((ch = next_char()) != 0) { - if (ch != ' ' && ch != '\t') { - return_char(ch); - break; - } - token += ch; - } - } - else if (ch == '"') - { - while ((ch = next_char()) != 0) { - token += ch; - if (ch == '"') - break; - if (ch == '\\') { - if ((ch = next_char()) != 0) - token += ch; - } - } - if (token == "\"\"" && (ch = next_char()) != 0) { - if (ch == '"') - token += ch; - else - return_char(ch); - } - } - else if (ch == '/') - { - if ((ch = next_char()) != 0) { - if (ch == '/') { - token += '*'; - char last_ch = 0; - while ((ch = next_char()) != 0) { - if (ch == '\n') { - return_char(ch); - break; - } - if (last_ch != '*' || ch != '/') { - token += ch; - last_ch = ch; - } - } - token += " */"; - } - else if (ch == '*') { - token += '*'; - int newline_count = 0; - char last_ch = 0; - while ((ch = next_char()) != 0) { - if (ch == '\n') { - newline_count++; - token += ' '; - } else - token += ch; - if (last_ch == '*' && ch == '/') - break; - last_ch = ch; - } - while (newline_count-- > 0) - return_char('\n'); - } - else - return_char(ch); - } - } - else - { - const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789"; - if (ch == '`' || strchr(ok, ch) != NULL) - { - char first = ch; - ch = next_char(); - if (first == '`' && (ch == '"' || ch == '`')) { - token += ch; - } else do { - if (strchr(ok, ch) == NULL) { - return_char(ch); - break; - } - token += ch; - } while ((ch = next_char()) != 0); - } - } - return token; -} - -static void input_file(std::istream &f, std::string filename) -{ - char buffer[513]; - int rc; - - insert_input(""); - auto it = input_buffer.begin(); - - input_buffer.insert(it, "`file_push \"" + filename + "\"\n"); - while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) { - buffer[rc] = 0; - input_buffer.insert(it, buffer); - } - input_buffer.insert(it, "\n`file_pop\n"); -} - - -static bool try_expand_macro(std::set &defines_with_args, - std::map &defines_map, - std::string &tok - ) -{ - if (tok == "`\"") { - std::string literal("\""); - // Expand string literal - while (!input_buffer.empty()) { - std::string ntok = next_token(); - if (ntok == "`\"") { - insert_input(literal+"\""); - return true; - } else if (!try_expand_macro(defines_with_args, defines_map, ntok)) { - literal += ntok; - } - } - return false; // error - unmatched `" - } else if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) { - std::string name = tok.substr(1); - // printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str()); - std::string skipped_spaces = skip_spaces(); - tok = next_token(false); - if (tok == "(" && defines_with_args.count(name) > 0) { - int level = 1; - std::vector args; - args.push_back(std::string()); - while (1) - { - skip_spaces(); - tok = next_token(true); - if (tok == ")" || tok == "}" || tok == "]") - level--; - if (level == 0) - break; - if (level == 1 && tok == ",") - args.push_back(std::string()); - else - args.back() += tok; - if (tok == "(" || tok == "{" || tok == "[") - level++; - } - for (int i = 0; i < GetSize(args); i++) - defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i]; - } else { - insert_input(tok); - insert_input(skipped_spaces); - } - insert_input(defines_map[name]); - return true; - } else if (tok == "``") { - // Swallow `` in macro expansion - return true; - } else return false; -} - -std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map &pre_defines_map, - dict> &global_defines_cache, const std::list &include_dirs) -{ - std::set defines_with_args; - std::map defines_map(pre_defines_map); - std::vector filename_stack; - int ifdef_fail_level = 0; - bool in_elseif = false; - - output_code.clear(); - input_buffer.clear(); - input_buffer_charp = 0; - - input_file(f, filename); - - defines_map["YOSYS"] = "1"; - defines_map[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1"; - - for (auto &it : pre_defines_map) - defines_map[it.first] = it.second; - - for (auto &it : global_defines_cache) { - if (it.second.second) - defines_with_args.insert(it.first); - defines_map[it.first] = it.second.first; - } - - while (!input_buffer.empty()) - { - std::string tok = next_token(); - // printf("token: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE"); - - if (tok == "`endif") { - if (ifdef_fail_level > 0) - ifdef_fail_level--; - if (ifdef_fail_level == 0) - in_elseif = false; - continue; - } - - if (tok == "`else") { - if (ifdef_fail_level == 0) - ifdef_fail_level = 1; - else if (ifdef_fail_level == 1 && !in_elseif) - ifdef_fail_level = 0; - continue; - } - - if (tok == "`elsif") { - skip_spaces(); - std::string name = next_token(true); - if (ifdef_fail_level == 0) - ifdef_fail_level = 1, in_elseif = true; - else if (ifdef_fail_level == 1 && defines_map.count(name) != 0) - ifdef_fail_level = 0, in_elseif = true; - continue; - } - - if (tok == "`ifdef") { - skip_spaces(); - std::string name = next_token(true); - if (ifdef_fail_level > 0 || defines_map.count(name) == 0) - ifdef_fail_level++; - continue; - } - - if (tok == "`ifndef") { - skip_spaces(); - std::string name = next_token(true); - if (ifdef_fail_level > 0 || defines_map.count(name) != 0) - ifdef_fail_level++; - continue; - } - - if (ifdef_fail_level > 0) { - if (tok == "\n") - output_code.push_back(tok); - continue; - } - - if (tok == "`include") { - skip_spaces(); - std::string fn = next_token(true); - while (try_expand_macro(defines_with_args, defines_map, fn)) { - fn = next_token(); - } - while (1) { - size_t pos = fn.find('"'); - if (pos == std::string::npos) - break; - if (pos == 0) - fn = fn.substr(1); - else - fn = fn.substr(0, pos) + fn.substr(pos+1); - } - std::ifstream ff; - ff.clear(); - std::string fixed_fn = fn; - ff.open(fixed_fn.c_str()); - - bool filename_path_sep_found; - bool fn_relative; -#ifdef _WIN32 - // Both forward and backslash are acceptable separators on Windows. - filename_path_sep_found = (filename.find_first_of("/\\") != std::string::npos); - // Easier just to invert the check for an absolute path (e.g. C:\ or C:/) - fn_relative = !(fn[1] == ':' && (fn[2] == '/' || fn[2] == '\\')); -#else - filename_path_sep_found = (filename.find('/') != std::string::npos); - fn_relative = (fn[0] != '/'); -#endif - - if (ff.fail() && fn.size() > 0 && fn_relative && filename_path_sep_found) { - // if the include file was not found, it is not given with an absolute path, and the - // currently read file is given with a path, then try again relative to its directory - ff.clear(); -#ifdef _WIN32 - fixed_fn = filename.substr(0, filename.find_last_of("/\\")+1) + fn; -#else - fixed_fn = filename.substr(0, filename.rfind('/')+1) + fn; -#endif - ff.open(fixed_fn); - } - if (ff.fail() && fn.size() > 0 && fn_relative) { - // if the include file was not found and it is not given with an absolute path, then - // search it in the include path - for (auto incdir : include_dirs) { - ff.clear(); - fixed_fn = incdir + '/' + fn; - ff.open(fixed_fn); - if (!ff.fail()) break; - } - } - if (ff.fail()) { - output_code.push_back("`file_notfound " + fn); - } else { - input_file(ff, fixed_fn); - yosys_input_files.insert(fixed_fn); - } - continue; - } - - if (tok == "`file_push") { - skip_spaces(); - std::string fn = next_token(true); - if (!fn.empty() && fn.front() == '"' && fn.back() == '"') - fn = fn.substr(1, fn.size()-2); - output_code.push_back(tok + " \"" + fn + "\""); - filename_stack.push_back(filename); - filename = fn; - continue; - } - - if (tok == "`file_pop") { - output_code.push_back(tok); - filename = filename_stack.back(); - filename_stack.pop_back(); - continue; - } - - if (tok == "`define") { - std::string name, value; - std::map args; - skip_spaces(); - name = next_token(true); - bool here_doc_mode = false; - int newline_count = 0; - int state = 0; - if (skip_spaces() != "") - state = 3; - while (!tok.empty()) { - tok = next_token(); - if (tok == "\"\"\"") { - here_doc_mode = !here_doc_mode; - continue; - } - if (state == 0 && tok == "(") { - state = 1; - skip_spaces(); - } else - if (state == 1) { - if (tok == ")") - state = 2; - else if (tok != ",") { - int arg_idx = args.size()+1; - args[tok] = arg_idx; - } - skip_spaces(); - } else { - if (state != 2) - state = 3; - if (tok == "\n") { - if (here_doc_mode) { - value += " "; - newline_count++; - } else { - return_char('\n'); - break; - } - } else - if (tok == "\\") { - char ch = next_char(); - if (ch == '\n') { - value += " "; - newline_count++; - } else { - value += std::string("\\"); - return_char(ch); - } - } else - if (args.count(tok) > 0) - value += stringf("`macro_%s_arg%d", name.c_str(), args.at(tok)); - else - value += tok; - } - } - while (newline_count-- > 0) - return_char('\n'); - // printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str()); - defines_map[name] = value; - if (state == 2) - defines_with_args.insert(name); - else - defines_with_args.erase(name); - global_defines_cache[name] = std::pair(value, state == 2); - continue; - } - - if (tok == "`undef") { - std::string name; - skip_spaces(); - name = next_token(true); - // printf("undef: >>%s<<\n", name.c_str()); - defines_map.erase(name); - defines_with_args.erase(name); - global_defines_cache.erase(name); - continue; - } - - if (tok == "`timescale") { - skip_spaces(); - while (!tok.empty() && tok != "\n") - tok = next_token(true); - if (tok == "\n") - return_char('\n'); - continue; - } - - if (tok == "`resetall") { - defines_map.clear(); - defines_with_args.clear(); - global_defines_cache.clear(); - continue; - } - - if (try_expand_macro(defines_with_args, defines_map, tok)) - continue; - - output_code.push_back(tok); - } - - std::string output; - for (auto &str : output_code) - output += str; - - output_code.clear(); - input_buffer.clear(); - input_buffer_charp = 0; - - return output; -} - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/verilog/verilog_frontend.cc b/yosys/frontends/verilog/verilog_frontend.cc deleted file mode 100644 index 0e2bead6f..000000000 --- a/yosys/frontends/verilog/verilog_frontend.cc +++ /dev/null @@ -1,614 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * The Verilog frontend. - * - * This frontend is using the AST frontend library (see frontends/ast/). - * Thus this frontend does not generate RTLIL code directly but creates an - * AST directly from the Verilog parse tree and then passes this AST to - * the AST frontend library. - * - */ - -#include "verilog_frontend.h" -#include "kernel/yosys.h" -#include "libs/sha1/sha1.h" -#include - -YOSYS_NAMESPACE_BEGIN -using namespace VERILOG_FRONTEND; - -// use the Verilog bison/flex parser to generate an AST and use AST::process() to convert it to RTLIL - -static std::vector verilog_defaults; -static std::list> verilog_defaults_stack; - -static void error_on_dpi_function(AST::AstNode *node) -{ - if (node->type == AST::AST_DPI_FUNCTION) - log_file_error(node->filename, node->linenum, "Found DPI function %s.\n", node->str.c_str()); - for (auto child : node->children) - error_on_dpi_function(child); -} - -struct VerilogFrontend : public Frontend { - VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_verilog [options] [filename]\n"); - log("\n"); - log("Load modules from a Verilog file to the current design. A large subset of\n"); - log("Verilog-2005 is supported.\n"); - log("\n"); - log(" -sv\n"); - log(" enable support for SystemVerilog features. (only a small subset\n"); - log(" of SystemVerilog is supported)\n"); - log("\n"); - log(" -formal\n"); - log(" enable support for SystemVerilog assertions and some Yosys extensions\n"); - log(" replace the implicit -D SYNTHESIS with -D FORMAL\n"); - log("\n"); - log(" -noassert\n"); - log(" ignore assert() statements\n"); - log("\n"); - log(" -noassume\n"); - log(" ignore assume() statements\n"); - log("\n"); - log(" -norestrict\n"); - log(" ignore restrict() statements\n"); - log("\n"); - log(" -assume-asserts\n"); - log(" treat all assert() statements like assume() statements\n"); - log("\n"); - log(" -assert-assumes\n"); - log(" treat all assume() statements like assert() statements\n"); - log("\n"); - log(" -debug\n"); - log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n"); - log("\n"); - log(" -dump_ast1\n"); - log(" dump abstract syntax tree (before simplification)\n"); - log("\n"); - log(" -dump_ast2\n"); - log(" dump abstract syntax tree (after simplification)\n"); - log("\n"); - log(" -no_dump_ptr\n"); - log(" do not include hex memory addresses in dump (easier to diff dumps)\n"); - log("\n"); - log(" -dump_vlog1\n"); - log(" dump ast as Verilog code (before simplification)\n"); - log("\n"); - log(" -dump_vlog2\n"); - log(" dump ast as Verilog code (after simplification)\n"); - log("\n"); - log(" -dump_rtlil\n"); - log(" dump generated RTLIL netlist\n"); - log("\n"); - log(" -yydebug\n"); - log(" enable parser debug output\n"); - log("\n"); - log(" -nolatches\n"); - log(" usually latches are synthesized into logic loops\n"); - log(" this option prohibits this and sets the output to 'x'\n"); - log(" in what would be the latches hold condition\n"); - log("\n"); - log(" this behavior can also be achieved by setting the\n"); - log(" 'nolatches' attribute on the respective module or\n"); - log(" always block.\n"); - log("\n"); - log(" -nomem2reg\n"); - log(" under certain conditions memories are converted to registers\n"); - log(" early during simplification to ensure correct handling of\n"); - log(" complex corner cases. this option disables this behavior.\n"); - log("\n"); - log(" this can also be achieved by setting the 'nomem2reg'\n"); - log(" attribute on the respective module or register.\n"); - log("\n"); - log(" This is potentially dangerous. Usually the front-end has good\n"); - log(" reasons for converting an array to a list of registers.\n"); - log(" Prohibiting this step will likely result in incorrect synthesis\n"); - log(" results.\n"); - log("\n"); - log(" -mem2reg\n"); - log(" always convert memories to registers. this can also be\n"); - log(" achieved by setting the 'mem2reg' attribute on the respective\n"); - log(" module or register.\n"); - log("\n"); - log(" -nomeminit\n"); - log(" do not infer $meminit cells and instead convert initialized\n"); - log(" memories to registers directly in the front-end.\n"); - log("\n"); - log(" -ppdump\n"); - log(" dump Verilog code after pre-processor\n"); - log("\n"); - log(" -nopp\n"); - log(" do not run the pre-processor\n"); - log("\n"); - log(" -nodpi\n"); - log(" disable DPI-C support\n"); - log("\n"); - log(" -noblackbox\n"); - log(" do not automatically add a (* blackbox *) attribute to an\n"); - log(" empty module.\n"); - log("\n"); - log(" -lib\n"); - log(" only create empty blackbox modules. This implies -DBLACKBOX.\n"); - log(" modules with the (* whitebox *) attribute will be preserved.\n"); - log(" (* lib_whitebox *) will be treated like (* whitebox *).\n"); - log("\n"); - log(" -nowb\n"); - log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n"); - log(" all modules.\n"); - log("\n"); - log(" -specify\n"); - log(" parse and import specify blocks\n"); - log("\n"); - log(" -noopt\n"); - log(" don't perform basic optimizations (such as const folding) in the\n"); - log(" high-level front-end.\n"); - log("\n"); - log(" -icells\n"); - log(" interpret cell types starting with '$' as internal cell types\n"); - log("\n"); - log(" -pwires\n"); - log(" add a wire for each module parameter\n"); - log("\n"); - log(" -nooverwrite\n"); - log(" ignore re-definitions of modules. (the default behavior is to\n"); - log(" create an error message if the existing module is not a black box\n"); - log(" module, and overwrite the existing module otherwise.)\n"); - log("\n"); - log(" -overwrite\n"); - log(" overwrite existing modules with the same name\n"); - log("\n"); - log(" -defer\n"); - log(" only read the abstract syntax tree and defer actual compilation\n"); - log(" to a later 'hierarchy' command. Useful in cases where the default\n"); - log(" parameters of modules yield invalid or not synthesizable code.\n"); - log("\n"); - log(" -noautowire\n"); - log(" make the default of `default_nettype be \"none\" instead of \"wire\".\n"); - log("\n"); - log(" -setattr \n"); - log(" set the specified attribute (to the value 1) on all loaded modules\n"); - log("\n"); - log(" -Dname[=definition]\n"); - log(" define the preprocessor symbol 'name' and set its optional value\n"); - log(" 'definition'\n"); - log("\n"); - log(" -Idir\n"); - log(" add 'dir' to the directories which are used when searching include\n"); - log(" files\n"); - log("\n"); - log("The command 'verilog_defaults' can be used to register default options for\n"); - log("subsequent calls to 'read_verilog'.\n"); - log("\n"); - log("Note that the Verilog frontend does a pretty good job of processing valid\n"); - log("verilog input, but has not very good error reporting. It generally is\n"); - log("recommended to use a simulator (for example Icarus Verilog) for checking\n"); - log("the syntax of the code, rather than to rely on read_verilog for that.\n"); - log("\n"); - log("Depending on if read_verilog is run in -formal mode, either the macro\n"); - log("SYNTHESIS or FORMAL is defined automatically. In addition, read_verilog\n"); - log("always defines the macro YOSYS.\n"); - log("\n"); - log("See the Yosys README file for a list of non-standard Verilog features\n"); - log("supported by the Yosys Verilog front-end.\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - bool flag_dump_ast1 = false; - bool flag_dump_ast2 = false; - bool flag_no_dump_ptr = false; - bool flag_dump_vlog1 = false; - bool flag_dump_vlog2 = false; - bool flag_dump_rtlil = false; - bool flag_nolatches = false; - bool flag_nomeminit = false; - bool flag_nomem2reg = false; - bool flag_mem2reg = false; - bool flag_ppdump = false; - bool flag_nopp = false; - bool flag_nodpi = false; - bool flag_noopt = false; - bool flag_icells = false; - bool flag_pwires = false; - bool flag_nooverwrite = false; - bool flag_overwrite = false; - bool flag_defer = false; - bool flag_noblackbox = false; - bool flag_nowb = false; - std::map defines_map; - std::list include_dirs; - std::list attributes; - - frontend_verilog_yydebug = false; - sv_mode = false; - formal_mode = false; - norestrict_mode = false; - assume_asserts_mode = false; - lib_mode = false; - specify_mode = false; - default_nettype_wire = true; - - args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-sv") { - sv_mode = true; - continue; - } - if (arg == "-formal") { - formal_mode = true; - continue; - } - if (arg == "-noassert") { - noassert_mode = true; - continue; - } - if (arg == "-noassume") { - noassume_mode = true; - continue; - } - if (arg == "-norestrict") { - norestrict_mode = true; - continue; - } - if (arg == "-assume-asserts") { - assume_asserts_mode = true; - continue; - } - if (arg == "-assert-assumes") { - assert_assumes_mode = true; - continue; - } - if (arg == "-debug") { - flag_dump_ast1 = true; - flag_dump_ast2 = true; - flag_dump_vlog1 = true; - flag_dump_vlog2 = true; - frontend_verilog_yydebug = true; - continue; - } - if (arg == "-dump_ast1") { - flag_dump_ast1 = true; - continue; - } - if (arg == "-dump_ast2") { - flag_dump_ast2 = true; - continue; - } - if (arg == "-no_dump_ptr") { - flag_no_dump_ptr = true; - continue; - } - if (arg == "-dump_vlog1") { - flag_dump_vlog1 = true; - continue; - } - if (arg == "-dump_vlog2") { - flag_dump_vlog2 = true; - continue; - } - if (arg == "-dump_rtlil") { - flag_dump_rtlil = true; - continue; - } - if (arg == "-yydebug") { - frontend_verilog_yydebug = true; - continue; - } - if (arg == "-nolatches") { - flag_nolatches = true; - continue; - } - if (arg == "-nomeminit") { - flag_nomeminit = true; - continue; - } - if (arg == "-nomem2reg") { - flag_nomem2reg = true; - continue; - } - if (arg == "-mem2reg") { - flag_mem2reg = true; - continue; - } - if (arg == "-ppdump") { - flag_ppdump = true; - continue; - } - if (arg == "-nopp") { - flag_nopp = true; - continue; - } - if (arg == "-nodpi") { - flag_nodpi = true; - continue; - } - if (arg == "-noblackbox") { - flag_noblackbox = true; - continue; - } - if (arg == "-lib") { - lib_mode = true; - defines_map["BLACKBOX"] = string(); - continue; - } - if (arg == "-nowb") { - flag_nowb = true; - continue; - } - if (arg == "-specify") { - specify_mode = true; - continue; - } - if (arg == "-noopt") { - flag_noopt = true; - continue; - } - if (arg == "-icells") { - flag_icells = true; - continue; - } - if (arg == "-pwires") { - flag_pwires = true; - continue; - } - if (arg == "-ignore_redef" || arg == "-nooverwrite") { - flag_nooverwrite = true; - flag_overwrite = false; - continue; - } - if (arg == "-overwrite") { - flag_nooverwrite = false; - flag_overwrite = true; - continue; - } - if (arg == "-defer") { - flag_defer = true; - continue; - } - if (arg == "-noautowire") { - default_nettype_wire = false; - continue; - } - if (arg == "-setattr" && argidx+1 < args.size()) { - attributes.push_back(RTLIL::escape_id(args[++argidx])); - continue; - } - if (arg == "-D" && argidx+1 < args.size()) { - std::string name = args[++argidx], value; - size_t equal = name.find('='); - if (equal != std::string::npos) { - value = name.substr(equal+1); - name = name.substr(0, equal); - } - defines_map[name] = value; - continue; - } - if (arg.compare(0, 2, "-D") == 0) { - size_t equal = arg.find('=', 2); - std::string name = arg.substr(2, equal-2); - std::string value; - if (equal != std::string::npos) - value = arg.substr(equal+1); - defines_map[name] = value; - continue; - } - if (arg == "-I" && argidx+1 < args.size()) { - include_dirs.push_back(args[++argidx]); - continue; - } - if (arg.compare(0, 2, "-I") == 0) { - include_dirs.push_back(arg.substr(2)); - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str()); - - log("Parsing %s%s input from `%s' to AST representation.\n", - formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str()); - - AST::current_filename = filename; - AST::set_line_num = &frontend_verilog_yyset_lineno; - AST::get_line_num = &frontend_verilog_yyget_lineno; - - current_ast = new AST::AstNode(AST::AST_DESIGN); - - lexin = f; - std::string code_after_preproc; - - if (!flag_nopp) { - code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, design->verilog_defines, include_dirs); - if (flag_ppdump) - log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str()); - lexin = new std::istringstream(code_after_preproc); - } - - frontend_verilog_yyset_lineno(1); - frontend_verilog_yyrestart(NULL); - frontend_verilog_yyparse(); - frontend_verilog_yylex_destroy(); - - for (auto &child : current_ast->children) { - if (child->type == AST::AST_MODULE) - for (auto &attr : attributes) - if (child->attributes.count(attr) == 0) - child->attributes[attr] = AST::AstNode::mkconst_int(1, false); - } - - if (flag_nodpi) - error_on_dpi_function(current_ast); - - AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, - flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); - - if (!flag_nopp) - delete lexin; - - delete current_ast; - current_ast = NULL; - - log("Successfully finished Verilog frontend.\n"); - } -} VerilogFrontend; - -struct VerilogDefaults : public Pass { - VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" verilog_defaults -add [options]\n"); - log("\n"); - log("Add the specified options to the list of default options to read_verilog.\n"); - log("\n"); - log("\n"); - log(" verilog_defaults -clear\n"); - log("\n"); - log("Clear the list of Verilog default options.\n"); - log("\n"); - log("\n"); - log(" verilog_defaults -push\n"); - log(" verilog_defaults -pop\n"); - log("\n"); - log("Push or pop the list of default options to a stack. Note that -push does\n"); - log("not imply -clear.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design*) YS_OVERRIDE - { - if (args.size() < 2) - cmd_error(args, 1, "Missing argument."); - - if (args[1] == "-add") { - verilog_defaults.insert(verilog_defaults.end(), args.begin()+2, args.end()); - return; - } - - if (args.size() != 2) - cmd_error(args, 2, "Extra argument."); - - if (args[1] == "-clear") { - verilog_defaults.clear(); - return; - } - - if (args[1] == "-push") { - verilog_defaults_stack.push_back(verilog_defaults); - return; - } - - if (args[1] == "-pop") { - if (verilog_defaults_stack.empty()) { - verilog_defaults.clear(); - } else { - verilog_defaults.swap(verilog_defaults_stack.back()); - verilog_defaults_stack.pop_back(); - } - return; - } - } -} VerilogDefaults; - -struct VerilogDefines : public Pass { - VerilogDefines() : Pass("verilog_defines", "define and undefine verilog defines") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" verilog_defines [options]\n"); - log("\n"); - log("Define and undefine verilog preprocessor macros.\n"); - log("\n"); - log(" -Dname[=definition]\n"); - log(" define the preprocessor symbol 'name' and set its optional value\n"); - log(" 'definition'\n"); - log("\n"); - log(" -Uname[=definition]\n"); - log(" undefine the preprocessor symbol 'name'\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-D" && argidx+1 < args.size()) { - std::string name = args[++argidx], value; - size_t equal = name.find('='); - if (equal != std::string::npos) { - value = name.substr(equal+1); - name = name.substr(0, equal); - } - design->verilog_defines[name] = std::pair(value, false); - continue; - } - if (arg.compare(0, 2, "-D") == 0) { - size_t equal = arg.find('=', 2); - std::string name = arg.substr(2, equal-2); - std::string value; - if (equal != std::string::npos) - value = arg.substr(equal+1); - design->verilog_defines[name] = std::pair(value, false); - continue; - } - if (arg == "-U" && argidx+1 < args.size()) { - std::string name = args[++argidx]; - design->verilog_defines.erase(name); - continue; - } - if (arg.compare(0, 2, "-U") == 0) { - std::string name = arg.substr(2); - design->verilog_defines.erase(name); - continue; - } - break; - } - - if (args.size() != argidx) - cmd_error(args, argidx, "Extra argument."); - } -} VerilogDefines; - -YOSYS_NAMESPACE_END - -// the yyerror function used by bison to report parser errors -void frontend_verilog_yyerror(char const *fmt, ...) -{ - va_list ap; - char buffer[1024]; - char *p = buffer; - va_start(ap, fmt); - p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); - va_end(ap); - p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); - YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(), - "%s", buffer); - exit(1); -} diff --git a/yosys/frontends/verilog/verilog_frontend.h b/yosys/frontends/verilog/verilog_frontend.h deleted file mode 100644 index a7c9b2fe6..000000000 --- a/yosys/frontends/verilog/verilog_frontend.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * The Verilog frontend. - * - * This frontend is using the AST frontend library (see frontends/ast/). - * Thus this frontend does not generate RTLIL code directly but creates an - * AST directly from the Verilog parse tree and then passes this AST to - * the AST frontend library. - * - */ - -#ifndef VERILOG_FRONTEND_H -#define VERILOG_FRONTEND_H - -#include "kernel/yosys.h" -#include "frontends/ast/ast.h" -#include -#include -#include - -YOSYS_NAMESPACE_BEGIN - -namespace VERILOG_FRONTEND -{ - // this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser - extern struct AST::AstNode *current_ast; - - // this function converts a Verilog constant to an AST_CONSTANT node - AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false); - - // state of `default_nettype - extern bool default_nettype_wire; - - // running in SystemVerilog mode - extern bool sv_mode; - - // running in -formal mode - extern bool formal_mode; - - // running in -noassert mode - extern bool noassert_mode; - - // running in -noassume mode - extern bool noassume_mode; - - // running in -norestrict mode - extern bool norestrict_mode; - - // running in -assume-asserts mode - extern bool assume_asserts_mode; - - // running in -assert-assumes mode - extern bool assert_assumes_mode; - - // running in -lib mode - extern bool lib_mode; - - // running in -specify mode - extern bool specify_mode; - - // lexer input stream - extern std::istream *lexin; -} - -// the pre-processor -std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map &pre_defines_map, - dict> &global_defines_cache, const std::list &include_dirs); - -YOSYS_NAMESPACE_END - -// the usual bison/flex stuff -extern int frontend_verilog_yydebug; -int frontend_verilog_yylex(void); -void frontend_verilog_yyerror(char const *fmt, ...); -void frontend_verilog_yyrestart(FILE *f); -int frontend_verilog_yyparse(void); -int frontend_verilog_yylex_destroy(void); -int frontend_verilog_yyget_lineno(void); -void frontend_verilog_yyset_lineno (int); - -#endif diff --git a/yosys/frontends/verilog/verilog_lexer.l b/yosys/frontends/verilog/verilog_lexer.l deleted file mode 100644 index 951d9c66f..000000000 --- a/yosys/frontends/verilog/verilog_lexer.l +++ /dev/null @@ -1,459 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * The Verilog frontend. - * - * This frontend is using the AST frontend library (see frontends/ast/). - * Thus this frontend does not generate RTLIL code directly but creates an - * AST directly from the Verilog parse tree and then passes this AST to - * the AST frontend library. - * - * --- - * - * A simple lexer for Verilog code. Non-preprocessor compiler directives are - * handled here. The preprocessor stuff is handled in preproc.cc. Everything - * else is left to the bison parser (see parser.y). - * - */ - -%{ - -#ifdef __clang__ -// bison generates code using the 'register' storage class specifier -#pragma clang diagnostic ignored "-Wdeprecated-register" -#endif - -#include "kernel/log.h" -#include "frontends/verilog/verilog_frontend.h" -#include "frontends/ast/ast.h" -#include "verilog_parser.tab.hh" - -USING_YOSYS_NAMESPACE -using namespace AST; -using namespace VERILOG_FRONTEND; - -YOSYS_NAMESPACE_BEGIN -namespace VERILOG_FRONTEND { - std::vector fn_stack; - std::vector ln_stack; -} -YOSYS_NAMESPACE_END - -#define SV_KEYWORD(_tok) \ - if (sv_mode) return _tok; \ - log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\ - "recognized unless read_verilog is called with -sv!\n", yytext, \ - AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \ - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \ - return TOK_ID; - -#define NON_KEYWORD() \ - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \ - return TOK_ID; - -#define YY_INPUT(buf,result,max_size) \ - result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) - -%} - -%option yylineno -%option noyywrap -%option nounput -%option prefix="frontend_verilog_yy" - -%x COMMENT -%x STRING -%x SYNOPSYS_TRANSLATE_OFF -%x SYNOPSYS_FLAGS -%x IMPORT_DPI - -%% - -"`file_push "[^\n]* { - fn_stack.push_back(current_filename); - ln_stack.push_back(frontend_verilog_yyget_lineno()); - current_filename = yytext+11; - if (!current_filename.empty() && current_filename.front() == '"') - current_filename = current_filename.substr(1); - if (!current_filename.empty() && current_filename.back() == '"') - current_filename = current_filename.substr(0, current_filename.size()-1); - frontend_verilog_yyset_lineno(0); -} - -"`file_pop"[^\n]*\n { - current_filename = fn_stack.back(); - fn_stack.pop_back(); - frontend_verilog_yyset_lineno(ln_stack.back()); - ln_stack.pop_back(); -} - -"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n { - char *p = yytext + 5; - while (*p == ' ' || *p == '\t') p++; - frontend_verilog_yyset_lineno(atoi(p)); - while (*p && *p != ' ' && *p != '\t') p++; - while (*p == ' ' || *p == '\t') p++; - char *q = *p ? p + 1 : p; - while (*q && *q != '"') q++; - current_filename = std::string(p).substr(1, q-p-1); -} - -"`file_notfound "[^\n]* { - log_error("Can't open include file `%s'!\n", yytext + 15); -} - -"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */ - -"`celldefine"[^\n]* /* ignore `celldefine */ -"`endcelldefine"[^\n]* /* ignore `endcelldefine */ - -"`default_nettype"[ \t]+[^ \t\r\n/]+ { - char *p = yytext; - while (*p != 0 && *p != ' ' && *p != '\t') p++; - while (*p == ' ' || *p == '\t') p++; - if (!strcmp(p, "none")) - VERILOG_FRONTEND::default_nettype_wire = false; - else if (!strcmp(p, "wire")) - VERILOG_FRONTEND::default_nettype_wire = true; - else - frontend_verilog_yyerror("Unsupported default nettype: %s", p); -} - -"`protect"[^\n]* /* ignore `protect*/ -"`endprotect"[^\n]* /* ignore `endprotect*/ - -"`"[a-zA-Z_$][a-zA-Z0-9_$]* { - frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext); -} - -"module" { return TOK_MODULE; } -"endmodule" { return TOK_ENDMODULE; } -"function" { return TOK_FUNCTION; } -"endfunction" { return TOK_ENDFUNCTION; } -"task" { return TOK_TASK; } -"endtask" { return TOK_ENDTASK; } -"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; } -"endspecify" { return TOK_ENDSPECIFY; } -"specparam" { return TOK_SPECPARAM; } -"package" { SV_KEYWORD(TOK_PACKAGE); } -"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } -"interface" { SV_KEYWORD(TOK_INTERFACE); } -"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); } -"modport" { SV_KEYWORD(TOK_MODPORT); } -"parameter" { return TOK_PARAMETER; } -"localparam" { return TOK_LOCALPARAM; } -"defparam" { return TOK_DEFPARAM; } -"assign" { return TOK_ASSIGN; } -"always" { return TOK_ALWAYS; } -"initial" { return TOK_INITIAL; } -"begin" { return TOK_BEGIN; } -"end" { return TOK_END; } -"if" { return TOK_IF; } -"else" { return TOK_ELSE; } -"for" { return TOK_FOR; } -"posedge" { return TOK_POSEDGE; } -"negedge" { return TOK_NEGEDGE; } -"or" { return TOK_OR; } -"case" { return TOK_CASE; } -"casex" { return TOK_CASEX; } -"casez" { return TOK_CASEZ; } -"endcase" { return TOK_ENDCASE; } -"default" { return TOK_DEFAULT; } -"generate" { return TOK_GENERATE; } -"endgenerate" { return TOK_ENDGENERATE; } -"while" { return TOK_WHILE; } -"repeat" { return TOK_REPEAT; } -"automatic" { return TOK_AUTOMATIC; } - -"unique" { SV_KEYWORD(TOK_UNIQUE); } -"unique0" { SV_KEYWORD(TOK_UNIQUE); } -"priority" { SV_KEYWORD(TOK_PRIORITY); } - -"always_comb" { SV_KEYWORD(TOK_ALWAYS); } -"always_ff" { SV_KEYWORD(TOK_ALWAYS); } -"always_latch" { SV_KEYWORD(TOK_ALWAYS); } - - /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex - to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some - global state.. its a mess) */ -[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] { - if (!strcmp(yytext, "default")) - return TOK_DEFAULT; - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); - return TOK_SVA_LABEL; -} - -"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } -"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } -"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } -"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } -"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } -"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); } -"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } -"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } -"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } -"final" { SV_KEYWORD(TOK_FINAL); } -"logic" { SV_KEYWORD(TOK_LOGIC); } -"var" { SV_KEYWORD(TOK_VAR); } -"bit" { SV_KEYWORD(TOK_REG); } - -"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } -"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } - -"input" { return TOK_INPUT; } -"output" { return TOK_OUTPUT; } -"inout" { return TOK_INOUT; } -"wire" { return TOK_WIRE; } -"wor" { return TOK_WOR; } -"wand" { return TOK_WAND; } -"reg" { return TOK_REG; } -"integer" { return TOK_INTEGER; } -"signed" { return TOK_SIGNED; } -"genvar" { return TOK_GENVAR; } -"real" { return TOK_REAL; } - -"enum" { SV_KEYWORD(TOK_ENUM); } -"typedef" { SV_KEYWORD(TOK_TYPEDEF); } - -[0-9][0-9_]* { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_CONSTVAL; -} - -[0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_CONSTVAL; -} - -[0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_REALVAL; -} - -[0-9][0-9_]*[eE][-+]?[0-9_]+ { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_REALVAL; -} - -\" { BEGIN(STRING); } -\\. { yymore(); } -\" { - BEGIN(0); - char *yystr = strdup(yytext); - yystr[strlen(yytext) - 1] = 0; - int i = 0, j = 0; - while (yystr[i]) { - if (yystr[i] == '\\' && yystr[i + 1]) { - i++; - if (yystr[i] == 'a') - yystr[i] = '\a'; - else if (yystr[i] == 'f') - yystr[i] = '\f'; - else if (yystr[i] == 'n') - yystr[i] = '\n'; - else if (yystr[i] == 'r') - yystr[i] = '\r'; - else if (yystr[i] == 't') - yystr[i] = '\t'; - else if (yystr[i] == 'v') - yystr[i] = '\v'; - else if ('0' <= yystr[i] && yystr[i] <= '7') { - yystr[i] = yystr[i] - '0'; - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - } - } - yystr[j++] = yystr[i++]; - } - yystr[j] = 0; - frontend_verilog_yylval.string = new std::string(yystr, j); - free(yystr); - return TOK_STRING; -} -. { yymore(); } - -and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_PRIMITIVE; -} - -supply0 { return TOK_SUPPLY0; } -supply1 { return TOK_SUPPLY1; } - -"$"(display|write|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_ID; -} - -"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { - if (!specify_mode) REJECT; - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_ID; -} - -"$"(info|warning|error|fatal) { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_MSG_TASKS; -} - -"$signed" { return TOK_TO_SIGNED; } -"$unsigned" { return TOK_TO_UNSIGNED; } - -[a-zA-Z_$][a-zA-Z0-9_$]* { - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); - return TOK_ID; -} - -[a-zA-Z_$][a-zA-Z0-9_$\.]* { - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); - return TOK_ID; -} - -"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { - static bool printed_warning = false; - if (!printed_warning) { - log_warning("Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n" - "Yosys does support them but it is recommended to use `ifdef constructs instead!\n"); - printed_warning = true; - } - BEGIN(SYNOPSYS_TRANSLATE_OFF); -} -. /* ignore synopsys translate_off body */ -\n /* ignore synopsys translate_off body */ -"/*"[ \t]*(synopsys|synthesis)[ \t]*"translate_on"[ \t]*"*/" { BEGIN(0); } - -"/*"[ \t]*(synopsys|synthesis)[ \t]+ { - BEGIN(SYNOPSYS_FLAGS); -} -full_case { - static bool printed_warning = false; - if (!printed_warning) { - log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n" - "Yosys does support them but it is recommended to use Verilog `full_case' attributes instead!\n"); - printed_warning = true; - } - return TOK_SYNOPSYS_FULL_CASE; -} -parallel_case { - static bool printed_warning = false; - if (!printed_warning) { - log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n" - "Yosys does support them but it is recommended to use Verilog `parallel_case' attributes instead!\n"); - printed_warning = true; - } - return TOK_SYNOPSYS_PARALLEL_CASE; -} -. /* ignore everything else */ -"*/" { BEGIN(0); } - -import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { - BEGIN(IMPORT_DPI); - return TOK_DPI_FUNCTION; -} - -[a-zA-Z_$][a-zA-Z0-9_$]* { - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); - return TOK_ID; -} - -[ \t\r\n] /* ignore whitespaces */ - -";" { - BEGIN(0); - return *yytext; -} - -. { - return *yytext; -} - -"\\"[^ \t\r\n]+ { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_ID; -} - -"(*" { return ATTR_BEGIN; } -"*)" { return ATTR_END; } - -"{*" { return DEFATTR_BEGIN; } -"*}" { return DEFATTR_END; } - -"**" { return OP_POW; } -"||" { return OP_LOR; } -"&&" { return OP_LAND; } -"==" { return OP_EQ; } -"!=" { return OP_NE; } -"<=" { return OP_LE; } -">=" { return OP_GE; } - -"===" { return OP_EQX; } -"!==" { return OP_NEX; } - -"~&" { return OP_NAND; } -"~|" { return OP_NOR; } -"~^" { return OP_XNOR; } -"^~" { return OP_XNOR; } - -"<<" { return OP_SHL; } -">>" { return OP_SHR; } -"<<<" { return OP_SSHL; } -">>>" { return OP_SSHR; } - -"::" { return TOK_PACKAGESEP; } -"++" { return TOK_INCREMENT; } -"--" { return TOK_DECREMENT; } - -"+:" { return TOK_POS_INDEXED; } -"-:" { return TOK_NEG_INDEXED; } - -[-+]?[=*]> { - if (!specify_mode) REJECT; - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_SPECIFY_OPER; -} - -"&&&" { - if (!specify_mode) REJECT; - return TOK_SPECIFY_AND; -} - -"/*" { BEGIN(COMMENT); } -. /* ignore comment body */ -\n /* ignore comment body */ -"*/" { BEGIN(0); } - -[ \t\r\n] /* ignore whitespaces */ -\\[\r\n] /* ignore continuation sequence */ -"//"[^\r\n]* /* ignore one-line comments */ - -. { return *yytext; } - -%% - -// this is a hack to avoid the 'yyinput defined but not used' error msgs -void *frontend_verilog_avoid_input_warnings() { - return (void*)&yyinput; -} - diff --git a/yosys/frontends/verilog/verilog_parser.y b/yosys/frontends/verilog/verilog_parser.y deleted file mode 100644 index 0fec445fa..000000000 --- a/yosys/frontends/verilog/verilog_parser.y +++ /dev/null @@ -1,2422 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * The Verilog frontend. - * - * This frontend is using the AST frontend library (see frontends/ast/). - * Thus this frontend does not generate RTLIL code directly but creates an - * AST directly from the Verilog parse tree and then passes this AST to - * the AST frontend library. - * - * --- - * - * This is the actual bison parser for Verilog code. The AST ist created directly - * from the bison reduce functions here. Note that this code uses a few global - * variables to hold the state of the AST generator and therefore this parser is - * not reentrant. - * - */ - -%{ -#include -#include -#include -#include "frontends/verilog/verilog_frontend.h" -#include "kernel/log.h" - -USING_YOSYS_NAMESPACE -using namespace AST; -using namespace VERILOG_FRONTEND; - -YOSYS_NAMESPACE_BEGIN -namespace VERILOG_FRONTEND { - int port_counter; - std::map port_stubs; - std::map *attr_list, default_attr_list; - std::stack *> attr_list_stack; - std::map *albuf; - std::vector ast_stack; - struct AstNode *astbuf1, *astbuf2, *astbuf3; - struct AstNode *current_function_or_task; - struct AstNode *current_ast, *current_ast_mod; - int current_function_or_task_port_id; - std::vector case_type_stack; - bool do_not_require_port_stubs; - bool default_nettype_wire; - bool sv_mode, formal_mode, lib_mode, specify_mode; - bool noassert_mode, noassume_mode, norestrict_mode; - bool assume_asserts_mode, assert_assumes_mode; - bool current_wire_rand, current_wire_const; - bool current_modport_input, current_modport_output; - std::istream *lexin; -} -YOSYS_NAMESPACE_END - -static void append_attr(AstNode *ast, std::map *al) -{ - for (auto &it : *al) { - if (ast->attributes.count(it.first) > 0) - delete ast->attributes[it.first]; - ast->attributes[it.first] = it.second; - } - delete al; -} - -static void append_attr_clone(AstNode *ast, std::map *al) -{ - for (auto &it : *al) { - if (ast->attributes.count(it.first) > 0) - delete ast->attributes[it.first]; - ast->attributes[it.first] = it.second->clone(); - } -} - -static void free_attr(std::map *al) -{ - for (auto &it : *al) - delete it.second; - delete al; -} - -struct specify_target { - char polarity_op; - AstNode *dst, *dat; -}; - -struct specify_triple { - AstNode *t_min, *t_avg, *t_max; -}; - -struct specify_rise_fall { - specify_triple rise; - specify_triple fall; -}; - -%} - -%define api.prefix {frontend_verilog_yy} - -/* The union is defined in the header, so we need to provide all the - * includes it requires - */ -%code requires { -#include -#include -#include "frontends/verilog/verilog_frontend.h" -} - -%union { - std::string *string; - struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; - std::map *al; - struct specify_target *specify_target_ptr; - struct specify_triple *specify_triple_ptr; - struct specify_rise_fall *specify_rise_fall_ptr; - bool boolean; - char ch; -} - -%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE -%token TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS -%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL -%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END -%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM -%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP -%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR -%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC -%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL -%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT -%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC -%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT -%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY -%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND -%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL -%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE -%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED -%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF -%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY -%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY - -%type range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int -%type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list -%type opt_label opt_sva_label tok_prim_wrapper hierarchical_id -%type opt_signed opt_property unique_case_attr -%type attr case_attr - -%type specify_target -%type specify_triple -%type specify_rise_fall -%type specify_if specify_condition specify_opt_arg -%type specify_edge - -// operator precedence from low to high -%left OP_LOR -%left OP_LAND -%left '|' OP_NOR -%left '^' OP_XNOR -%left '&' OP_NAND -%left OP_EQ OP_NE OP_EQX OP_NEX -%left '<' OP_LE OP_GE '>' -%left OP_SHL OP_SHR OP_SSHL OP_SSHR -%left '+' '-' -%left '*' '/' '%' -%left OP_POW -%right UNARY_OPS - -%define parse.error verbose -%define parse.lac full - -%nonassoc FAKE_THEN -%nonassoc TOK_ELSE - -%debug - -%% - -input: { - ast_stack.clear(); - ast_stack.push_back(current_ast); -} design { - ast_stack.pop_back(); - log_assert(GetSize(ast_stack) == 0); - for (auto &it : default_attr_list) - delete it.second; - default_attr_list.clear(); -}; - -design: - module design | - defattr design | - task_func_decl design | - param_decl design | - localparam_decl design | - package design | - interface design | - /* empty */; - -attr: - { - if (attr_list != nullptr) - attr_list_stack.push(attr_list); - attr_list = new std::map; - for (auto &it : default_attr_list) - (*attr_list)[it.first] = it.second->clone(); - } attr_opt { - $$ = attr_list; - if (!attr_list_stack.empty()) { - attr_list = attr_list_stack.top(); - attr_list_stack.pop(); - } else - attr_list = nullptr; - }; - -attr_opt: - attr_opt ATTR_BEGIN opt_attr_list ATTR_END | - /* empty */; - -defattr: - DEFATTR_BEGIN { - if (attr_list != nullptr) - attr_list_stack.push(attr_list); - attr_list = new std::map; - for (auto &it : default_attr_list) - delete it.second; - default_attr_list.clear(); - } opt_attr_list { - attr_list->swap(default_attr_list); - delete attr_list; - if (!attr_list_stack.empty()) { - attr_list = attr_list_stack.top(); - attr_list_stack.pop(); - } else - attr_list = nullptr; - } DEFATTR_END; - -opt_attr_list: - attr_list | /* empty */; - -attr_list: - attr_assign | - attr_list ',' attr_assign; - -attr_assign: - hierarchical_id { - if (attr_list->count(*$1) != 0) - delete (*attr_list)[*$1]; - (*attr_list)[*$1] = AstNode::mkconst_int(1, false); - delete $1; - } | - hierarchical_id '=' expr { - if (attr_list->count(*$1) != 0) - delete (*attr_list)[*$1]; - (*attr_list)[*$1] = $3; - delete $1; - }; - -hierarchical_id: - TOK_ID { - $$ = $1; - } | - hierarchical_id TOK_PACKAGESEP TOK_ID { - if ($3->substr(0, 1) == "\\") - *$1 += "::" + $3->substr(1); - else - *$1 += "::" + *$3; - delete $3; - $$ = $1; - } | - hierarchical_id '.' TOK_ID { - if ($3->substr(0, 1) == "\\") - *$1 += "." + $3->substr(1); - else - *$1 += "." + *$3; - delete $3; - $$ = $1; - }; - -module: - attr TOK_MODULE TOK_ID { - do_not_require_port_stubs = false; - AstNode *mod = new AstNode(AST_MODULE); - ast_stack.back()->children.push_back(mod); - ast_stack.push_back(mod); - current_ast_mod = mod; - port_stubs.clear(); - port_counter = 0; - mod->str = *$3; - append_attr(mod, $1); - delete $3; - } module_para_opt module_args_opt ';' module_body TOK_ENDMODULE { - if (port_stubs.size() != 0) - frontend_verilog_yyerror("Missing details for module port `%s'.", - port_stubs.begin()->first.c_str()); - ast_stack.pop_back(); - log_assert(ast_stack.size() == 1); - current_ast_mod = NULL; - }; - -module_para_opt: - '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */; - -module_para_list: - single_module_para | module_para_list ',' single_module_para; - -single_module_para: - /* empty */ | - attr TOK_PARAMETER { - if (astbuf1) delete astbuf1; - astbuf1 = new AstNode(AST_PARAMETER); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); - } param_signed param_integer param_range single_param_decl | - attr TOK_LOCALPARAM { - if (astbuf1) delete astbuf1; - astbuf1 = new AstNode(AST_LOCALPARAM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); - } param_signed param_integer param_range single_param_decl | - single_param_decl; - -module_args_opt: - '(' ')' | /* empty */ | '(' module_args optional_comma ')'; - -module_args: - module_arg | module_args ',' module_arg; - -optional_comma: - ',' | /* empty */; - -module_arg_opt_assignment: - '=' expr { - if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { - AstNode *wire = new AstNode(AST_IDENTIFIER); - wire->str = ast_stack.back()->children.back()->str; - if (ast_stack.back()->children.back()->is_input) { - AstNode *n = ast_stack.back()->children.back(); - if (n->attributes.count("\\defaultvalue")) - delete n->attributes.at("\\defaultvalue"); - n->attributes["\\defaultvalue"] = $2; - } else - if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic) - ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2)))); - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2)); - } else - frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value."); - } | - /* empty */; - -module_arg: - TOK_ID { - if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { - AstNode *node = ast_stack.back()->children.back()->clone(); - node->str = *$1; - node->port_id = ++port_counter; - ast_stack.back()->children.push_back(node); - } else { - if (port_stubs.count(*$1) != 0) - frontend_verilog_yyerror("Duplicate module port `%s'.", $1->c_str()); - port_stubs[*$1] = ++port_counter; - } - delete $1; - } module_arg_opt_assignment | - TOK_ID { - astbuf1 = new AstNode(AST_INTERFACEPORT); - astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE)); - astbuf1->children[0]->str = *$1; - delete $1; - } TOK_ID { /* SV interfaces */ - if (!sv_mode) - frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); - astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type. - astbuf2->str = *$3; - delete $3; - astbuf2->port_id = ++port_counter; - ast_stack.back()->children.push_back(astbuf2); - delete astbuf1; // really only needed if multiple instances of same type. - } module_arg_opt_assignment | - attr wire_type range TOK_ID { - AstNode *node = $2; - node->str = *$4; - node->port_id = ++port_counter; - if ($3 != NULL) - node->children.push_back($3); - if (!node->is_input && !node->is_output) - frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str()); - if (node->is_reg && node->is_input && !node->is_output && !sv_mode) - frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str()); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); - delete $4; - } module_arg_opt_assignment | - '.' '.' '.' { - do_not_require_port_stubs = true; - }; - -package: - attr TOK_PACKAGE TOK_ID { - AstNode *mod = new AstNode(AST_PACKAGE); - ast_stack.back()->children.push_back(mod); - ast_stack.push_back(mod); - current_ast_mod = mod; - mod->str = *$3; - append_attr(mod, $1); - } ';' package_body TOK_ENDPACKAGE { - ast_stack.pop_back(); - current_ast_mod = NULL; - }; - -package_body: - package_body package_body_stmt |; - -package_body_stmt: - localparam_decl; - -interface: - TOK_INTERFACE TOK_ID { - do_not_require_port_stubs = false; - AstNode *intf = new AstNode(AST_INTERFACE); - ast_stack.back()->children.push_back(intf); - ast_stack.push_back(intf); - current_ast_mod = intf; - port_stubs.clear(); - port_counter = 0; - intf->str = *$2; - delete $2; - } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE { - if (port_stubs.size() != 0) - frontend_verilog_yyerror("Missing details for module port `%s'.", - port_stubs.begin()->first.c_str()); - ast_stack.pop_back(); - log_assert(ast_stack.size() == 1); - current_ast_mod = NULL; - }; - -interface_body: - interface_body interface_body_stmt |; - -interface_body_stmt: - param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt | - modport_stmt; - -non_opt_delay: - '#' TOK_ID { delete $2; } | - '#' TOK_CONSTVAL { delete $2; } | - '#' TOK_REALVAL { delete $2; } | - '#' '(' expr ')' { delete $3; } | - '#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; }; - -delay: - non_opt_delay | /* empty */; - -wire_type: - { - astbuf3 = new AstNode(AST_WIRE); - current_wire_rand = false; - current_wire_const = false; - } wire_type_token_list delay { - $$ = astbuf3; - }; - -wire_type_token_list: - wire_type_token | wire_type_token_list wire_type_token | - wire_type_token_io ; - -wire_type_token_io: - TOK_INPUT { - astbuf3->is_input = true; - } | - TOK_OUTPUT { - astbuf3->is_output = true; - } | - TOK_INOUT { - astbuf3->is_input = true; - astbuf3->is_output = true; - }; - -wire_type_token: - TOK_WIRE { - } | - TOK_WOR { - astbuf3->is_wor = true; - } | - TOK_WAND { - astbuf3->is_wand = true; - } | - TOK_REG { - astbuf3->is_reg = true; - } | - TOK_LOGIC { - astbuf3->is_logic = true; - } | - TOK_VAR { - astbuf3->is_logic = true; - } | - TOK_INTEGER { - astbuf3->is_reg = true; - astbuf3->range_left = 31; - astbuf3->range_right = 0; - astbuf3->is_signed = true; - } | - TOK_GENVAR { - astbuf3->type = AST_GENVAR; - astbuf3->is_reg = true; - astbuf3->is_signed = true; - astbuf3->range_left = 31; - astbuf3->range_right = 0; - } | - TOK_SIGNED { - astbuf3->is_signed = true; - } | - TOK_RAND { - current_wire_rand = true; - } | - TOK_CONST { - current_wire_const = true; - }; - -non_opt_range: - '[' expr ':' expr ']' { - $$ = new AstNode(AST_RANGE); - $$->children.push_back($2); - $$->children.push_back($4); - } | - '[' expr TOK_POS_INDEXED expr ']' { - $$ = new AstNode(AST_RANGE); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, $2->clone(), $4), AstNode::mkconst_int(1, true))); - $$->children.push_back(new AstNode(AST_ADD, $2, AstNode::mkconst_int(0, true))); - } | - '[' expr TOK_NEG_INDEXED expr ']' { - $$ = new AstNode(AST_RANGE); - $$->children.push_back(new AstNode(AST_ADD, $2, AstNode::mkconst_int(0, true))); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true)), $4)); - } | - '[' expr ']' { - $$ = new AstNode(AST_RANGE); - $$->children.push_back($2); - }; - -non_opt_multirange: - non_opt_range non_opt_range { - $$ = new AstNode(AST_MULTIRANGE, $1, $2); - } | - non_opt_multirange non_opt_range { - $$ = $1; - $$->children.push_back($2); - }; - -range: - non_opt_range { - $$ = $1; - } | - /* empty */ { - $$ = NULL; - }; - -range_or_multirange: - range { $$ = $1; } | - non_opt_multirange { $$ = $1; }; - -range_or_signed_int: - range { - $$ = $1; - } | - TOK_INTEGER { - $$ = new AstNode(AST_RANGE); - $$->children.push_back(AstNode::mkconst_int(31, true)); - $$->children.push_back(AstNode::mkconst_int(0, true)); - $$->is_signed = true; - }; - -module_body: - module_body module_body_stmt | - /* the following line makes the generate..endgenrate keywords optional */ - module_body gen_stmt | - /* empty */; - -module_body_stmt: - task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | - always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; - -checker_decl: - TOK_CHECKER TOK_ID ';' { - AstNode *node = new AstNode(AST_GENBLOCK); - node->str = *$2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } module_body TOK_ENDCHECKER { - delete $2; - ast_stack.pop_back(); - }; - -task_func_decl: - attr TOK_DPI_FUNCTION TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4)); - current_function_or_task->str = *$4; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $4; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; - } | - attr TOK_DPI_FUNCTION TOK_ID '=' TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3)); - current_function_or_task->str = *$6; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $5; - delete $6; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; - } | - attr TOK_DPI_FUNCTION TOK_ID ':' TOK_ID '=' TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5))); - current_function_or_task->str = *$8; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $5; - delete $7; - delete $8; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; - } | - attr TOK_TASK opt_automatic TOK_ID { - current_function_or_task = new AstNode(AST_TASK); - current_function_or_task->str = *$4; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - ast_stack.push_back(current_function_or_task); - current_function_or_task_port_id = 1; - delete $4; - } task_func_args_opt ';' task_func_body TOK_ENDTASK { - current_function_or_task = NULL; - ast_stack.pop_back(); - } | - attr TOK_FUNCTION opt_automatic opt_signed range_or_signed_int TOK_ID { - current_function_or_task = new AstNode(AST_FUNCTION); - current_function_or_task->str = *$6; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - ast_stack.push_back(current_function_or_task); - AstNode *outreg = new AstNode(AST_WIRE); - outreg->str = *$6; - outreg->is_signed = $4; - outreg->is_reg = true; - if ($5 != NULL) { - outreg->children.push_back($5); - outreg->is_signed = $4 || $5->is_signed; - $5->is_signed = false; - } - current_function_or_task->children.push_back(outreg); - current_function_or_task_port_id = 1; - delete $6; - } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION { - current_function_or_task = NULL; - ast_stack.pop_back(); - }; - -dpi_function_arg: - TOK_ID TOK_ID { - current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); - delete $1; - delete $2; - } | - TOK_ID { - current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); - delete $1; - }; - -opt_dpi_function_args: - '(' dpi_function_args ')' | - /* empty */; - -dpi_function_args: - dpi_function_args ',' dpi_function_arg | - dpi_function_args ',' | - dpi_function_arg | - /* empty */; - -opt_automatic: - TOK_AUTOMATIC | - /* empty */; - -opt_signed: - TOK_SIGNED { - $$ = true; - } | - /* empty */ { - $$ = false; - }; - -task_func_args_opt: - '(' ')' | /* empty */ | '(' { - albuf = nullptr; - astbuf1 = nullptr; - astbuf2 = nullptr; - } task_func_args optional_comma { - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); - } ')'; - -task_func_args: - task_func_port | task_func_args ',' task_func_port; - -task_func_port: - attr wire_type range { - if (albuf) { - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); - } - albuf = $1; - astbuf1 = $2; - astbuf2 = $3; - if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { - if (astbuf2) { - frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions (task/function arguments)"); - } else { - astbuf2 = new AstNode(AST_RANGE); - astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true)); - astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true)); - } - } - if (astbuf2 && astbuf2->children.size() != 2) - frontend_verilog_yyerror("task/function argument range must be of the form: [:], [+:], or [-:]"); - } wire_name | wire_name; - -task_func_body: - task_func_body behavioral_stmt | - /* empty */; - -/*************************** specify parser ***************************/ - -specify_block: - TOK_SPECIFY specify_item_list TOK_ENDSPECIFY; - -specify_item_list: - specify_item specify_item_list | - /* empty */; - -specify_item: - specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' { - AstNode *en_expr = $1; - char specify_edge = $3; - AstNode *src_expr = $4; - string *oper = $5; - specify_target *target = $6; - specify_rise_fall *timing = $9; - - if (specify_edge != 0 && target->dat == nullptr) - frontend_verilog_yyerror("Found specify edge but no data spec.\n"); - - AstNode *cell = new AstNode(AST_CELL); - ast_stack.back()->children.push_back(cell); - cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(new AstNode(AST_CELLTYPE)); - cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; - - char oper_polarity = 0; - char oper_type = oper->at(0); - - if (oper->size() == 3) { - oper_polarity = oper->at(0); - oper_type = oper->at(1); - } - - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); - cell->children.back()->str = "\\FULL"; - - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); - cell->children.back()->str = "\\SRC_DST_PEN"; - - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); - cell->children.back()->str = "\\SRC_DST_POL"; - - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min)); - cell->children.back()->str = "\\T_RISE_MIN"; - - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg)); - cell->children.back()->str = "\\T_RISE_TYP"; - - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max)); - cell->children.back()->str = "\\T_RISE_MAX"; - - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min)); - cell->children.back()->str = "\\T_FALL_MIN"; - - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg)); - cell->children.back()->str = "\\T_FALL_TYP"; - - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max)); - cell->children.back()->str = "\\T_FALL_MAX"; - - cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1))); - cell->children.back()->str = "\\EN"; - - cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); - cell->children.back()->str = "\\SRC"; - - cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst)); - cell->children.back()->str = "\\DST"; - - if (target->dat) - { - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); - cell->children.back()->str = "\\EDGE_EN"; - - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); - cell->children.back()->str = "\\EDGE_POL"; - - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); - cell->children.back()->str = "\\DAT_DST_PEN"; - - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); - cell->children.back()->str = "\\DAT_DST_POL"; - - cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat)); - cell->children.back()->str = "\\DAT"; - } - - delete oper; - delete target; - delete timing; - } | - TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' { - if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && - *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") - frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str()); - - AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1); - AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1); - AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1); - - AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1); - AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); - AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1); - - AstNode *limit = $11; - AstNode *limit2 = $12; - - AstNode *cell = new AstNode(AST_CELL); - ast_stack.back()->children.push_back(cell); - cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(new AstNode(AST_CELLTYPE)); - cell->children.back()->str = "$specrule"; - - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1))); - cell->children.back()->str = "\\TYPE"; - - cell->children.push_back(new AstNode(AST_PARASET, limit)); - cell->children.back()->str = "\\T_LIMIT"; - - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true))); - cell->children.back()->str = "\\T_LIMIT2"; - - cell->children.push_back(new AstNode(AST_PARASET, src_pen)); - cell->children.back()->str = "\\SRC_PEN"; - - cell->children.push_back(new AstNode(AST_PARASET, src_pol)); - cell->children.back()->str = "\\SRC_POL"; - - cell->children.push_back(new AstNode(AST_PARASET, dst_pen)); - cell->children.back()->str = "\\DST_PEN"; - - cell->children.push_back(new AstNode(AST_PARASET, dst_pol)); - cell->children.back()->str = "\\DST_POL"; - - cell->children.push_back(new AstNode(AST_ARGUMENT, src_en)); - cell->children.back()->str = "\\SRC_EN"; - - cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); - cell->children.back()->str = "\\SRC"; - - cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en)); - cell->children.back()->str = "\\DST_EN"; - - cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr)); - cell->children.back()->str = "\\DST"; - - delete $1; - }; - -specify_opt_arg: - ',' expr { - $$ = $2; - } | - /* empty */ { - $$ = nullptr; - }; - -specify_if: - TOK_IF '(' expr ')' { - $$ = $3; - } | - /* empty */ { - $$ = nullptr; - }; - -specify_condition: - TOK_SPECIFY_AND expr { - $$ = $2; - } | - /* empty */ { - $$ = nullptr; - }; - -specify_target: - expr { - $$ = new specify_target; - $$->polarity_op = 0; - $$->dst = $1; - $$->dat = nullptr; - } | - '(' expr ':' expr ')'{ - $$ = new specify_target; - $$->polarity_op = 0; - $$->dst = $2; - $$->dat = $4; - } | - '(' expr TOK_NEG_INDEXED expr ')'{ - $$ = new specify_target; - $$->polarity_op = '-'; - $$->dst = $2; - $$->dat = $4; - } | - '(' expr TOK_POS_INDEXED expr ')'{ - $$ = new specify_target; - $$->polarity_op = '+'; - $$->dst = $2; - $$->dat = $4; - }; - -specify_edge: - TOK_POSEDGE { $$ = 'p'; } | - TOK_NEGEDGE { $$ = 'n'; } | - { $$ = 0; }; - -specify_rise_fall: - specify_triple { - $$ = new specify_rise_fall; - $$->rise = *$1; - $$->fall.t_min = $1->t_min->clone(); - $$->fall.t_avg = $1->t_avg->clone(); - $$->fall.t_max = $1->t_max->clone(); - delete $1; - } | - '(' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; - }; - -specify_triple: - expr { - $$ = new specify_triple; - $$->t_min = $1; - $$->t_avg = $1->clone(); - $$->t_max = $1->clone(); - } | - expr ':' expr ':' expr { - $$ = new specify_triple; - $$->t_min = $1; - $$->t_avg = $3; - $$->t_max = $5; - }; - -/******************** ignored specify parser **************************/ - -ignored_specify_block: - TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY | - TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ; - -ignored_specify_item_opt: - ignored_specify_item_opt ignored_specify_item | - ignored_specify_item ; - -ignored_specify_item: - specparam_declaration - // | pulsestyle_declaration - // | showcancelled_declaration - | path_declaration - | system_timing_declaration - ; - -specparam_declaration: - TOK_SPECPARAM list_of_specparam_assignments ';' | - TOK_SPECPARAM specparam_range list_of_specparam_assignments ';' ; - -// IEEE 1364-2005 calls this sinmply 'range' but the current 'range' rule allows empty match -// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 -// exxxxtending this for SV specparam would change this anyhow -specparam_range: - '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ; - -list_of_specparam_assignments: - specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; - -specparam_assignment: - ignspec_id '=' constant_mintypmax_expression ; - -ignspec_opt_cond: - TOK_IF '(' ignspec_expr ')' | /* empty */; - -path_declaration : - simple_path_declaration ';' - // | edge_sensitive_path_declaration - // | state_dependent_path_declaration - ; - -simple_path_declaration : - ignspec_opt_cond parallel_path_description '=' path_delay_value | - ignspec_opt_cond full_path_description '=' path_delay_value - ; - -path_delay_value : - '(' path_delay_expression list_of_path_delay_extra_expressions ')' - | path_delay_expression - | path_delay_expression list_of_path_delay_extra_expressions - ; - -list_of_path_delay_extra_expressions : - ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions; - -specify_edge_identifier : - TOK_POSEDGE | TOK_NEGEDGE ; - -parallel_path_description : - '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' | - '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' | - '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ; - -full_path_description : - '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' | - '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' | - '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ; - -// This was broken into 2 rules to solve shift/reduce conflicts -list_of_path_inputs : - specify_input_terminal_descriptor opt_polarity_operator | - specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ; - -more_path_inputs : - ',' specify_input_terminal_descriptor | - more_path_inputs ',' specify_input_terminal_descriptor ; - -list_of_path_outputs : - specify_output_terminal_descriptor | - list_of_path_outputs ',' specify_output_terminal_descriptor ; - -opt_polarity_operator : - '+' - | '-' - | ; - -// Good enough for the time being -specify_input_terminal_descriptor : - ignspec_id ; - -// Good enough for the time being -specify_output_terminal_descriptor : - ignspec_id ; - -system_timing_declaration : - ignspec_id '(' system_timing_args ')' ';' ; - -system_timing_arg : - TOK_POSEDGE ignspec_id | - TOK_NEGEDGE ignspec_id | - ignspec_expr ; - -system_timing_args : - system_timing_arg | - system_timing_args ',' system_timing_arg ; - -path_delay_expression : - ignspec_constant_expression; - -constant_mintypmax_expression : - ignspec_constant_expression - | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression - ; - -// for the time being this is OK, but we may write our own expr here. -// as I'm not sure it is legal to use a full expr here (probably not) -// On the other hand, other rules requiring constant expressions also use 'expr' -// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness -ignspec_constant_expression: - expr { delete $1; }; - -ignspec_expr: - expr { delete $1; }; - -ignspec_id: - TOK_ID { delete $1; }; - -/**********************************************************************/ - -param_signed: - TOK_SIGNED { - astbuf1->is_signed = true; - } | /* empty */; - -param_integer: - TOK_INTEGER { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Internal error in param_integer - should not happen?"); - astbuf1->children.push_back(new AstNode(AST_RANGE)); - astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); - astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); - astbuf1->is_signed = true; - } | /* empty */; - -param_real: - TOK_REAL { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real."); - astbuf1->children.push_back(new AstNode(AST_REALVALUE)); - } | /* empty */; - -param_range: - range { - if ($1 != NULL) { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("integer/real parameters should not have a range."); - astbuf1->children.push_back($1); - } - }; - -param_decl: - attr TOK_PARAMETER { - astbuf1 = new AstNode(AST_PARAMETER); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); - } param_signed param_integer param_real param_range param_decl_list ';' { - delete astbuf1; - }; - -localparam_decl: - attr TOK_LOCALPARAM { - astbuf1 = new AstNode(AST_LOCALPARAM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); - } param_signed param_integer param_real param_range param_decl_list ';' { - delete astbuf1; - }; - -param_decl_list: - single_param_decl | param_decl_list ',' single_param_decl; - -single_param_decl: - TOK_ID '=' expr { - AstNode *node; - if (astbuf1 == nullptr) { - if (!sv_mode) - frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); - node = new AstNode(AST_PARAMETER); - node->children.push_back(AstNode::mkconst_int(0, true)); - } else { - node = astbuf1->clone(); - } - node->str = *$1; - delete node->children[0]; - node->children[0] = $3; - ast_stack.back()->children.push_back(node); - delete $1; - }; - -defparam_decl: - TOK_DEFPARAM defparam_decl_list ';'; - -defparam_decl_list: - single_defparam_decl | defparam_decl_list ',' single_defparam_decl; - -single_defparam_decl: - range rvalue '=' expr { - AstNode *node = new AstNode(AST_DEFPARAM); - node->children.push_back($2); - node->children.push_back($4); - if ($1 != NULL) - node->children.push_back($1); - ast_stack.back()->children.push_back(node); - }; - -wire_decl: - attr wire_type range { - albuf = $1; - astbuf1 = $2; - astbuf2 = $3; - if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { - if (astbuf2) { - frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions."); - } else { - astbuf2 = new AstNode(AST_RANGE); - astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true)); - astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true)); - } - } - if (astbuf2 && astbuf2->children.size() != 2) - frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [:], [+:], or [-:]"); - } wire_name_list { - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); - } ';' | - attr TOK_SUPPLY0 TOK_ID { - ast_stack.back()->children.push_back(new AstNode(AST_WIRE)); - ast_stack.back()->children.back()->str = *$3; - append_attr(ast_stack.back()->children.back(), $1); - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))); - ast_stack.back()->children.back()->children[0]->str = *$3; - delete $3; - } opt_supply_wires ';' | - attr TOK_SUPPLY1 TOK_ID { - ast_stack.back()->children.push_back(new AstNode(AST_WIRE)); - ast_stack.back()->children.back()->str = *$3; - append_attr(ast_stack.back()->children.back(), $1); - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1))); - ast_stack.back()->children.back()->children[0]->str = *$3; - delete $3; - } opt_supply_wires ';'; - -opt_supply_wires: - /* empty */ | - opt_supply_wires ',' TOK_ID { - AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone(); - AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone(); - wire_node->str = *$3; - assign_node->children[0]->str = *$3; - ast_stack.back()->children.push_back(wire_node); - ast_stack.back()->children.push_back(assign_node); - delete $3; - }; - -wire_name_list: - wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign; - -wire_name_and_opt_assign: - wire_name { - bool attr_anyconst = false; - bool attr_anyseq = false; - bool attr_allconst = false; - bool attr_allseq = false; - if (ast_stack.back()->children.back()->get_bool_attribute("\\anyconst")) { - delete ast_stack.back()->children.back()->attributes.at("\\anyconst"); - ast_stack.back()->children.back()->attributes.erase("\\anyconst"); - attr_anyconst = true; - } - if (ast_stack.back()->children.back()->get_bool_attribute("\\anyseq")) { - delete ast_stack.back()->children.back()->attributes.at("\\anyseq"); - ast_stack.back()->children.back()->attributes.erase("\\anyseq"); - attr_anyseq = true; - } - if (ast_stack.back()->children.back()->get_bool_attribute("\\allconst")) { - delete ast_stack.back()->children.back()->attributes.at("\\allconst"); - ast_stack.back()->children.back()->attributes.erase("\\allconst"); - attr_allconst = true; - } - if (ast_stack.back()->children.back()->get_bool_attribute("\\allseq")) { - delete ast_stack.back()->children.back()->attributes.at("\\allseq"); - ast_stack.back()->children.back()->attributes.erase("\\allseq"); - attr_allseq = true; - } - if (current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) { - AstNode *wire = new AstNode(AST_IDENTIFIER); - AstNode *fcall = new AstNode(AST_FCALL); - wire->str = ast_stack.back()->children.back()->str; - fcall->str = current_wire_const ? "\\$anyconst" : "\\$anyseq"; - if (attr_anyconst) - fcall->str = "\\$anyconst"; - if (attr_anyseq) - fcall->str = "\\$anyseq"; - if (attr_allconst) - fcall->str = "\\$allconst"; - if (attr_allseq) - fcall->str = "\\$allseq"; - fcall->attributes["\\reg"] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str)); - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, fcall)); - } - } | - wire_name '=' expr { - AstNode *wire = new AstNode(AST_IDENTIFIER); - wire->str = ast_stack.back()->children.back()->str; - if (astbuf1->is_input) { - if (astbuf1->attributes.count("\\defaultvalue")) - delete astbuf1->attributes.at("\\defaultvalue"); - astbuf1->attributes["\\defaultvalue"] = $3; - } else - if (astbuf1->is_reg || astbuf1->is_logic) - ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3)))); - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3)); - }; - -wire_name: - TOK_ID range_or_multirange { - if (astbuf1 == nullptr) - frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node."); - AstNode *node = astbuf1->clone(); - node->str = *$1; - append_attr_clone(node, albuf); - if (astbuf2 != NULL) - node->children.push_back(astbuf2->clone()); - if ($2 != NULL) { - if (node->is_input || node->is_output) - frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions."); - if (!astbuf2) { - AstNode *rng = new AstNode(AST_RANGE); - rng->children.push_back(AstNode::mkconst_int(0, true)); - rng->children.push_back(AstNode::mkconst_int(0, true)); - node->children.push_back(rng); - } - node->type = AST_MEMORY; - auto *rangeNode = $2; - if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { - // SV array size [n], rewrite as [n-1:0] - rangeNode->children[0] = new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true)); - rangeNode->children.push_back(AstNode::mkconst_int(0, false)); - } - node->children.push_back(rangeNode); - } - if (current_function_or_task == NULL) { - if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) { - port_stubs[*$1] = ++port_counter; - } - if (port_stubs.count(*$1) != 0) { - if (!node->is_input && !node->is_output) - frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str()); - if (node->is_reg && node->is_input && !node->is_output && !sv_mode) - frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str()); - node->port_id = port_stubs[*$1]; - port_stubs.erase(*$1); - } else { - if (node->is_input || node->is_output) - frontend_verilog_yyerror("Module port `%s' is not declared in module header.", $1->c_str()); - } - } else { - if (node->is_input || node->is_output) - node->port_id = current_function_or_task_port_id++; - } - ast_stack.back()->children.push_back(node); - - delete $1; - }; - -assign_stmt: - TOK_ASSIGN delay assign_expr_list ';'; - -assign_expr_list: - assign_expr | assign_expr_list ',' assign_expr; - -assign_expr: - lvalue '=' expr { - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3)); - }; - -cell_stmt: - attr TOK_ID { - astbuf1 = new AstNode(AST_CELL); - append_attr(astbuf1, $1); - astbuf1->children.push_back(new AstNode(AST_CELLTYPE)); - astbuf1->children[0]->str = *$2; - delete $2; - } cell_parameter_list_opt cell_list ';' { - delete astbuf1; - } | - attr tok_prim_wrapper delay { - astbuf1 = new AstNode(AST_PRIMITIVE); - astbuf1->str = *$2; - append_attr(astbuf1, $1); - delete $2; - } prim_list ';' { - delete astbuf1; - }; - -tok_prim_wrapper: - TOK_PRIMITIVE { - $$ = $1; - } | - TOK_OR { - $$ = new std::string("or"); - }; - -cell_list: - single_cell | - cell_list ',' single_cell; - -single_cell: - TOK_ID { - astbuf2 = astbuf1->clone(); - if (astbuf2->type != AST_PRIMITIVE) - astbuf2->str = *$1; - delete $1; - ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')' | - TOK_ID non_opt_range { - astbuf2 = astbuf1->clone(); - if (astbuf2->type != AST_PRIMITIVE) - astbuf2->str = *$1; - delete $1; - ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2)); - } '(' cell_port_list ')'; - -prim_list: - single_prim | - prim_list ',' single_prim; - -single_prim: - single_cell | - /* no name */ { - astbuf2 = astbuf1->clone(); - ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')'; - -cell_parameter_list_opt: - '#' '(' cell_parameter_list ')' | /* empty */; - -cell_parameter_list: - cell_parameter | cell_parameter_list ',' cell_parameter; - -cell_parameter: - /* empty */ | - expr { - AstNode *node = new AstNode(AST_PARASET); - astbuf1->children.push_back(node); - node->children.push_back($1); - } | - '.' TOK_ID '(' expr ')' { - AstNode *node = new AstNode(AST_PARASET); - node->str = *$2; - astbuf1->children.push_back(node); - node->children.push_back($4); - delete $2; - }; - -cell_port_list: - cell_port_list_rules { - // remove empty args from end of list - while (!astbuf2->children.empty()) { - AstNode *node = astbuf2->children.back(); - if (node->type != AST_ARGUMENT) break; - if (!node->children.empty()) break; - if (!node->str.empty()) break; - astbuf2->children.pop_back(); - delete node; - } - - // check port types - bool has_positional_args = false; - bool has_named_args = false; - for (auto node : astbuf2->children) { - if (node->type != AST_ARGUMENT) continue; - if (node->str.empty()) - has_positional_args = true; - else - has_named_args = true; - } - - if (has_positional_args && has_named_args) - frontend_verilog_yyerror("Mix of positional and named cell ports."); - }; - -cell_port_list_rules: - cell_port | cell_port_list_rules ',' cell_port; - -cell_port: - attr { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); - free_attr($1); - } | - attr expr { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); - node->children.push_back($2); - free_attr($1); - } | - attr '.' TOK_ID '(' expr ')' { - AstNode *node = new AstNode(AST_ARGUMENT); - node->str = *$3; - astbuf2->children.push_back(node); - node->children.push_back($5); - delete $3; - free_attr($1); - } | - attr '.' TOK_ID '(' ')' { - AstNode *node = new AstNode(AST_ARGUMENT); - node->str = *$3; - astbuf2->children.push_back(node); - delete $3; - free_attr($1); - } | - attr '.' TOK_ID { - AstNode *node = new AstNode(AST_ARGUMENT); - node->str = *$3; - astbuf2->children.push_back(node); - node->children.push_back(new AstNode(AST_IDENTIFIER)); - node->children.back()->str = *$3; - delete $3; - free_attr($1); - }; - -always_stmt: - attr TOK_ALWAYS { - AstNode *node = new AstNode(AST_ALWAYS); - append_attr(node, $1); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } always_cond { - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); - } | - attr TOK_INITIAL { - AstNode *node = new AstNode(AST_INITIAL); - append_attr(node, $1); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); - }; - -always_cond: - '@' '(' always_events ')' | - '@' '(' '*' ')' | - '@' ATTR_BEGIN ')' | - '@' '(' ATTR_END | - '@' '*' | - /* empty */; - -always_events: - always_event | - always_events TOK_OR always_event | - always_events ',' always_event; - -always_event: - TOK_POSEDGE expr { - AstNode *node = new AstNode(AST_POSEDGE); - ast_stack.back()->children.push_back(node); - node->children.push_back($2); - } | - TOK_NEGEDGE expr { - AstNode *node = new AstNode(AST_NEGEDGE); - ast_stack.back()->children.push_back(node); - node->children.push_back($2); - } | - expr { - AstNode *node = new AstNode(AST_EDGE); - ast_stack.back()->children.push_back(node); - node->children.push_back($1); - }; - -opt_label: - ':' TOK_ID { - $$ = $2; - } | - /* empty */ { - $$ = NULL; - }; - -opt_sva_label: - TOK_SVA_LABEL ':' { - $$ = $1; - } | - /* empty */ { - $$ = NULL; - }; - -opt_property: - TOK_PROPERTY { - $$ = true; - } | - TOK_FINAL { - $$ = false; - } | - /* empty */ { - $$ = false; - }; - -modport_stmt: - TOK_MODPORT TOK_ID { - AstNode *modport = new AstNode(AST_MODPORT); - ast_stack.back()->children.push_back(modport); - ast_stack.push_back(modport); - modport->str = *$2; - delete $2; - } modport_args_opt { - ast_stack.pop_back(); - log_assert(ast_stack.size() == 2); - } ';' - -modport_args_opt: - '(' ')' | '(' modport_args optional_comma ')'; - -modport_args: - modport_arg | modport_args ',' modport_arg; - -modport_arg: - modport_type_token modport_member | - modport_member - -modport_member: - TOK_ID { - AstNode *modport_member = new AstNode(AST_MODPORTMEMBER); - ast_stack.back()->children.push_back(modport_member); - modport_member->str = *$1; - modport_member->is_input = current_modport_input; - modport_member->is_output = current_modport_output; - delete $1; - } - -modport_type_token: - TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;} - -assert: - opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' { - if (noassert_mode) { - delete $5; - } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); - if ($1 != nullptr) - node->str = *$1; - ast_stack.back()->children.push_back(node); - } - if ($1 != nullptr) - delete $1; - } | - opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' { - if (noassume_mode) { - delete $5; - } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); - if ($1 != nullptr) - node->str = *$1; - ast_stack.back()->children.push_back(node); - } - if ($1 != nullptr) - delete $1; - } | - opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassert_mode) { - delete $6; - } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); - if ($1 != nullptr) - node->str = *$1; - ast_stack.back()->children.push_back(node); - } - if ($1 != nullptr) - delete $1; - } | - opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassume_mode) { - delete $6; - } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6); - if ($1 != nullptr) - node->str = *$1; - ast_stack.back()->children.push_back(node); - } - if ($1 != nullptr) - delete $1; - } | - opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { - AstNode *node = new AstNode(AST_COVER, $5); - if ($1 != nullptr) { - node->str = *$1; - delete $1; - } - ast_stack.back()->children.push_back(node); - } | - opt_sva_label TOK_COVER opt_property '(' ')' ';' { - AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); - if ($1 != nullptr) { - node->str = *$1; - delete $1; - } - ast_stack.back()->children.push_back(node); - } | - opt_sva_label TOK_COVER ';' { - AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); - if ($1 != nullptr) { - node->str = *$1; - delete $1; - } - ast_stack.back()->children.push_back(node); - } | - opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' { - if (norestrict_mode) { - delete $5; - } else { - AstNode *node = new AstNode(AST_ASSUME, $5); - if ($1 != nullptr) - node->str = *$1; - ast_stack.back()->children.push_back(node); - } - if (!$3) - log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); - if ($1 != nullptr) - delete $1; - } | - opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) { - delete $6; - } else { - AstNode *node = new AstNode(AST_FAIR, $6); - if ($1 != nullptr) - node->str = *$1; - ast_stack.back()->children.push_back(node); - } - if (!$3) - log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); - if ($1 != nullptr) - delete $1; - }; - -assert_property: - opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { - if (norestrict_mode) { - delete $5; - } else { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } - } | - opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) { - delete $6; - } else { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } - }; - -simple_behavioral_stmt: - lvalue '=' delay expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4); - ast_stack.back()->children.push_back(node); - } | - lvalue TOK_INCREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_ADD, $1->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - } | - lvalue TOK_DECREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_SUB, $1->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - } | - lvalue OP_LE delay expr { - AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4); - ast_stack.back()->children.push_back(node); - }; - -// this production creates the obligatory if-else shift/reduce conflict -behavioral_stmt: - defattr | assert | wire_decl | param_decl | localparam_decl | - non_opt_delay behavioral_stmt | - simple_behavioral_stmt ';' | ';' | - hierarchical_id attr { - AstNode *node = new AstNode(AST_TCALL); - node->str = *$1; - delete $1; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $2); - } opt_arg_list ';'{ - ast_stack.pop_back(); - } | - TOK_MSG_TASKS attr { - AstNode *node = new AstNode(AST_TCALL); - node->str = *$1; - delete $1; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $2); - } opt_arg_list ';'{ - ast_stack.pop_back(); - } | - attr TOK_BEGIN opt_label { - AstNode *node = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $1); - if ($3 != NULL) - node->str = *$3; - } behavioral_stmt_list TOK_END opt_label { - if ($3 != NULL && $7 != NULL && *$3 != *$7) - frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1); - if ($3 != NULL) - delete $3; - if ($7 != NULL) - delete $7; - ast_stack.pop_back(); - } | - attr TOK_FOR '(' { - AstNode *node = new AstNode(AST_FOR); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $1); - } simple_behavioral_stmt ';' expr { - ast_stack.back()->children.push_back($7); - } ';' simple_behavioral_stmt ')' { - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); - } | - attr TOK_WHILE '(' expr ')' { - AstNode *node = new AstNode(AST_WHILE); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $1); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back($4); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); - } | - attr TOK_REPEAT '(' expr ')' { - AstNode *node = new AstNode(AST_REPEAT); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $1); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back($4); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); - } | - attr TOK_IF '(' expr ')' { - AstNode *node = new AstNode(AST_CASE); - AstNode *block = new AstNode(AST_BLOCK); - AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block); - ast_stack.back()->children.push_back(node); - node->children.push_back(new AstNode(AST_REDUCE_BOOL, $4)); - node->children.push_back(cond); - ast_stack.push_back(node); - ast_stack.push_back(block); - append_attr(node, $1); - } behavioral_stmt optional_else { - ast_stack.pop_back(); - ast_stack.pop_back(); - } | - case_attr case_type '(' expr ')' { - AstNode *node = new AstNode(AST_CASE, $4); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $1); - } opt_synopsys_attr case_body TOK_ENDCASE { - case_type_stack.pop_back(); - ast_stack.pop_back(); - }; - -unique_case_attr: - /* empty */ { - $$ = false; - } | - TOK_PRIORITY case_attr { - $$ = $2; - } | - TOK_UNIQUE case_attr { - $$ = true; - }; - -case_attr: - attr unique_case_attr { - if ($2) (*$1)["\\parallel_case"] = AstNode::mkconst_int(1, false); - $$ = $1; - }; - -case_type: - TOK_CASE { - case_type_stack.push_back(0); - } | - TOK_CASEX { - case_type_stack.push_back('x'); - } | - TOK_CASEZ { - case_type_stack.push_back('z'); - }; - -opt_synopsys_attr: - opt_synopsys_attr TOK_SYNOPSYS_FULL_CASE { - if (ast_stack.back()->attributes.count("\\full_case") == 0) - ast_stack.back()->attributes["\\full_case"] = AstNode::mkconst_int(1, false); - } | - opt_synopsys_attr TOK_SYNOPSYS_PARALLEL_CASE { - if (ast_stack.back()->attributes.count("\\parallel_case") == 0) - ast_stack.back()->attributes["\\parallel_case"] = AstNode::mkconst_int(1, false); - } | - /* empty */; - -behavioral_stmt_list: - behavioral_stmt_list behavioral_stmt | - /* empty */; - -optional_else: - TOK_ELSE { - AstNode *block = new AstNode(AST_BLOCK); - AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block); - ast_stack.pop_back(); - ast_stack.back()->children.push_back(cond); - ast_stack.push_back(block); - } behavioral_stmt | - /* empty */ %prec FAKE_THEN; - -case_body: - case_body case_item | - /* empty */; - -case_item: - { - AstNode *node = new AstNode( - case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : - case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } case_select { - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - case_type_stack.push_back(0); - } behavioral_stmt { - case_type_stack.pop_back(); - ast_stack.pop_back(); - ast_stack.pop_back(); - }; - -gen_case_body: - gen_case_body gen_case_item | - /* empty */; - -gen_case_item: - { - AstNode *node = new AstNode( - case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : - case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } case_select { - case_type_stack.push_back(0); - } gen_stmt_or_null { - case_type_stack.pop_back(); - ast_stack.pop_back(); - }; - -case_select: - case_expr_list ':' | - TOK_DEFAULT; - -case_expr_list: - TOK_DEFAULT { - ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT)); - } | - TOK_SVA_LABEL { - ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER)); - ast_stack.back()->children.back()->str = *$1; - delete $1; - } | - expr { - ast_stack.back()->children.push_back($1); - } | - case_expr_list ',' expr { - ast_stack.back()->children.push_back($3); - }; - -rvalue: - hierarchical_id '[' expr ']' '.' rvalue { - $$ = new AstNode(AST_PREFIX, $3, $6); - $$->str = *$1; - delete $1; - } | - hierarchical_id range { - $$ = new AstNode(AST_IDENTIFIER, $2); - $$->str = *$1; - delete $1; - if ($2 == nullptr && ($$->str == "\\$initstate" || - $$->str == "\\$anyconst" || $$->str == "\\$anyseq" || - $$->str == "\\$allconst" || $$->str == "\\$allseq")) - $$->type = AST_FCALL; - } | - hierarchical_id non_opt_multirange { - $$ = new AstNode(AST_IDENTIFIER, $2); - $$->str = *$1; - delete $1; - }; - -lvalue: - rvalue { - $$ = $1; - } | - '{' lvalue_concat_list '}' { - $$ = $2; - }; - -lvalue_concat_list: - expr { - $$ = new AstNode(AST_CONCAT); - $$->children.push_back($1); - } | - expr ',' lvalue_concat_list { - $$ = $3; - $$->children.push_back($1); - }; - -opt_arg_list: - '(' arg_list optional_comma ')' | - /* empty */; - -arg_list: - arg_list2 | - /* empty */; - -arg_list2: - single_arg | - arg_list ',' single_arg; - -single_arg: - expr { - ast_stack.back()->children.push_back($1); - }; - -module_gen_body: - module_gen_body gen_stmt_or_module_body_stmt | - /* empty */; - -gen_stmt_or_module_body_stmt: - gen_stmt | module_body_stmt; - -// this production creates the obligatory if-else shift/reduce conflict -gen_stmt: - TOK_FOR '(' { - AstNode *node = new AstNode(AST_GENFOR); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } simple_behavioral_stmt ';' expr { - ast_stack.back()->children.push_back($6); - } ';' simple_behavioral_stmt ')' gen_stmt_block { - ast_stack.pop_back(); - } | - TOK_IF '(' expr ')' { - AstNode *node = new AstNode(AST_GENIF); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - ast_stack.back()->children.push_back($3); - } gen_stmt_block opt_gen_else { - ast_stack.pop_back(); - } | - case_type '(' expr ')' { - AstNode *node = new AstNode(AST_GENCASE, $3); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } gen_case_body TOK_ENDCASE { - case_type_stack.pop_back(); - ast_stack.pop_back(); - } | - TOK_BEGIN opt_label { - AstNode *node = new AstNode(AST_GENBLOCK); - node->str = $2 ? *$2 : std::string(); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } module_gen_body TOK_END opt_label { - if ($2 != NULL) - delete $2; - if ($6 != NULL) - delete $6; - ast_stack.pop_back(); - } | - TOK_MSG_TASKS { - AstNode *node = new AstNode(AST_TECALL); - node->str = *$1; - delete $1; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } opt_arg_list ';'{ - ast_stack.pop_back(); - }; - -gen_stmt_block: - { - AstNode *node = new AstNode(AST_GENBLOCK); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } gen_stmt_or_module_body_stmt { - ast_stack.pop_back(); - }; - -gen_stmt_or_null: - gen_stmt_block | ';'; - -opt_gen_else: - TOK_ELSE gen_stmt_or_null | /* empty */ %prec FAKE_THEN; - -expr: - basic_expr { - $$ = $1; - } | - basic_expr '?' attr expr ':' expr { - $$ = new AstNode(AST_TERNARY); - $$->children.push_back($1); - $$->children.push_back($4); - $$->children.push_back($6); - append_attr($$, $3); - }; - -basic_expr: - rvalue { - $$ = $1; - } | - '(' expr ')' TOK_CONSTVAL { - if ($4->substr(0, 1) != "'") - frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); - AstNode *bits = $2; - AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - if (val == NULL) - log_error("Value conversion failed: `%s'\n", $4->c_str()); - $$ = new AstNode(AST_TO_BITS, bits, val); - delete $4; - } | - hierarchical_id TOK_CONSTVAL { - if ($2->substr(0, 1) != "'") - frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); - AstNode *bits = new AstNode(AST_IDENTIFIER); - bits->str = *$1; - AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - if (val == NULL) - log_error("Value conversion failed: `%s'\n", $2->c_str()); - $$ = new AstNode(AST_TO_BITS, bits, val); - delete $1; - delete $2; - } | - TOK_CONSTVAL TOK_CONSTVAL { - $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - if ($$ == NULL || (*$2)[0] != '\'') - log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str()); - delete $1; - delete $2; - } | - TOK_CONSTVAL { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - if ($$ == NULL) - log_error("Value conversion failed: `%s'\n", $1->c_str()); - delete $1; - } | - TOK_REALVAL { - $$ = new AstNode(AST_REALVALUE); - char *p = (char*)malloc(GetSize(*$1) + 1), *q; - for (int i = 0, j = 0; j < GetSize(*$1); j++) - if ((*$1)[j] != '_') - p[i++] = (*$1)[j], p[i] = 0; - $$->realvalue = strtod(p, &q); - log_assert(*q == 0); - delete $1; - free(p); - } | - TOK_STRING { - $$ = AstNode::mkconst_str(*$1); - delete $1; - } | - hierarchical_id attr { - AstNode *node = new AstNode(AST_FCALL); - node->str = *$1; - delete $1; - ast_stack.push_back(node); - append_attr(node, $2); - } '(' arg_list optional_comma ')' { - $$ = ast_stack.back(); - ast_stack.pop_back(); - } | - TOK_TO_SIGNED attr '(' expr ')' { - $$ = new AstNode(AST_TO_SIGNED, $4); - append_attr($$, $2); - } | - TOK_TO_UNSIGNED attr '(' expr ')' { - $$ = new AstNode(AST_TO_UNSIGNED, $4); - append_attr($$, $2); - } | - '(' expr ')' { - $$ = $2; - } | - '(' expr ':' expr ':' expr ')' { - delete $2; - $$ = $4; - delete $6; - } | - '{' concat_list '}' { - $$ = $2; - } | - '{' expr '{' concat_list '}' '}' { - $$ = new AstNode(AST_REPLICATE, $2, $4); - } | - '~' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_BIT_NOT, $3); - append_attr($$, $2); - } | - basic_expr '&' attr basic_expr { - $$ = new AstNode(AST_BIT_AND, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_NAND attr basic_expr { - $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_AND, $1, $4)); - append_attr($$, $3); - } | - basic_expr '|' attr basic_expr { - $$ = new AstNode(AST_BIT_OR, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_NOR attr basic_expr { - $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_OR, $1, $4)); - append_attr($$, $3); - } | - basic_expr '^' attr basic_expr { - $$ = new AstNode(AST_BIT_XOR, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_XNOR attr basic_expr { - $$ = new AstNode(AST_BIT_XNOR, $1, $4); - append_attr($$, $3); - } | - '&' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_AND, $3); - append_attr($$, $2); - } | - OP_NAND attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_AND, $3); - append_attr($$, $2); - $$ = new AstNode(AST_LOGIC_NOT, $$); - } | - '|' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_OR, $3); - append_attr($$, $2); - } | - OP_NOR attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_OR, $3); - append_attr($$, $2); - $$ = new AstNode(AST_LOGIC_NOT, $$); - } | - '^' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_XOR, $3); - append_attr($$, $2); - } | - OP_XNOR attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_XNOR, $3); - append_attr($$, $2); - } | - basic_expr OP_SHL attr basic_expr { - $$ = new AstNode(AST_SHIFT_LEFT, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_SHR attr basic_expr { - $$ = new AstNode(AST_SHIFT_RIGHT, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_SSHL attr basic_expr { - $$ = new AstNode(AST_SHIFT_SLEFT, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_SSHR attr basic_expr { - $$ = new AstNode(AST_SHIFT_SRIGHT, $1, $4); - append_attr($$, $3); - } | - basic_expr '<' attr basic_expr { - $$ = new AstNode(AST_LT, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_LE attr basic_expr { - $$ = new AstNode(AST_LE, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_EQ attr basic_expr { - $$ = new AstNode(AST_EQ, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_NE attr basic_expr { - $$ = new AstNode(AST_NE, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_EQX attr basic_expr { - $$ = new AstNode(AST_EQX, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_NEX attr basic_expr { - $$ = new AstNode(AST_NEX, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_GE attr basic_expr { - $$ = new AstNode(AST_GE, $1, $4); - append_attr($$, $3); - } | - basic_expr '>' attr basic_expr { - $$ = new AstNode(AST_GT, $1, $4); - append_attr($$, $3); - } | - basic_expr '+' attr basic_expr { - $$ = new AstNode(AST_ADD, $1, $4); - append_attr($$, $3); - } | - basic_expr '-' attr basic_expr { - $$ = new AstNode(AST_SUB, $1, $4); - append_attr($$, $3); - } | - basic_expr '*' attr basic_expr { - $$ = new AstNode(AST_MUL, $1, $4); - append_attr($$, $3); - } | - basic_expr '/' attr basic_expr { - $$ = new AstNode(AST_DIV, $1, $4); - append_attr($$, $3); - } | - basic_expr '%' attr basic_expr { - $$ = new AstNode(AST_MOD, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_POW attr basic_expr { - $$ = new AstNode(AST_POW, $1, $4); - append_attr($$, $3); - } | - '+' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_POS, $3); - append_attr($$, $2); - } | - '-' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_NEG, $3); - append_attr($$, $2); - } | - basic_expr OP_LAND attr basic_expr { - $$ = new AstNode(AST_LOGIC_AND, $1, $4); - append_attr($$, $3); - } | - basic_expr OP_LOR attr basic_expr { - $$ = new AstNode(AST_LOGIC_OR, $1, $4); - append_attr($$, $3); - } | - '!' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_LOGIC_NOT, $3); - append_attr($$, $2); - }; - -concat_list: - expr { - $$ = new AstNode(AST_CONCAT, $1); - } | - expr ',' concat_list { - $$ = $3; - $$->children.push_back($1); - }; diff --git a/yosys/kernel/bitpattern.h b/yosys/kernel/bitpattern.h deleted file mode 100644 index 894a95ed1..000000000 --- a/yosys/kernel/bitpattern.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef BITPATTERN_H -#define BITPATTERN_H - -#include "kernel/log.h" -#include "kernel/rtlil.h" - -YOSYS_NAMESPACE_BEGIN - -struct BitPatternPool -{ - int width; - struct bits_t { - std::vector bitdata; - mutable unsigned int cached_hash; - bits_t(int width = 0) : bitdata(width), cached_hash(0) { } - RTLIL::State &operator[](int index) { - return bitdata[index]; - } - const RTLIL::State &operator[](int index) const { - return bitdata[index]; - } - bool operator==(const bits_t &other) const { - if (hash() != other.hash()) - return false; - return bitdata == other.bitdata; - } - unsigned int hash() const { - if (!cached_hash) - cached_hash = hash_ops>::hash(bitdata); - return cached_hash; - } - }; - pool database; - - BitPatternPool(RTLIL::SigSpec sig) - { - width = sig.size(); - if (width > 0) { - bits_t pattern(width); - for (int i = 0; i < width; i++) { - if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1) - pattern[i] = sig[i].data; - else - pattern[i] = RTLIL::State::Sa; - } - database.insert(pattern); - } - } - - BitPatternPool(int width) - { - this->width = width; - if (width > 0) { - bits_t pattern(width); - for (int i = 0; i < width; i++) - pattern[i] = RTLIL::State::Sa; - database.insert(pattern); - } - } - - bits_t sig2bits(RTLIL::SigSpec sig) - { - bits_t bits; - bits.bitdata = sig.as_const().bits; - for (auto &b : bits.bitdata) - if (b > RTLIL::State::S1) - b = RTLIL::State::Sa; - return bits; - } - - bool match(bits_t a, bits_t b) - { - log_assert(int(a.bitdata.size()) == width); - log_assert(int(b.bitdata.size()) == width); - for (int i = 0; i < width; i++) - if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i]) - return false; - return true; - } - - bool has_any(RTLIL::SigSpec sig) - { - bits_t bits = sig2bits(sig); - for (auto &it : database) - if (match(it, bits)) - return true; - return false; - } - - bool has_all(RTLIL::SigSpec sig) - { - bits_t bits = sig2bits(sig); - for (auto &it : database) - if (match(it, bits)) { - for (int i = 0; i < width; i++) - if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1) - goto next_database_entry; - return true; - next_database_entry:; - } - return false; - } - - bool take(RTLIL::SigSpec sig) - { - bool status = false; - bits_t bits = sig2bits(sig); - for (auto it = database.begin(); it != database.end();) - if (match(*it, bits)) { - for (int i = 0; i < width; i++) { - if ((*it)[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa) - continue; - bits_t new_pattern; - new_pattern.bitdata = it->bitdata; - new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1; - database.insert(new_pattern); - } - it = database.erase(it); - status = true; - continue; - } else - ++it; - return status; - } - - bool take_all() - { - if (database.empty()) - return false; - database.clear(); - return true; - } - - bool empty() - { - return database.empty(); - } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/calc.cc b/yosys/kernel/calc.cc deleted file mode 100644 index 4a4840771..000000000 --- a/yosys/kernel/calc.cc +++ /dev/null @@ -1,586 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// [[CITE]] Power-Modulus Algorithm -// Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms, and Source Code in C, -// Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4, page 244 - -#include "kernel/yosys.h" -#include "libs/bigint/BigIntegerLibrary.hh" - -YOSYS_NAMESPACE_BEGIN - -static void extend_u0(RTLIL::Const &arg, int width, bool is_signed) -{ - RTLIL::State padding = RTLIL::State::S0; - - if (arg.bits.size() > 0 && is_signed) - padding = arg.bits.back(); - - while (int(arg.bits.size()) < width) - arg.bits.push_back(padding); - - arg.bits.resize(width); -} - -static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_bit_pos) -{ - BigUnsigned mag; - - BigInteger::Sign sign = BigInteger::positive; - State inv_sign_bit = RTLIL::State::S1; - size_t num_bits = val.bits.size(); - - if (as_signed && num_bits && val.bits[num_bits-1] == RTLIL::State::S1) { - inv_sign_bit = RTLIL::State::S0; - sign = BigInteger::negative; - num_bits--; - } - - for (size_t i = 0; i < num_bits; i++) - if (val.bits[i] == RTLIL::State::S0 || val.bits[i] == RTLIL::State::S1) - mag.setBit(i, val.bits[i] == inv_sign_bit); - else if (undef_bit_pos < 0) - undef_bit_pos = i; - - if (sign == BigInteger::negative) - mag += 1; - - return BigInteger(mag, sign); -} - -static RTLIL::Const big2const(const BigInteger &val, int result_len, int undef_bit_pos) -{ - if (undef_bit_pos >= 0) - return RTLIL::Const(RTLIL::State::Sx, result_len); - - BigUnsigned mag = val.getMagnitude(); - RTLIL::Const result(0, result_len); - - if (!mag.isZero()) - { - if (val.getSign() < 0) - { - mag--; - for (int i = 0; i < result_len; i++) - result.bits[i] = mag.getBit(i) ? RTLIL::State::S0 : RTLIL::State::S1; - } - else - { - for (int i = 0; i < result_len; i++) - result.bits[i] = mag.getBit(i) ? RTLIL::State::S1 : RTLIL::State::S0; - } - } - -#if 0 - if (undef_bit_pos >= 0) - for (int i = undef_bit_pos; i < result_len; i++) - result.bits[i] = RTLIL::State::Sx; -#endif - - return result; -} - -static RTLIL::State logic_and(RTLIL::State a, RTLIL::State b) -{ - if (a == RTLIL::State::S0) return RTLIL::State::S0; - if (b == RTLIL::State::S0) return RTLIL::State::S0; - if (a != RTLIL::State::S1) return RTLIL::State::Sx; - if (b != RTLIL::State::S1) return RTLIL::State::Sx; - return RTLIL::State::S1; -} - -static RTLIL::State logic_or(RTLIL::State a, RTLIL::State b) -{ - if (a == RTLIL::State::S1) return RTLIL::State::S1; - if (b == RTLIL::State::S1) return RTLIL::State::S1; - if (a != RTLIL::State::S0) return RTLIL::State::Sx; - if (b != RTLIL::State::S0) return RTLIL::State::Sx; - return RTLIL::State::S0; -} - -static RTLIL::State logic_xor(RTLIL::State a, RTLIL::State b) -{ - if (a != RTLIL::State::S0 && a != RTLIL::State::S1) return RTLIL::State::Sx; - if (b != RTLIL::State::S0 && b != RTLIL::State::S1) return RTLIL::State::Sx; - return a != b ? RTLIL::State::S1 : RTLIL::State::S0; -} - -static RTLIL::State logic_xnor(RTLIL::State a, RTLIL::State b) -{ - if (a != RTLIL::State::S0 && a != RTLIL::State::S1) return RTLIL::State::Sx; - if (b != RTLIL::State::S0 && b != RTLIL::State::S1) return RTLIL::State::Sx; - return a == b ? RTLIL::State::S1 : RTLIL::State::S0; -} - -RTLIL::Const RTLIL::const_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) -{ - if (result_len < 0) - result_len = arg1.bits.size(); - - RTLIL::Const arg1_ext = arg1; - extend_u0(arg1_ext, result_len, signed1); - - RTLIL::Const result(RTLIL::State::Sx, result_len); - for (size_t i = 0; i < size_t(result_len); i++) { - if (i >= arg1_ext.bits.size()) - result.bits[i] = RTLIL::State::S0; - else if (arg1_ext.bits[i] == RTLIL::State::S0) - result.bits[i] = RTLIL::State::S1; - else if (arg1_ext.bits[i] == RTLIL::State::S1) - result.bits[i] = RTLIL::State::S0; - } - - return result; -} - -static RTLIL::Const logic_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL::State), - RTLIL::Const arg1, RTLIL::Const arg2, bool signed1, bool signed2, int result_len = -1) -{ - if (result_len < 0) - result_len = max(arg1.bits.size(), arg2.bits.size()); - - extend_u0(arg1, result_len, signed1); - extend_u0(arg2, result_len, signed2); - - RTLIL::Const result(RTLIL::State::Sx, result_len); - for (size_t i = 0; i < size_t(result_len); i++) { - RTLIL::State a = i < arg1.bits.size() ? arg1.bits[i] : RTLIL::State::S0; - RTLIL::State b = i < arg2.bits.size() ? arg2.bits[i] : RTLIL::State::S0; - result.bits[i] = logic_func(a, b); - } - - return result; -} - -RTLIL::Const RTLIL::const_and(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - return logic_wrapper(logic_and, arg1, arg2, signed1, signed2, result_len); -} - -RTLIL::Const RTLIL::const_or(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - return logic_wrapper(logic_or, arg1, arg2, signed1, signed2, result_len); -} - -RTLIL::Const RTLIL::const_xor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - return logic_wrapper(logic_xor, arg1, arg2, signed1, signed2, result_len); -} - -RTLIL::Const RTLIL::const_xnor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - return logic_wrapper(logic_xnor, arg1, arg2, signed1, signed2, result_len); -} - -static RTLIL::Const logic_reduce_wrapper(RTLIL::State initial, RTLIL::State(*logic_func)(RTLIL::State, RTLIL::State), const RTLIL::Const &arg1, int result_len) -{ - RTLIL::State temp = initial; - - for (size_t i = 0; i < arg1.bits.size(); i++) - temp = logic_func(temp, arg1.bits[i]); - - RTLIL::Const result(temp); - while (int(result.bits.size()) < result_len) - result.bits.push_back(RTLIL::State::S0); - return result; -} - -RTLIL::Const RTLIL::const_reduce_and(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int result_len) -{ - return logic_reduce_wrapper(RTLIL::State::S1, logic_and, arg1, result_len); -} - -RTLIL::Const RTLIL::const_reduce_or(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int result_len) -{ - return logic_reduce_wrapper(RTLIL::State::S0, logic_or, arg1, result_len); -} - -RTLIL::Const RTLIL::const_reduce_xor(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int result_len) -{ - return logic_reduce_wrapper(RTLIL::State::S0, logic_xor, arg1, result_len); -} - -RTLIL::Const RTLIL::const_reduce_xnor(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int result_len) -{ - RTLIL::Const buffer = logic_reduce_wrapper(RTLIL::State::S0, logic_xor, arg1, result_len); - if (!buffer.bits.empty()) { - if (buffer.bits.front() == RTLIL::State::S0) - buffer.bits.front() = RTLIL::State::S1; - else if (buffer.bits.front() == RTLIL::State::S1) - buffer.bits.front() = RTLIL::State::S0; - } - return buffer; -} - -RTLIL::Const RTLIL::const_reduce_bool(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int result_len) -{ - return logic_reduce_wrapper(RTLIL::State::S0, logic_or, arg1, result_len); -} - -RTLIL::Const RTLIL::const_logic_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) -{ - int undef_bit_pos_a = -1; - BigInteger a = const2big(arg1, signed1, undef_bit_pos_a); - RTLIL::Const result(a.isZero() ? undef_bit_pos_a >= 0 ? RTLIL::State::Sx : RTLIL::State::S1 : RTLIL::State::S0); - - while (int(result.bits.size()) < result_len) - result.bits.push_back(RTLIL::State::S0); - return result; -} - -RTLIL::Const RTLIL::const_logic_and(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos_a = -1, undef_bit_pos_b = -1; - BigInteger a = const2big(arg1, signed1, undef_bit_pos_a); - BigInteger b = const2big(arg2, signed2, undef_bit_pos_b); - - RTLIL::State bit_a = a.isZero() ? undef_bit_pos_a >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1; - RTLIL::State bit_b = b.isZero() ? undef_bit_pos_b >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1; - RTLIL::Const result(logic_and(bit_a, bit_b)); - - while (int(result.bits.size()) < result_len) - result.bits.push_back(RTLIL::State::S0); - return result; -} - -RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos_a = -1, undef_bit_pos_b = -1; - BigInteger a = const2big(arg1, signed1, undef_bit_pos_a); - BigInteger b = const2big(arg2, signed2, undef_bit_pos_b); - - RTLIL::State bit_a = a.isZero() ? undef_bit_pos_a >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1; - RTLIL::State bit_b = b.isZero() ? undef_bit_pos_b >= 0 ? RTLIL::State::Sx : RTLIL::State::S0 : RTLIL::State::S1; - RTLIL::Const result(logic_or(bit_a, bit_b)); - - while (int(result.bits.size()) < result_len) - result.bits.push_back(RTLIL::State::S0); - return result; -} - -static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len) -{ - int undef_bit_pos = -1; - BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction; - - if (result_len < 0) - result_len = arg1.bits.size(); - - RTLIL::Const result(RTLIL::State::Sx, result_len); - if (undef_bit_pos >= 0) - return result; - - for (int i = 0; i < result_len; i++) { - BigInteger pos = BigInteger(i) + offset; - if (pos < 0) - result.bits[i] = RTLIL::State::S0; - else if (pos >= BigInteger(int(arg1.bits.size()))) - result.bits[i] = sign_ext ? arg1.bits.back() : RTLIL::State::S0; - else - result.bits[i] = arg1.bits[pos.toInt()]; - } - - return result; -} - -RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len) -{ - RTLIL::Const arg1_ext = arg1; - extend_u0(arg1_ext, result_len, signed1); - return const_shift_worker(arg1_ext, arg2, false, -1, result_len); -} - -RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len) -{ - RTLIL::Const arg1_ext = arg1; - extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1); - return const_shift_worker(arg1_ext, arg2, false, +1, result_len); -} - -RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - if (!signed1) - return const_shl(arg1, arg2, signed1, signed2, result_len); - return const_shift_worker(arg1, arg2, true, -1, result_len); -} - -RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - if (!signed1) - return const_shr(arg1, arg2, signed1, signed2, result_len); - return const_shift_worker(arg1, arg2, true, +1, result_len); -} - -static RTLIL::Const const_shift_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len, RTLIL::State other_bits) -{ - int undef_bit_pos = -1; - BigInteger offset = const2big(arg2, signed2, undef_bit_pos); - - if (result_len < 0) - result_len = arg1.bits.size(); - - RTLIL::Const result(RTLIL::State::Sx, result_len); - if (undef_bit_pos >= 0) - return result; - - for (int i = 0; i < result_len; i++) { - BigInteger pos = BigInteger(i) + offset; - if (pos < 0 || pos >= BigInteger(int(arg1.bits.size()))) - result.bits[i] = other_bits; - else - result.bits[i] = arg1.bits[pos.toInt()]; - } - - return result; -} - -RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::S0); -} - -RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::Sx); -} - -RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - bool y = const2big(arg1, signed1, undef_bit_pos) < const2big(arg2, signed2, undef_bit_pos); - RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0); - - while (int(result.bits.size()) < result_len) - result.bits.push_back(RTLIL::State::S0); - return result; -} - -RTLIL::Const RTLIL::const_le(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - bool y = const2big(arg1, signed1, undef_bit_pos) <= const2big(arg2, signed2, undef_bit_pos); - RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0); - - while (int(result.bits.size()) < result_len) - result.bits.push_back(RTLIL::State::S0); - return result; -} - -RTLIL::Const RTLIL::const_eq(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - RTLIL::Const arg1_ext = arg1; - RTLIL::Const arg2_ext = arg2; - RTLIL::Const result(RTLIL::State::S0, result_len); - - int width = max(arg1_ext.bits.size(), arg2_ext.bits.size()); - extend_u0(arg1_ext, width, signed1 && signed2); - extend_u0(arg2_ext, width, signed1 && signed2); - - RTLIL::State matched_status = RTLIL::State::S1; - for (size_t i = 0; i < arg1_ext.bits.size(); i++) { - if (arg1_ext.bits.at(i) == RTLIL::State::S0 && arg2_ext.bits.at(i) == RTLIL::State::S1) - return result; - if (arg1_ext.bits.at(i) == RTLIL::State::S1 && arg2_ext.bits.at(i) == RTLIL::State::S0) - return result; - if (arg1_ext.bits.at(i) > RTLIL::State::S1 || arg2_ext.bits.at(i) > RTLIL::State::S1) - matched_status = RTLIL::State::Sx; - } - - result.bits.front() = matched_status; - return result; -} - -RTLIL::Const RTLIL::const_ne(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - RTLIL::Const result = RTLIL::const_eq(arg1, arg2, signed1, signed2, result_len); - if (result.bits.front() == RTLIL::State::S0) - result.bits.front() = RTLIL::State::S1; - else if (result.bits.front() == RTLIL::State::S1) - result.bits.front() = RTLIL::State::S0; - return result; -} - -RTLIL::Const RTLIL::const_eqx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - RTLIL::Const arg1_ext = arg1; - RTLIL::Const arg2_ext = arg2; - RTLIL::Const result(RTLIL::State::S0, result_len); - - int width = max(arg1_ext.bits.size(), arg2_ext.bits.size()); - extend_u0(arg1_ext, width, signed1 && signed2); - extend_u0(arg2_ext, width, signed1 && signed2); - - for (size_t i = 0; i < arg1_ext.bits.size(); i++) { - if (arg1_ext.bits.at(i) != arg2_ext.bits.at(i)) - return result; - } - - result.bits.front() = RTLIL::State::S1; - return result; -} - -RTLIL::Const RTLIL::const_nex(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - RTLIL::Const result = RTLIL::const_eqx(arg1, arg2, signed1, signed2, result_len); - if (result.bits.front() == RTLIL::State::S0) - result.bits.front() = RTLIL::State::S1; - else if (result.bits.front() == RTLIL::State::S1) - result.bits.front() = RTLIL::State::S0; - return result; -} - -RTLIL::Const RTLIL::const_ge(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - bool y = const2big(arg1, signed1, undef_bit_pos) >= const2big(arg2, signed2, undef_bit_pos); - RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0); - - while (int(result.bits.size()) < result_len) - result.bits.push_back(RTLIL::State::S0); - return result; -} - -RTLIL::Const RTLIL::const_gt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - bool y = const2big(arg1, signed1, undef_bit_pos) > const2big(arg2, signed2, undef_bit_pos); - RTLIL::Const result(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0); - - while (int(result.bits.size()) < result_len) - result.bits.push_back(RTLIL::State::S0); - return result; -} - -RTLIL::Const RTLIL::const_add(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - BigInteger y = const2big(arg1, signed1, undef_bit_pos) + const2big(arg2, signed2, undef_bit_pos); - return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos); -} - -RTLIL::Const RTLIL::const_sub(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - BigInteger y = const2big(arg1, signed1, undef_bit_pos) - const2big(arg2, signed2, undef_bit_pos); - return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos); -} - -RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - BigInteger y = const2big(arg1, signed1, undef_bit_pos) * const2big(arg2, signed2, undef_bit_pos); - return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); -} - -RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - BigInteger a = const2big(arg1, signed1, undef_bit_pos); - BigInteger b = const2big(arg2, signed2, undef_bit_pos); - if (b.isZero()) - return RTLIL::Const(RTLIL::State::Sx, result_len); - bool result_neg = (a.getSign() == BigInteger::negative) != (b.getSign() == BigInteger::negative); - a = a.getSign() == BigInteger::negative ? -a : a; - b = b.getSign() == BigInteger::negative ? -b : b; - return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); -} - -RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - BigInteger a = const2big(arg1, signed1, undef_bit_pos); - BigInteger b = const2big(arg2, signed2, undef_bit_pos); - if (b.isZero()) - return RTLIL::Const(RTLIL::State::Sx, result_len); - bool result_neg = a.getSign() == BigInteger::negative; - a = a.getSign() == BigInteger::negative ? -a : a; - b = b.getSign() == BigInteger::negative ? -b : b; - return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); -} - -RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) -{ - int undef_bit_pos = -1; - - BigInteger a = const2big(arg1, signed1, undef_bit_pos); - BigInteger b = const2big(arg2, signed2, undef_bit_pos); - BigInteger y = 1; - - if (a == 0 && b < 0) - return RTLIL::Const(RTLIL::State::Sx, result_len); - - if (a == 0 && b > 0) - return RTLIL::Const(RTLIL::State::S0, result_len); - - if (b < 0) - { - if (a < -1 || a > 1) - y = 0; - if (a == -1) - y = (-b % 2) == 0 ? 1 : -1; - } - - if (b > 0) - { - // Power-modulo with 2^result_len as modulus - BigInteger modulus = 1; - int modulus_bits = (result_len >= 0 ? result_len : 1024); - for (int i = 0; i < modulus_bits; i++) - modulus *= 2; - - bool flip_result_sign = false; - if (a < 0) { - a *= -1; - if (b % 2 == 1) - flip_result_sign = true; - } - - while (b > 0) { - if (b % 2 == 1) - y = (y * a) % modulus; - b = b / 2; - a = (a * a) % modulus; - } - - if (flip_result_sign) - y *= -1; - } - - return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); -} - -RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) -{ - RTLIL::Const arg1_ext = arg1; - extend_u0(arg1_ext, result_len, signed1); - - return arg1_ext; -} - -RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) -{ - RTLIL::Const arg1_ext = arg1; - RTLIL::Const zero(RTLIL::State::S0, 1); - - return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len); -} - -YOSYS_NAMESPACE_END - diff --git a/yosys/kernel/cellaigs.cc b/yosys/kernel/cellaigs.cc deleted file mode 100644 index 26c625f89..000000000 --- a/yosys/kernel/cellaigs.cc +++ /dev/null @@ -1,493 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/cellaigs.h" - -YOSYS_NAMESPACE_BEGIN - -AigNode::AigNode() -{ - portbit = -1; - inverter = false; - left_parent = -1; - right_parent = -1; -} - -bool AigNode::operator==(const AigNode &other) const -{ - if (portname != other.portname) return false; - if (portbit != other.portbit) return false; - if (inverter != other.inverter) return false; - if (left_parent != other.left_parent) return false; - if (right_parent != other.right_parent) return false; - return true; -} - -unsigned int AigNode::hash() 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); - return h; -} - -bool Aig::operator==(const Aig &other) const -{ - return name == other.name; -} - -unsigned int Aig::hash() const -{ - return hash_ops::hash(name); -} - -struct AigMaker -{ - Aig *aig; - Cell *cell; - idict aig_indices; - - int the_true_node; - int the_false_node; - - AigMaker(Aig *aig, Cell *cell) : aig(aig), cell(cell) - { - the_true_node = -1; - the_false_node = -1; - } - - int node2index(const AigNode &node) - { - if (node.left_parent > node.right_parent) { - AigNode n(node); - std::swap(n.left_parent, n.right_parent); - return node2index(n); - } - - if (!aig_indices.count(node)) { - aig_indices.expect(node, GetSize(aig->nodes)); - aig->nodes.push_back(node); - } - - return aig_indices.at(node); - } - - int bool_node(bool value) - { - AigNode node; - node.inverter = value; - return node2index(node); - } - - int inport(IdString portname, int portbit = 0, bool inverter = false) - { - if (portbit >= GetSize(cell->getPort(portname))) { - if (cell->parameters.count(portname.str() + "_SIGNED") && cell->getParam(portname.str() + "_SIGNED").as_bool()) - return inport(portname, GetSize(cell->getPort(portname))-1, inverter); - return bool_node(inverter); - } - - AigNode node; - node.portname = portname; - node.portbit = portbit; - node.inverter = inverter; - return node2index(node); - } - - vector inport_vec(IdString portname, int width) - { - vector vec; - for (int i = 0; i < width; i++) - vec.push_back(inport(portname, i)); - return vec; - } - - int not_inport(IdString portname, int portbit = 0) - { - return inport(portname, portbit, true); - } - - int not_gate(int A) - { - AigNode node(aig_indices[A]); - node.outports.clear(); - node.inverter = !node.inverter; - return node2index(node); - } - - int and_gate(int A, int B, bool inverter = false) - { - if (A == B) - return inverter ? not_gate(A) : A; - - const AigNode &nA = aig_indices[A]; - const AigNode &nB = aig_indices[B]; - - AigNode nB_inv(nB); - nB_inv.inverter = !nB_inv.inverter; - - if (nA == nB_inv) - return bool_node(inverter); - - bool nA_bool = nA.portbit < 0 && nA.left_parent < 0 && nA.right_parent < 0; - bool nB_bool = nB.portbit < 0 && nB.left_parent < 0 && nB.right_parent < 0; - - if (nA_bool && nB_bool) { - bool bA = nA.inverter; - bool bB = nB.inverter; - return bool_node(inverter != (bA && bB)); - } - - if (nA_bool) { - bool bA = nA.inverter; - if (inverter) - return bA ? not_gate(B) : bool_node(true); - return bA ? B : bool_node(false); - } - - if (nB_bool) { - bool bB = nB.inverter; - if (inverter) - return bB ? not_gate(A) : bool_node(true); - return bB ? A : bool_node(false); - } - - AigNode node; - node.inverter = inverter; - node.left_parent = A; - node.right_parent = B; - return node2index(node); - } - - int nand_gate(int A, int B) - { - return and_gate(A, B, true); - } - - int or_gate(int A, int B) - { - return nand_gate(not_gate(A), not_gate(B)); - } - - int nor_gate(int A, int B) - { - return and_gate(not_gate(A), not_gate(B)); - } - - int xor_gate(int A, int B) - { - return nor_gate(and_gate(A, B), nor_gate(A, B)); - } - - int xnor_gate(int A, int B) - { - return or_gate(and_gate(A, B), nor_gate(A, B)); - } - - int andnot_gate(int A, int B) - { - return and_gate(A, not_gate(B)); - } - - int ornot_gate(int A, int B) - { - return or_gate(A, not_gate(B)); - } - - int mux_gate(int A, int B, int S) - { - return or_gate(and_gate(A, not_gate(S)), and_gate(B, S)); - } - - vector adder(const vector &A, const vector &B, int carry, vector *X = nullptr, vector *CO = nullptr) - { - vector Y(GetSize(A)); - log_assert(GetSize(A) == GetSize(B)); - for (int i = 0; i < GetSize(A); i++) { - Y[i] = xor_gate(xor_gate(A[i], B[i]), carry); - carry = or_gate(and_gate(A[i], B[i]), and_gate(or_gate(A[i], B[i]), carry)); - if (X != nullptr) - X->at(i) = xor_gate(A[i], B[i]); - if (CO != nullptr) - CO->at(i) = carry; - } - return Y; - } - - void outport(int node, IdString portname, int portbit = 0) - { - if (portbit < GetSize(cell->getPort(portname))) - aig->nodes.at(node).outports.push_back(pair(portname, portbit)); - } - - void outport_bool(int node, IdString portname) - { - outport(node, portname); - for (int i = 1; i < GetSize(cell->getPort(portname)); i++) - outport(bool_node(false), portname, i); - } - - void outport_vec(const vector &vec, IdString portname) - { - for (int i = 0; i < GetSize(vec); i++) - outport(vec.at(i), portname, i); - } -}; - -Aig::Aig(Cell *cell) -{ - if (cell->type[0] != '$') - return; - - AigMaker mk(this, cell); - name = cell->type.str(); - - string mkname_last; - bool mkname_a_signed = false; - bool mkname_b_signed = false; - bool mkname_is_signed = false; - - cell->parameters.sort(); - for (auto p : cell->parameters) - { - if (p.first == "\\A_WIDTH" && mkname_a_signed) { - name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); - } else if (p.first == "\\B_WIDTH" && mkname_b_signed) { - name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); - } else { - mkname_last = name; - name += stringf(":%d", p.second.as_int()); - } - - mkname_a_signed = false; - mkname_b_signed = false; - mkname_is_signed = false; - if (p.first == "\\A_SIGNED") { - mkname_a_signed = true; - mkname_is_signed = p.second.as_bool(); - } - if (p.first == "\\B_SIGNED") { - mkname_b_signed = true; - mkname_is_signed = p.second.as_bool(); - } - } - - if (cell->type.in("$not", "$_NOT_", "$pos", "$_BUF_")) - { - for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { - int A = mk.inport("\\A", i); - int Y = cell->type.in("$not", "$_NOT_") ? mk.not_gate(A) : A; - mk.outport(Y, "\\Y", i); - } - goto optimize; - } - - if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) - { - for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { - int A = mk.inport("\\A", i); - int B = mk.inport("\\B", i); - int Y = cell->type.in("$and", "$_AND_") ? mk.and_gate(A, B) : - cell->type.in("$_NAND_") ? mk.nand_gate(A, B) : - cell->type.in("$or", "$_OR_") ? mk.or_gate(A, B) : - cell->type.in("$_NOR_") ? mk.nor_gate(A, B) : - cell->type.in("$xor", "$_XOR_") ? mk.xor_gate(A, B) : - cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) : - cell->type.in("$_ANDNOT_") ? mk.andnot_gate(A, B) : - cell->type.in("$_ORNOT_") ? mk.ornot_gate(A, B) : -1; - mk.outport(Y, "\\Y", i); - } - goto optimize; - } - - if (cell->type.in("$mux", "$_MUX_")) - { - int S = mk.inport("\\S"); - for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { - int A = mk.inport("\\A", i); - int B = mk.inport("\\B", i); - int Y = mk.mux_gate(A, B, S); - mk.outport(Y, "\\Y", i); - } - goto optimize; - } - - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) - { - int Y = mk.inport("\\A", 0); - for (int i = 1; i < GetSize(cell->getPort("\\A")); i++) { - int A = mk.inport("\\A", i); - if (cell->type == "$reduce_and") Y = mk.and_gate(A, Y); - if (cell->type == "$reduce_or") Y = mk.or_gate(A, Y); - if (cell->type == "$reduce_bool") Y = mk.or_gate(A, Y); - if (cell->type == "$reduce_xor") Y = mk.xor_gate(A, Y); - if (cell->type == "$reduce_xnor") Y = mk.xor_gate(A, Y); - } - if (cell->type == "$reduce_xnor") - Y = mk.not_gate(Y); - mk.outport(Y, "\\Y", 0); - for (int i = 1; i < GetSize(cell->getPort("\\Y")); i++) - mk.outport(mk.bool_node(false), "\\Y", i); - goto optimize; - } - - if (cell->type.in("$logic_not", "$logic_and", "$logic_or")) - { - int A = mk.inport("\\A", 0), Y = -1; - for (int i = 1; i < GetSize(cell->getPort("\\A")); i++) - A = mk.or_gate(mk.inport("\\A", i), A); - if (cell->type.in("$logic_and", "$logic_or")) { - int B = mk.inport("\\B", 0); - for (int i = 1; i < GetSize(cell->getPort("\\B")); i++) - B = mk.or_gate(mk.inport("\\B", i), B); - if (cell->type == "$logic_and") Y = mk.and_gate(A, B); - if (cell->type == "$logic_or") Y = mk.or_gate(A, B); - } else { - if (cell->type == "$logic_not") Y = mk.not_gate(A); - } - mk.outport_bool(Y, "\\Y"); - goto optimize; - } - - if (cell->type.in("$add", "$sub")) - { - int width = GetSize(cell->getPort("\\Y")); - vector A = mk.inport_vec("\\A", width); - vector B = mk.inport_vec("\\B", width); - int carry = mk.bool_node(false); - if (cell->type == "$sub") { - for (auto &n : B) - n = mk.not_gate(n); - carry = mk.not_gate(carry); - } - vector Y = mk.adder(A, B, carry); - mk.outport_vec(Y, "\\Y"); - goto optimize; - } - - if (cell->type == "$alu") - { - int width = GetSize(cell->getPort("\\Y")); - vector A = mk.inport_vec("\\A", width); - vector B = mk.inport_vec("\\B", width); - int carry = mk.inport("\\CI"); - int binv = mk.inport("\\BI"); - for (auto &n : B) - n = mk.xor_gate(n, binv); - vector X(width), CO(width); - vector Y = mk.adder(A, B, carry, &X, &CO); - for (int i = 0; i < width; i++) - X[i] = mk.xor_gate(A[i], B[i]); - mk.outport_vec(Y, "\\Y"); - mk.outport_vec(X, "\\X"); - mk.outport_vec(CO, "\\CO"); - goto optimize; - } - - if (cell->type.in("$eq", "$ne")) - { - int width = max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B"))); - vector A = mk.inport_vec("\\A", width); - vector B = mk.inport_vec("\\B", width); - int Y = mk.bool_node(false); - for (int i = 0; i < width; i++) - Y = mk.or_gate(Y, mk.xor_gate(A[i], B[i])); - if (cell->type == "$eq") - Y = mk.not_gate(Y); - mk.outport_bool(Y, "\\Y"); - goto optimize; - } - - if (cell->type == "$_AOI3_") - { - int A = mk.inport("\\A"); - int B = mk.inport("\\B"); - int C = mk.inport("\\C"); - int Y = mk.nor_gate(mk.and_gate(A, B), C); - mk.outport(Y, "\\Y"); - goto optimize; - } - - if (cell->type == "$_OAI3_") - { - int A = mk.inport("\\A"); - int B = mk.inport("\\B"); - int C = mk.inport("\\C"); - int Y = mk.nand_gate(mk.or_gate(A, B), C); - mk.outport(Y, "\\Y"); - goto optimize; - } - - if (cell->type == "$_AOI4_") - { - int A = mk.inport("\\A"); - int B = mk.inport("\\B"); - int C = mk.inport("\\C"); - int D = mk.inport("\\D"); - int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D)); - mk.outport(Y, "\\Y"); - goto optimize; - } - - if (cell->type == "$_OAI4_") - { - int A = mk.inport("\\A"); - int B = mk.inport("\\B"); - int C = mk.inport("\\C"); - int D = mk.inport("\\D"); - int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D)); - mk.outport(Y, "\\Y"); - goto optimize; - } - - name.clear(); - return; - -optimize:; - pool used_old_ids; - vector new_nodes; - dict old_to_new_ids; - old_to_new_ids[-1] = -1; - - for (int i = GetSize(nodes)-1; i >= 0; i--) { - if (!nodes[i].outports.empty()) - used_old_ids.insert(i); - if (!used_old_ids.count(i)) - continue; - if (nodes[i].left_parent >= 0) - used_old_ids.insert(nodes[i].left_parent); - if (nodes[i].right_parent >= 0) - used_old_ids.insert(nodes[i].right_parent); - } - - for (int i = 0; i < GetSize(nodes); i++) { - if (!used_old_ids.count(i)) - continue; - nodes[i].left_parent = old_to_new_ids.at(nodes[i].left_parent); - nodes[i].right_parent = old_to_new_ids.at(nodes[i].right_parent); - old_to_new_ids[i] = GetSize(new_nodes); - new_nodes.push_back(nodes[i]); - } - - new_nodes.swap(nodes); -} - -YOSYS_NAMESPACE_END diff --git a/yosys/kernel/cellaigs.h b/yosys/kernel/cellaigs.h deleted file mode 100644 index 1417a614c..000000000 --- a/yosys/kernel/cellaigs.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef CELLAIGS_H -#define CELLAIGS_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -struct AigNode -{ - IdString portname; - int portbit; - bool inverter; - int left_parent, right_parent; - vector> outports; - - AigNode(); - bool operator==(const AigNode &other) const; - unsigned int hash() const; -}; - -struct Aig -{ - string name; - vector nodes; - Aig(Cell *cell); - - bool operator==(const Aig &other) const; - unsigned int hash() const; -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/celledges.cc b/yosys/kernel/celledges.cc deleted file mode 100644 index 556e8b826..000000000 --- a/yosys/kernel/celledges.cc +++ /dev/null @@ -1,209 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/celledges.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - IdString A = "\\A", Y = "\\Y"; - - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); - int a_width = GetSize(cell->getPort(A)); - int y_width = GetSize(cell->getPort(Y)); - - for (int i = 0; i < y_width; i++) - { - if (i < a_width) - db->add_edge(cell, A, i, Y, i, -1); - else if (is_signed && a_width > 0) - db->add_edge(cell, A, a_width-1, Y, i, -1); - } -} - -void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - IdString A = "\\A", B = "\\B", Y = "\\Y"; - - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); - int a_width = GetSize(cell->getPort(A)); - int b_width = GetSize(cell->getPort(B)); - int y_width = GetSize(cell->getPort(Y)); - - if (cell->type == "$and" && !is_signed) { - if (a_width > b_width) - a_width = b_width; - else - b_width = a_width; - } - - for (int i = 0; i < y_width; i++) - { - if (i < a_width) - db->add_edge(cell, A, i, Y, i, -1); - else if (is_signed && a_width > 0) - db->add_edge(cell, A, a_width-1, Y, i, -1); - - if (i < b_width) - db->add_edge(cell, B, i, Y, i, -1); - else if (is_signed && b_width > 0) - db->add_edge(cell, B, b_width-1, Y, i, -1); - } -} - -void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - IdString A = "\\A", Y = "\\Y"; - - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); - int a_width = GetSize(cell->getPort(A)); - int y_width = GetSize(cell->getPort(Y)); - - if (is_signed && a_width == 1) - y_width = std::min(y_width, 1); - - for (int i = 0; i < y_width; i++) - for (int k = 0; k <= i && k < a_width; k++) - db->add_edge(cell, A, k, Y, i, -1); -} - -void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - IdString A = "\\A", B = "\\B", Y = "\\Y"; - - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); - int a_width = GetSize(cell->getPort(A)); - int b_width = GetSize(cell->getPort(B)); - int y_width = GetSize(cell->getPort(Y)); - - if (!is_signed && cell->type != "$sub") { - int ab_width = std::max(a_width, b_width); - y_width = std::min(y_width, ab_width+1); - } - - for (int i = 0; i < y_width; i++) - { - for (int k = 0; k <= i; k++) - { - if (k < a_width) - db->add_edge(cell, A, k, Y, i, -1); - - if (k < b_width) - db->add_edge(cell, B, k, Y, i, -1); - } - } -} - -void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - IdString A = "\\A", Y = "\\Y"; - - int a_width = GetSize(cell->getPort(A)); - - for (int i = 0; i < a_width; i++) - db->add_edge(cell, A, i, Y, 0, -1); -} - -void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - IdString A = "\\A", B = "\\B", Y = "\\Y"; - - int a_width = GetSize(cell->getPort(A)); - int b_width = GetSize(cell->getPort(B)); - - for (int i = 0; i < a_width; i++) - db->add_edge(cell, A, i, Y, 0, -1); - - for (int i = 0; i < b_width; i++) - db->add_edge(cell, B, i, Y, 0, -1); -} - -void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y"; - - int a_width = GetSize(cell->getPort(A)); - int b_width = GetSize(cell->getPort(B)); - int s_width = GetSize(cell->getPort(S)); - - for (int i = 0; i < a_width; i++) - { - db->add_edge(cell, A, i, Y, i, -1); - - for (int k = i; k < b_width; k += a_width) - db->add_edge(cell, B, k, Y, i, -1); - - for (int k = 0; k < s_width; k++) - db->add_edge(cell, S, k, Y, i, -1); - } -} - -PRIVATE_NAMESPACE_END - -bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell) -{ - if (cell->type.in("$not", "$pos")) { - bitwise_unary_op(this, cell); - return true; - } - - if (cell->type.in("$and", "$or", "$xor", "$xnor")) { - bitwise_binary_op(this, cell); - return true; - } - - if (cell->type == "$neg") { - arith_neg_op(this, cell); - return true; - } - - if (cell->type.in("$add", "$sub")) { - arith_binary_op(this, cell); - return true; - } - - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$logic_not")) { - reduce_op(this, cell); - return true; - } - - // FIXME: - // if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) { - // shift_op(this, cell); - // return true; - // } - - if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) { - compare_op(this, cell); - return true; - } - - if (cell->type.in("$mux", "$pmux")) { - mux_op(this, cell); - return true; - } - - // FIXME: $mul $div $mod $slice $concat - // FIXME: $lut $sop $alu $lcu $macc $fa - - return false; -} - diff --git a/yosys/kernel/celledges.h b/yosys/kernel/celledges.h deleted file mode 100644 index 2cc297cb2..000000000 --- a/yosys/kernel/celledges.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef CELLEDGES_H -#define CELLEDGES_H - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -YOSYS_NAMESPACE_BEGIN - -struct AbstractCellEdgesDatabase -{ - virtual ~AbstractCellEdgesDatabase() { } - virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int delay) = 0; - bool add_edges_from_cell(RTLIL::Cell *cell); -}; - -struct FwdCellEdgesDatabase : AbstractCellEdgesDatabase -{ - SigMap &sigmap; - dict> db; - FwdCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { } - - void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) YS_OVERRIDE { - SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]); - SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]); - db[from_sigbit].insert(to_sigbit); - } -}; - -struct RevCellEdgesDatabase : AbstractCellEdgesDatabase -{ - SigMap &sigmap; - dict> db; - RevCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { } - - void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) YS_OVERRIDE { - SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]); - SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]); - db[to_sigbit].insert(from_sigbit); - } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/celltypes.h b/yosys/kernel/celltypes.h deleted file mode 100644 index 4e91eddda..000000000 --- a/yosys/kernel/celltypes.h +++ /dev/null @@ -1,485 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef CELLTYPES_H -#define CELLTYPES_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -struct CellType -{ - RTLIL::IdString type; - pool inputs, outputs; - bool is_evaluable; -}; - -struct CellTypes -{ - dict cell_types; - - CellTypes() - { - } - - CellTypes(RTLIL::Design *design) - { - setup(design); - } - - void setup(RTLIL::Design *design = NULL) - { - if (design) - setup_design(design); - - setup_internals(); - setup_internals_mem(); - setup_stdcells(); - setup_stdcells_mem(); - } - - void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false) - { - CellType ct = {type, inputs, outputs, is_evaluable}; - cell_types[ct.type] = ct; - } - - void setup_module(RTLIL::Module *module) - { - pool inputs, outputs; - for (RTLIL::IdString wire_name : module->ports) { - RTLIL::Wire *wire = module->wire(wire_name); - if (wire->port_input) - inputs.insert(wire->name); - if (wire->port_output) - outputs.insert(wire->name); - } - setup_type(module->name, inputs, outputs); - } - - void setup_design(RTLIL::Design *design) - { - for (auto module : design->modules()) - setup_module(module); - } - - void setup_internals() - { - setup_internals_eval(); - - IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y"; - IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT"; - IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST"; - - setup_type("$tribuf", {A, EN}, {Y}, true); - - setup_type("$assert", {A, EN}, pool(), true); - setup_type("$assume", {A, EN}, pool(), true); - setup_type("$live", {A, EN}, pool(), true); - setup_type("$fair", {A, EN}, pool(), true); - setup_type("$cover", {A, EN}, pool(), true); - setup_type("$initstate", pool(), {Y}, true); - setup_type("$anyconst", pool(), {Y}, true); - setup_type("$anyseq", pool(), {Y}, true); - setup_type("$allconst", pool(), {Y}, true); - setup_type("$allseq", pool(), {Y}, true); - setup_type("$equiv", {A, B}, {Y}, true); - setup_type("$specify2", {EN, SRC, DST}, pool(), true); - setup_type("$specify3", {EN, SRC, DST, DAT}, pool(), true); - setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool(), true); - } - - void setup_internals_eval() - { - std::vector unary_ops = { - "$not", "$pos", "$neg", - "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", - "$logic_not", "$slice", "$lut", "$sop" - }; - - std::vector binary_ops = { - "$and", "$or", "$xor", "$xnor", - "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", - "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt", - "$add", "$sub", "$mul", "$div", "$mod", "$pow", - "$logic_and", "$logic_or", "$concat", "$macc" - }; - IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y"; - IdString P = "\\P", G = "\\G", C = "\\C", X = "\\X"; - IdString BI = "\\BI", CI = "\\CI", CO = "\\CO", EN = "\\EN"; - - for (auto type : unary_ops) - setup_type(type, {A}, {Y}, true); - - for (auto type : binary_ops) - setup_type(type, {A, B}, {Y}, true); - - for (auto type : std::vector({"$mux", "$pmux"})) - setup_type(type, {A, B, S}, {Y}, true); - - setup_type("$lcu", {P, G, CI}, {CO}, true); - setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true); - setup_type("$fa", {A, B, C}, {X, Y}, true); - } - - void setup_internals_mem() - { - IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN"; - IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA", RD_EN = "\\RD_EN"; - IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN"; - IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA"; - IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT"; - - setup_type("$sr", {SET, CLR}, {Q}); - setup_type("$ff", {D}, {Q}); - setup_type("$dff", {CLK, D}, {Q}); - setup_type("$dffe", {CLK, EN, D}, {Q}); - setup_type("$dffsr", {CLK, SET, CLR, D}, {Q}); - setup_type("$adff", {CLK, ARST, D}, {Q}); - setup_type("$dlatch", {EN, D}, {Q}); - setup_type("$dlatchsr", {EN, SET, CLR, D}, {Q}); - - setup_type("$memrd", {CLK, EN, ADDR}, {DATA}); - setup_type("$memwr", {CLK, EN, ADDR, DATA}, pool()); - setup_type("$meminit", {ADDR, DATA}, pool()); - setup_type("$mem", {RD_CLK, RD_EN, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA}); - - setup_type("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT}); - } - - void setup_stdcells() - { - setup_stdcells_eval(); - - IdString A = "\\A", E = "\\E", Y = "\\Y"; - - setup_type("$_TBUF_", {A, E}, {Y}, true); - } - - void setup_stdcells_eval() - { - IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D"; - IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H"; - IdString I = "\\I", J = "\\J", K = "\\K", L = "\\L"; - IdString M = "\\M", N = "\\N", O = "\\O", P = "\\P"; - IdString S = "\\S", T = "\\T", U = "\\U", V = "\\V"; - IdString Y = "\\Y"; - - setup_type("$_BUF_", {A}, {Y}, true); - setup_type("$_NOT_", {A}, {Y}, true); - setup_type("$_AND_", {A, B}, {Y}, true); - setup_type("$_NAND_", {A, B}, {Y}, true); - setup_type("$_OR_", {A, B}, {Y}, true); - setup_type("$_NOR_", {A, B}, {Y}, true); - setup_type("$_XOR_", {A, B}, {Y}, true); - setup_type("$_XNOR_", {A, B}, {Y}, true); - setup_type("$_ANDNOT_", {A, B}, {Y}, true); - setup_type("$_ORNOT_", {A, B}, {Y}, true); - setup_type("$_MUX_", {A, B, S}, {Y}, true); - setup_type("$_MUX4_", {A, B, C, D, S, T}, {Y}, true); - setup_type("$_MUX8_", {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true); - setup_type("$_MUX16_", {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V}, {Y}, true); - setup_type("$_AOI3_", {A, B, C}, {Y}, true); - setup_type("$_OAI3_", {A, B, C}, {Y}, true); - setup_type("$_AOI4_", {A, B, C, D}, {Y}, true); - setup_type("$_OAI4_", {A, B, C, D}, {Y}, true); - } - - void setup_stdcells_mem() - { - IdString S = "\\S", R = "\\R", C = "\\C"; - IdString D = "\\D", Q = "\\Q", E = "\\E"; - - std::vector list_np = {'N', 'P'}, list_01 = {'0', '1'}; - - for (auto c1 : list_np) - for (auto c2 : list_np) - setup_type(stringf("$_SR_%c%c_", c1, c2), {S, R}, {Q}); - - setup_type("$_FF_", {D}, {Q}); - - for (auto c1 : list_np) - setup_type(stringf("$_DFF_%c_", c1), {C, D}, {Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - setup_type(stringf("$_DFFE_%c%c_", c1, c2), {C, D, E}, {Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_01) - setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {C, R, D}, {Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_np) - setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {C, S, R, D}, {Q}); - - for (auto c1 : list_np) - setup_type(stringf("$_DLATCH_%c_", c1), {E, D}, {Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_np) - setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {E, S, R, D}, {Q}); - } - - void clear() - { - cell_types.clear(); - } - - bool cell_known(RTLIL::IdString type) - { - return cell_types.count(type) != 0; - } - - bool cell_output(RTLIL::IdString type, RTLIL::IdString port) - { - auto it = cell_types.find(type); - return it != cell_types.end() && it->second.outputs.count(port) != 0; - } - - bool cell_input(RTLIL::IdString type, RTLIL::IdString port) - { - auto it = cell_types.find(type); - return it != cell_types.end() && it->second.inputs.count(port) != 0; - } - - bool cell_evaluable(RTLIL::IdString type) - { - auto it = cell_types.find(type); - return it != cell_types.end() && it->second.is_evaluable; - } - - static RTLIL::Const eval_not(RTLIL::Const v) - { - for (auto &bit : v.bits) - if (bit == RTLIL::S0) bit = RTLIL::S1; - else if (bit == RTLIL::S1) bit = RTLIL::S0; - return v; - } - - static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr) - { - if (type == "$sshr" && !signed1) - type = "$shr"; - if (type == "$sshl" && !signed1) - type = "$shl"; - - if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" && type != "$shift" && type != "$shiftx" && - type != "$pos" && type != "$neg" && type != "$not") { - if (!signed1 || !signed2) - signed1 = false, signed2 = false; - } - -#define HANDLE_CELL_TYPE(_t) if (type == "$" #_t) return const_ ## _t(arg1, arg2, signed1, signed2, result_len); - HANDLE_CELL_TYPE(not) - HANDLE_CELL_TYPE(and) - HANDLE_CELL_TYPE(or) - HANDLE_CELL_TYPE(xor) - HANDLE_CELL_TYPE(xnor) - HANDLE_CELL_TYPE(reduce_and) - HANDLE_CELL_TYPE(reduce_or) - HANDLE_CELL_TYPE(reduce_xor) - HANDLE_CELL_TYPE(reduce_xnor) - HANDLE_CELL_TYPE(reduce_bool) - HANDLE_CELL_TYPE(logic_not) - HANDLE_CELL_TYPE(logic_and) - HANDLE_CELL_TYPE(logic_or) - HANDLE_CELL_TYPE(shl) - HANDLE_CELL_TYPE(shr) - HANDLE_CELL_TYPE(sshl) - HANDLE_CELL_TYPE(sshr) - HANDLE_CELL_TYPE(shift) - HANDLE_CELL_TYPE(shiftx) - HANDLE_CELL_TYPE(lt) - HANDLE_CELL_TYPE(le) - HANDLE_CELL_TYPE(eq) - HANDLE_CELL_TYPE(ne) - HANDLE_CELL_TYPE(eqx) - HANDLE_CELL_TYPE(nex) - HANDLE_CELL_TYPE(ge) - HANDLE_CELL_TYPE(gt) - HANDLE_CELL_TYPE(add) - HANDLE_CELL_TYPE(sub) - HANDLE_CELL_TYPE(mul) - HANDLE_CELL_TYPE(div) - HANDLE_CELL_TYPE(mod) - HANDLE_CELL_TYPE(pow) - HANDLE_CELL_TYPE(pos) - HANDLE_CELL_TYPE(neg) -#undef HANDLE_CELL_TYPE - - if (type == "$_BUF_") - return arg1; - if (type == "$_NOT_") - return eval_not(arg1); - if (type == "$_AND_") - return const_and(arg1, arg2, false, false, 1); - if (type == "$_NAND_") - return eval_not(const_and(arg1, arg2, false, false, 1)); - if (type == "$_OR_") - return const_or(arg1, arg2, false, false, 1); - if (type == "$_NOR_") - return eval_not(const_or(arg1, arg2, false, false, 1)); - if (type == "$_XOR_") - return const_xor(arg1, arg2, false, false, 1); - if (type == "$_XNOR_") - return const_xnor(arg1, arg2, false, false, 1); - if (type == "$_ANDNOT_") - return const_and(arg1, eval_not(arg2), false, false, 1); - if (type == "$_ORNOT_") - return const_or(arg1, eval_not(arg2), false, false, 1); - - if (errp != nullptr) { - *errp = true; - return State::Sm; - } - - log_abort(); - } - - static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr) - { - if (cell->type == "$slice") { - RTLIL::Const ret; - int width = cell->parameters.at("\\Y_WIDTH").as_int(); - int offset = cell->parameters.at("\\OFFSET").as_int(); - ret.bits.insert(ret.bits.end(), arg1.bits.begin()+offset, arg1.bits.begin()+offset+width); - return ret; - } - - if (cell->type == "$concat") { - RTLIL::Const ret = arg1; - ret.bits.insert(ret.bits.end(), arg2.bits.begin(), arg2.bits.end()); - return ret; - } - - if (cell->type == "$lut") - { - int width = cell->parameters.at("\\WIDTH").as_int(); - - std::vector t = cell->parameters.at("\\LUT").bits; - while (GetSize(t) < (1 << width)) - t.push_back(RTLIL::S0); - t.resize(1 << width); - - for (int i = width-1; i >= 0; i--) { - RTLIL::State sel = arg1.bits.at(i); - std::vector new_t; - if (sel == RTLIL::S0) - new_t = std::vector(t.begin(), t.begin() + GetSize(t)/2); - else if (sel == RTLIL::S1) - new_t = std::vector(t.begin() + GetSize(t)/2, t.end()); - else - for (int j = 0; j < GetSize(t)/2; j++) - new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx); - t.swap(new_t); - } - - log_assert(GetSize(t) == 1); - return t; - } - - if (cell->type == "$sop") - { - int width = cell->parameters.at("\\WIDTH").as_int(); - int depth = cell->parameters.at("\\DEPTH").as_int(); - std::vector t = cell->parameters.at("\\TABLE").bits; - - while (GetSize(t) < width*depth*2) - t.push_back(RTLIL::S0); - - RTLIL::State default_ret = State::S0; - - for (int i = 0; i < depth; i++) - { - bool match = true; - bool match_x = true; - - for (int j = 0; j < width; j++) { - RTLIL::State a = arg1.bits.at(j); - if (t.at(2*width*i + 2*j + 0) == State::S1) { - if (a == State::S1) match_x = false; - if (a != State::S0) match = false; - } - if (t.at(2*width*i + 2*j + 1) == State::S1) { - if (a == State::S0) match_x = false; - if (a != State::S1) match = false; - } - } - - if (match) - return State::S1; - - if (match_x) - default_ret = State::Sx; - } - - return default_ret; - } - - bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool(); - bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool(); - int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1; - return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp); - } - - static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr) - { - if (cell->type.in("$mux", "$pmux", "$_MUX_")) { - RTLIL::Const ret = arg1; - for (size_t i = 0; i < arg3.bits.size(); i++) - if (arg3.bits[i] == RTLIL::State::S1) { - std::vector bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size()); - ret = RTLIL::Const(bits); - } - return ret; - } - - if (cell->type == "$_AOI3_") - return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1)); - if (cell->type == "$_OAI3_") - return eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1)); - - log_assert(arg3.bits.size() == 0); - return eval(cell, arg1, arg2, errp); - } - - static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr) - { - if (cell->type == "$_AOI4_") - return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); - if (cell->type == "$_OAI4_") - return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1)); - - log_assert(arg4.bits.size() == 0); - return eval(cell, arg1, arg2, arg3, errp); - } -}; - -// initialized by yosys_setup() -extern CellTypes yosys_celltypes; - -YOSYS_NAMESPACE_END - -#endif - diff --git a/yosys/kernel/consteval.h b/yosys/kernel/consteval.h deleted file mode 100644 index 154373a8d..000000000 --- a/yosys/kernel/consteval.h +++ /dev/null @@ -1,395 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef CONSTEVAL_H -#define CONSTEVAL_H - -#include "kernel/rtlil.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/macc.h" - -YOSYS_NAMESPACE_BEGIN - -struct ConstEval -{ - RTLIL::Module *module; - SigMap assign_map; - SigMap values_map; - SigPool stop_signals; - SigSet sig2driver; - std::set busy; - std::vector stack; - RTLIL::State defaultval; - - ConstEval(RTLIL::Module *module, RTLIL::State defaultval = RTLIL::State::Sm) : module(module), assign_map(module), defaultval(defaultval) - { - CellTypes ct; - ct.setup_internals(); - ct.setup_stdcells(); - - for (auto &it : module->cells_) { - if (!ct.cell_known(it.second->type)) - continue; - for (auto &it2 : it.second->connections()) - if (ct.cell_output(it.second->type, it2.first)) - sig2driver.insert(assign_map(it2.second), it.second); - } - } - - void clear() - { - values_map.clear(); - stop_signals.clear(); - } - - void push() - { - stack.push_back(values_map); - } - - void pop() - { - values_map.swap(stack.back()); - stack.pop_back(); - } - - void set(RTLIL::SigSpec sig, RTLIL::Const value) - { - assign_map.apply(sig); -#ifndef NDEBUG - RTLIL::SigSpec current_val = values_map(sig); - for (int i = 0; i < GetSize(current_val); i++) - log_assert(current_val[i].wire != NULL || current_val[i] == value.bits[i]); -#endif - values_map.add(sig, RTLIL::SigSpec(value)); - } - - void stop(RTLIL::SigSpec sig) - { - assign_map.apply(sig); - stop_signals.add(sig); - } - - bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef) - { - if (cell->type == "$lcu") - { - RTLIL::SigSpec sig_p = cell->getPort("\\P"); - RTLIL::SigSpec sig_g = cell->getPort("\\G"); - RTLIL::SigSpec sig_ci = cell->getPort("\\CI"); - RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort("\\CO"))); - - if (sig_co.is_fully_const()) - return true; - - if (!eval(sig_p, undef, cell)) - return false; - - if (!eval(sig_g, undef, cell)) - return false; - - if (!eval(sig_ci, undef, cell)) - return false; - - if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def()) - { - RTLIL::Const coval(RTLIL::Sx, GetSize(sig_co)); - bool carry = sig_ci.as_bool(); - - for (int i = 0; i < GetSize(coval); i++) { - carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry); - coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0; - } - - set(sig_co, coval); - } - else - set(sig_co, RTLIL::Const(RTLIL::Sx, GetSize(sig_co))); - - return true; - } - - RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y; - - log_assert(cell->hasPort("\\Y")); - sig_y = values_map(assign_map(cell->getPort("\\Y"))); - if (sig_y.is_fully_const()) - return true; - - if (cell->hasPort("\\S")) { - sig_s = cell->getPort("\\S"); - if (!eval(sig_s, undef, cell)) - return false; - } - - if (cell->hasPort("\\A")) - sig_a = cell->getPort("\\A"); - - if (cell->hasPort("\\B")) - sig_b = cell->getPort("\\B"); - - if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") - { - std::vector y_candidates; - int count_maybe_set_s_bits = 0; - int count_set_s_bits = 0; - - for (int i = 0; i < sig_s.size(); i++) - { - RTLIL::State s_bit = sig_s.extract(i, 1).as_const().bits.at(0); - RTLIL::SigSpec b_slice = sig_b.extract(sig_y.size()*i, sig_y.size()); - - if (s_bit == RTLIL::State::Sx || s_bit == RTLIL::State::S1) - y_candidates.push_back(b_slice); - - if (s_bit == RTLIL::State::S1 || s_bit == RTLIL::State::Sx) - count_maybe_set_s_bits++; - - if (s_bit == RTLIL::State::S1) - count_set_s_bits++; - } - - if (count_set_s_bits == 0) - y_candidates.push_back(sig_a); - - std::vector y_values; - - log_assert(y_candidates.size() > 0); - for (auto &yc : y_candidates) { - if (!eval(yc, undef, cell)) - return false; - y_values.push_back(yc.as_const()); - } - - if (y_values.size() > 1) - { - std::vector master_bits = y_values.at(0).bits; - - for (size_t i = 1; i < y_values.size(); i++) { - std::vector &slave_bits = y_values.at(i).bits; - log_assert(master_bits.size() == slave_bits.size()); - for (size_t j = 0; j < master_bits.size(); j++) - if (master_bits[j] != slave_bits[j]) - master_bits[j] = RTLIL::State::Sx; - } - - set(sig_y, RTLIL::Const(master_bits)); - } - else - set(sig_y, y_values.front()); - } - else if (cell->type == "$fa") - { - RTLIL::SigSpec sig_c = cell->getPort("\\C"); - RTLIL::SigSpec sig_x = cell->getPort("\\X"); - int width = GetSize(sig_c); - - if (!eval(sig_a, undef, cell)) - return false; - - if (!eval(sig_b, undef, cell)) - return false; - - if (!eval(sig_c, undef, cell)) - return false; - - RTLIL::Const t1 = const_xor(sig_a.as_const(), sig_b.as_const(), false, false, width); - RTLIL::Const val_y = const_xor(t1, sig_c.as_const(), false, false, width); - - RTLIL::Const t2 = const_and(sig_a.as_const(), sig_b.as_const(), false, false, width); - RTLIL::Const t3 = const_and(sig_c.as_const(), t1, false, false, width); - RTLIL::Const val_x = const_or(t2, t3, false, false, width); - - for (int i = 0; i < GetSize(val_y); i++) - if (val_y.bits[i] == RTLIL::Sx) - val_x.bits[i] = RTLIL::Sx; - - set(sig_y, val_y); - set(sig_x, val_x); - } - else if (cell->type == "$alu") - { - bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool(); - bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool(); - - RTLIL::SigSpec sig_ci = cell->getPort("\\CI"); - RTLIL::SigSpec sig_bi = cell->getPort("\\BI"); - - if (!eval(sig_a, undef, cell)) - return false; - - if (!eval(sig_b, undef, cell)) - return false; - - if (!eval(sig_ci, undef, cell)) - return false; - - if (!eval(sig_bi, undef, cell)) - return false; - - RTLIL::SigSpec sig_x = cell->getPort("\\X"); - RTLIL::SigSpec sig_co = cell->getPort("\\CO"); - - bool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def()); - sig_a.extend_u0(GetSize(sig_y), signed_a); - sig_b.extend_u0(GetSize(sig_y), signed_b); - - bool carry = sig_ci[0] == RTLIL::S1; - bool b_inv = sig_bi[0] == RTLIL::S1; - - for (int i = 0; i < GetSize(sig_y); i++) - { - RTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] }; - - if (!x_inputs.is_fully_def()) { - set(sig_x[i], RTLIL::Sx); - } else { - bool bit_a = sig_a[i] == RTLIL::S1; - bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv; - bool bit_x = bit_a != bit_b; - set(sig_x[i], bit_x ? RTLIL::S1 : RTLIL::S0); - } - - if (any_input_undef) { - set(sig_y[i], RTLIL::Sx); - set(sig_co[i], RTLIL::Sx); - } else { - bool bit_a = sig_a[i] == RTLIL::S1; - bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv; - bool bit_y = (bit_a != bit_b) != carry; - carry = (bit_a && bit_b) || (bit_a && carry) || (bit_b && carry); - set(sig_y[i], bit_y ? RTLIL::S1 : RTLIL::S0); - set(sig_co[i], carry ? RTLIL::S1 : RTLIL::S0); - } - } - } - else if (cell->type == "$macc") - { - 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; - if (!eval(port.in_b, undef, cell)) - return false; - } - - RTLIL::Const result(0, GetSize(cell->getPort("\\Y"))); - if (!macc.eval(result)) - log_abort(); - - set(cell->getPort("\\Y"), result); - } - else - { - RTLIL::SigSpec sig_c, sig_d; - - if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) { - if (cell->hasPort("\\C")) - sig_c = cell->getPort("\\C"); - if (cell->hasPort("\\D")) - sig_d = cell->getPort("\\D"); - } - - if (sig_a.size() > 0 && !eval(sig_a, undef, cell)) - return false; - if (sig_b.size() > 0 && !eval(sig_b, undef, cell)) - return false; - if (sig_c.size() > 0 && !eval(sig_c, undef, cell)) - return false; - if (sig_d.size() > 0 && !eval(sig_d, undef, cell)) - return false; - - bool eval_err = false; - RTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err); - - if (eval_err) - return false; - - set(sig_y, eval_ret); - } - - return true; - } - - bool eval(RTLIL::SigSpec &sig, RTLIL::SigSpec &undef, RTLIL::Cell *busy_cell = NULL) - { - assign_map.apply(sig); - values_map.apply(sig); - - if (sig.is_fully_const()) - return true; - - if (stop_signals.check_any(sig)) { - undef = stop_signals.extract(sig); - return false; - } - - if (busy_cell) { - if (busy.count(busy_cell) > 0) { - undef = sig; - return false; - } - busy.insert(busy_cell); - } - - std::set driver_cells; - sig2driver.find(sig, driver_cells); - for (auto cell : driver_cells) { - if (!eval(cell, undef)) { - if (busy_cell) - busy.erase(busy_cell); - return false; - } - } - - if (busy_cell) - busy.erase(busy_cell); - - values_map.apply(sig); - if (sig.is_fully_const()) - return true; - - if (defaultval != RTLIL::State::Sm) { - for (auto &bit : sig) - if (bit.wire) bit = defaultval; - return true; - } - - for (auto &c : sig.chunks()) - if (c.wire != NULL) - undef.append(c); - return false; - } - - bool eval(RTLIL::SigSpec &sig) - { - RTLIL::SigSpec undef; - return eval(sig, undef); - } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/cost.h b/yosys/kernel/cost.h deleted file mode 100644 index 41a09eb63..000000000 --- a/yosys/kernel/cost.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef COST_H -#define COST_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -int get_cell_cost(RTLIL::Cell *cell, dict *mod_cost_cache = nullptr); - -inline int get_cell_cost(RTLIL::IdString type, const dict ¶meters = dict(), - RTLIL::Design *design = nullptr, dict *mod_cost_cache = nullptr) -{ - static dict gate_cost = { - { "$_BUF_", 1 }, - { "$_NOT_", 2 }, - { "$_AND_", 4 }, - { "$_NAND_", 4 }, - { "$_OR_", 4 }, - { "$_NOR_", 4 }, - { "$_ANDNOT_", 4 }, - { "$_ORNOT_", 4 }, - { "$_XOR_", 8 }, - { "$_XNOR_", 8 }, - { "$_AOI3_", 6 }, - { "$_OAI3_", 6 }, - { "$_AOI4_", 8 }, - { "$_OAI4_", 8 }, - { "$_MUX_", 4 } - }; - - if (gate_cost.count(type)) - return gate_cost.at(type); - - if (parameters.empty() && design && design->module(type)) - { - RTLIL::Module *mod = design->module(type); - - if (mod->attributes.count("\\cost")) - return mod->attributes.at("\\cost").as_int(); - - dict local_mod_cost_cache; - if (mod_cost_cache == nullptr) - mod_cost_cache = &local_mod_cost_cache; - - if (mod_cost_cache->count(mod->name)) - return mod_cost_cache->at(mod->name); - - int module_cost = 1; - for (auto c : mod->cells()) - module_cost += get_cell_cost(c, mod_cost_cache); - - (*mod_cost_cache)[mod->name] = module_cost; - return module_cost; - } - - log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters)); - return 1; -} - -inline int get_cell_cost(RTLIL::Cell *cell, dict *mod_cost_cache) -{ - return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache); -} - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/driver.cc b/yosys/kernel/driver.cc deleted file mode 100644 index f273057dd..000000000 --- a/yosys/kernel/driver.cc +++ /dev/null @@ -1,676 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "libs/sha1/sha1.h" - -#ifdef YOSYS_ENABLE_READLINE -# include -# include -#endif - -#ifdef YOSYS_ENABLE_EDITLINE -# include -#endif - -#include -#include -#include -#include - -#if defined (__linux__) || defined(__FreeBSD__) -# include -# include -# include -#endif - -#ifdef __FreeBSD__ -# include -# include -#endif - -#if !defined(_WIN32) || defined(__MINGW32__) -# include -#else -char *optarg; -int optind = 1, optcur = 1; -int getopt(int argc, char **argv, const char *optstring) -{ - if (optind >= argc || argv[optind][0] != '-') - return -1; - - bool takes_arg = false; - int opt = argv[optind][optcur]; - for (int i = 0; optstring[i]; i++) - if (opt == optstring[i] && optstring[i + 1] == ':') - takes_arg = true; - - if (!takes_arg) { - if (argv[optind][++optcur] == 0) - optind++, optcur = 1; - return opt; - } - - if (argv[optind][++optcur]) { - optarg = argv[optind++] + optcur; - optcur = 1; - return opt; - } - - optarg = argv[++optind]; - optind++, optcur = 1; - return opt; -} -#endif - - -USING_YOSYS_NAMESPACE - -#ifdef EMSCRIPTEN -# include -# include -# include - -extern "C" int main(int, char**); -extern "C" void run(const char*); -extern "C" const char *errmsg(); -extern "C" const char *prompt(); - -int main(int argc, char **argv) -{ - EM_ASM( - if (ENVIRONMENT_IS_NODE) - { - FS.mkdir('/hostcwd'); - FS.mount(NODEFS, { root: '.' }, '/hostcwd'); - FS.mkdir('/hostfs'); - FS.mount(NODEFS, { root: '/' }, '/hostfs'); - } - ); - - mkdir("/work", 0777); - chdir("/work"); - log_files.push_back(stdout); - log_error_stderr = true; - yosys_banner(); - yosys_setup(); -#ifdef WITH_PYTHON - PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); - PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); -#endif - - if (argc == 2) - { - // Run the first argument as a script file - run_frontend(argv[1], "script", 0, 0, 0); - } -} - -void run(const char *command) -{ - int selSize = GetSize(yosys_get_design()->selection_stack); - try { - log_last_error = "Internal error (see JavaScript console for details)"; - run_pass(command); - log_last_error = ""; - } catch (...) { - while (GetSize(yosys_get_design()->selection_stack) > selSize) - yosys_get_design()->selection_stack.pop_back(); - throw; - } -} - -const char *errmsg() -{ - return log_last_error.c_str(); -} - -const char *prompt() -{ - const char *p = create_prompt(yosys_get_design(), 0); - while (*p == '\n') p++; - return p; -} - -#else /* EMSCRIPTEN */ - -#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) -int yosys_history_offset = 0; -std::string yosys_history_file; -#endif - -void yosys_atexit() -{ -#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) - if (!yosys_history_file.empty()) { -#if defined(YOSYS_ENABLE_READLINE) - if (yosys_history_offset > 0) { - history_truncate_file(yosys_history_file.c_str(), 100); - append_history(where_history() - yosys_history_offset, yosys_history_file.c_str()); - } else - write_history(yosys_history_file.c_str()); -#else - write_history(yosys_history_file.c_str()); -#endif - } - - clear_history(); -#if defined(YOSYS_ENABLE_READLINE) - HIST_ENTRY **hist_list = history_list(); - if (hist_list != NULL) - free(hist_list); -#endif -#endif -} - -int main(int argc, char **argv) -{ - std::string frontend_command = "auto"; - std::string backend_command = "auto"; - std::vector vlog_defines; - std::vector passes_commands; - std::vector plugin_filenames; - std::string output_filename = ""; - std::string scriptfile = ""; - std::string depsfile = ""; - bool scriptfile_tcl = false; - bool got_output_filename = false; - bool print_banner = true; - bool print_stats = true; - bool call_abort = false; - bool timing_details = false; - bool mode_v = false; - bool mode_q = false; - -#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) - if (getenv("HOME") != NULL) { - yosys_history_file = stringf("%s/.yosys_history", getenv("HOME")); - read_history(yosys_history_file.c_str()); - yosys_history_offset = where_history(); - } -#endif - - if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help"))) - { - printf("\n"); - printf("Usage: %s [options] [ [..]]\n", argv[0]); - printf("\n"); - printf(" -Q\n"); - printf(" suppress printing of banner (copyright, disclaimer, version)\n"); - printf("\n"); - printf(" -T\n"); - printf(" suppress printing of footer (log hash, version, timing statistics)\n"); - printf("\n"); - printf(" -q\n"); - printf(" quiet operation. only write warnings and error messages to console\n"); - printf(" use this option twice to also quiet warning messages\n"); - printf("\n"); - printf(" -v \n"); - printf(" print log headers up to level to the console. (this\n"); - printf(" implies -q for everything except the 'End of script.' message.)\n"); - printf("\n"); - printf(" -t\n"); - printf(" annotate all log messages with a time stamp\n"); - printf("\n"); - printf(" -d\n"); - printf(" print more detailed timing stats at exit\n"); - printf("\n"); - printf(" -l logfile\n"); - printf(" write log messages to the specified file\n"); - printf("\n"); - printf(" -L logfile\n"); - printf(" like -l but open log file in line buffered mode\n"); - printf("\n"); - printf(" -o outfile\n"); - printf(" write the design to the specified file on exit\n"); - printf("\n"); - printf(" -b backend\n"); - printf(" use this backend for the output file specified on the command line\n"); - printf("\n"); - printf(" -f frontend\n"); - printf(" use the specified frontend for the input files on the command line\n"); - printf("\n"); - printf(" -H\n"); - printf(" print the command list\n"); - printf("\n"); - printf(" -h command\n"); - printf(" print the help message for the specified command\n"); - printf("\n"); - printf(" -s scriptfile\n"); - printf(" execute the commands in the script file\n"); - printf("\n"); - printf(" -c tcl_scriptfile\n"); - printf(" execute the commands in the tcl script file (see 'help tcl' for details)\n"); - printf("\n"); - printf(" -p command\n"); - printf(" execute the commands\n"); - printf("\n"); - printf(" -m module_file\n"); - printf(" load the specified module (aka plugin)\n"); - printf("\n"); - printf(" -X\n"); - printf(" enable tracing of core data structure changes. for debugging\n"); - printf("\n"); - printf(" -M\n"); - printf(" will slightly randomize allocated pointer addresses. for debugging\n"); - printf("\n"); - printf(" -A\n"); - printf(" will call abort() at the end of the script. for debugging\n"); - printf("\n"); - printf(" -D [=]\n"); - printf(" set the specified Verilog define (via \"read -define\")\n"); - printf("\n"); - printf(" -P [:]\n"); - printf(" dump the design when printing the specified log header to a file.\n"); - printf(" yosys_dump_.il is used as filename if none is specified.\n"); - printf(" Use 'ALL' as to dump at every header.\n"); - printf("\n"); - printf(" -W regex\n"); - printf(" print a warning for all log messages matching the regex.\n"); - printf("\n"); - printf(" -w regex\n"); - printf(" if a warning message matches the regex, it is printed as regular\n"); - printf(" message instead.\n"); - printf("\n"); - printf(" -e regex\n"); - printf(" if a warning message matches the regex, it is printed as error\n"); - printf(" message instead and the tool terminates with a nonzero return code.\n"); - printf("\n"); - printf(" -E \n"); - printf(" write a Makefile dependencies file with in- and output file names\n"); - printf("\n"); - printf(" -g\n"); - printf(" globally enable debug log messages\n"); - printf("\n"); - printf(" -V\n"); - printf(" print version information and exit\n"); - printf("\n"); - printf("The option -S is an shortcut for calling the \"synth\" command, a default\n"); - printf("script for transforming the Verilog input to a gate-level netlist. For example:\n"); - printf("\n"); - printf(" yosys -o output.blif -S input.v\n"); - printf("\n"); - printf("For more complex synthesis jobs it is recommended to use the read_* and write_*\n"); - printf("commands in a script file instead of specifying input and output files on the\n"); - printf("command line.\n"); - printf("\n"); - printf("When no commands, script files or input files are specified on the command\n"); - printf("line, yosys automatically enters the interactive command mode. Use the 'help'\n"); - printf("command to get information on the individual commands.\n"); - printf("\n"); - exit(0); - } - - int opt; - while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) - { - switch (opt) - { - case 'M': - memhasher_on(); - break; - case 'X': - yosys_xtrace++; - break; - case 'A': - call_abort = true; - break; - case 'Q': - print_banner = false; - break; - case 'T': - print_stats = false; - break; - case 'V': - printf("%s\n", yosys_version_str); - exit(0); - case 'S': - passes_commands.push_back("synth"); - break; - case 'g': - log_force_debug++; - break; - case 'm': - plugin_filenames.push_back(optarg); - break; - case 'f': - frontend_command = optarg; - break; - case 'H': - passes_commands.push_back("help"); - break; - case 'h': - passes_commands.push_back(stringf("help %s", optarg)); - break; - case 'b': - backend_command = optarg; - break; - case 'p': - passes_commands.push_back(optarg); - break; - case 'o': - output_filename = optarg; - got_output_filename = true; - break; - case 'l': - case 'L': - log_files.push_back(fopen(optarg, "wt")); - if (log_files.back() == NULL) { - fprintf(stderr, "Can't open log file `%s' for writing!\n", optarg); - exit(1); - } - if (opt == 'L') - setvbuf(log_files.back(), NULL, _IOLBF, 0); - break; - case 'q': - mode_q = true; - if (log_errfile == stderr) - log_quiet_warnings = true; - log_errfile = stderr; - break; - case 'v': - mode_v = true; - log_errfile = stderr; - log_verbose_level = atoi(optarg); - break; - case 't': - log_time = true; - break; - case 'd': - timing_details = true; - break; - case 's': - scriptfile = optarg; - scriptfile_tcl = false; - break; - case 'c': - scriptfile = optarg; - scriptfile_tcl = true; - break; - case 'W': - log_warn_regexes.push_back(std::regex(optarg, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); - break; - case 'w': - log_nowarn_regexes.push_back(std::regex(optarg, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); - break; - case 'e': - log_werror_regexes.push_back(std::regex(optarg, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); - break; - case 'D': - vlog_defines.push_back(optarg); - break; - case 'P': - { - auto args = split_tokens(optarg, ":"); - if (!args.empty() && args[0] == "ALL") { - if (GetSize(args) != 1) { - fprintf(stderr, "Invalid number of tokens in -D ALL.\n"); - exit(1); - } - log_hdump_all = true; - } else { - if (!args.empty() && !args[0].empty() && args[0].back() == '.') - args[0].pop_back(); - if (GetSize(args) == 1) - args.push_back("yosys_dump_" + args[0] + ".il"); - if (GetSize(args) != 2) { - fprintf(stderr, "Invalid number of tokens in -D.\n"); - exit(1); - } - log_hdump[args[0]].insert(args[1]); - } - } - break; - case 'E': - depsfile = optarg; - break; - default: - fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); - exit(1); - } - } - - if (log_errfile == NULL) { - log_files.push_back(stdout); - log_error_stderr = true; - } - - if (print_banner) - yosys_banner(); - - if (print_stats) - log_hasher = new SHA1; - -#if defined(__linux__) - // set stack size to >= 128 MB - { - struct rlimit rl; - const rlim_t stack_size = 128L * 1024L * 1024L; - if (getrlimit(RLIMIT_STACK, &rl) == 0 && rl.rlim_cur < stack_size) { - rl.rlim_cur = stack_size; - setrlimit(RLIMIT_STACK, &rl); - } - } -#endif - - yosys_setup(); -#ifdef WITH_PYTHON - PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); - PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); -#endif - log_error_atexit = yosys_atexit; - - for (auto &fn : plugin_filenames) - load_plugin(fn, {}); - - if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) { - if (!got_output_filename) - backend_command = ""; - shell(yosys_design); - } - - if (!vlog_defines.empty()) { - std::string vdef_cmd = "read -define"; - for (auto vdef : vlog_defines) - vdef_cmd += " " + vdef; - run_pass(vdef_cmd); - } - - while (optind < argc) - run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL); - - if (!scriptfile.empty()) { - if (scriptfile_tcl) { -#ifdef YOSYS_ENABLE_TCL - if (Tcl_EvalFile(yosys_get_tcl_interp(), scriptfile.c_str()) != TCL_OK) - log_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp())); -#else - log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n"); -#endif - } else - run_frontend(scriptfile, "script", output_filename == "-" ? &backend_command : NULL); - } - - for (auto it = passes_commands.begin(); it != passes_commands.end(); it++) - run_pass(*it); - - if (!backend_command.empty()) - run_backend(output_filename, backend_command); - - if (!depsfile.empty()) - { - FILE *f = fopen(depsfile.c_str(), "wt"); - if (f == nullptr) - log_error("Can't open dependencies file for writing: %s\n", strerror(errno)); - bool first = true; - for (auto fn : yosys_output_files) { - fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(fn).c_str()); - first = false; - } - fprintf(f, ":"); - for (auto fn : yosys_input_files) { - if (yosys_output_files.count(fn) == 0) - fprintf(f, " %s", escape_filename_spaces(fn).c_str()); - } - fprintf(f, "\n"); - } - - if (print_stats) - { - std::string hash = log_hasher->final().substr(0, 10); - delete log_hasher; - log_hasher = nullptr; - - log_time = false; - yosys_xtrace = 0; - log_spacer(); - - if (mode_v && !mode_q) - log_files.push_back(stderr); - - if (log_warnings_count) - log("Warnings: %d unique messages, %d total\n", GetSize(log_warnings), log_warnings_count); -#ifdef _WIN32 - log("End of script. Logfile hash: %s\n", hash.c_str()); -#else - std::string meminfo; - std::string stats_divider = ", "; -# if defined(__linux__) - std::ifstream statm; - statm.open(stringf("/proc/%lld/statm", (long long)getpid())); - if (statm.is_open()) { - int sz_total, sz_resident; - statm >> sz_total >> sz_resident; - meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident", - sz_total * (getpagesize() / 1024.0 / 1024.0), - sz_resident * (getpagesize() / 1024.0 / 1024.0)); - stats_divider = "\n"; - } -# elif defined(__FreeBSD__) - pid_t pid = getpid(); - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid}; - struct kinfo_proc kip; - size_t kip_len = sizeof(kip); - if (sysctl(mib, 4, &kip, &kip_len, NULL, 0) == 0) { - vm_size_t sz_total = kip.ki_size; - segsz_t sz_resident = kip.ki_rssize; - meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident", - (int)sz_total / 1024.0 / 1024.0, - (int)sz_resident * (getpagesize() / 1024.0 / 1024.0)); - stats_divider = "\n"; - } -# endif - - struct rusage ru_buffer; - getrusage(RUSAGE_SELF, &ru_buffer); - log("End of script. Logfile hash: %s%sCPU: user %.2fs system %.2fs%s\n", hash.c_str(), - stats_divider.c_str(), ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec, - ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec, meminfo.c_str()); -#endif - log("%s\n", yosys_version_str); - - int64_t total_ns = 0; - std::set> timedat; - - for (auto &it : pass_register) - if (it.second->call_counter) { - total_ns += it.second->runtime_ns + 1; - timedat.insert(make_tuple(it.second->runtime_ns + 1, it.second->call_counter, it.first)); - } - - if (timing_details) - { - log("Time spent:\n"); - for (auto it = timedat.rbegin(); it != timedat.rend(); it++) { - log("%5d%% %5d calls %8.3f sec %s\n", int(100*std::get<0>(*it) / total_ns), - std::get<1>(*it), std::get<0>(*it) / 1000000000.0, std::get<2>(*it).c_str()); - } - } - else - { - int out_count = 0; - log("Time spent:"); - for (auto it = timedat.rbegin(); it != timedat.rend() && out_count < 4; it++, out_count++) { - if (out_count >= 2 && (std::get<0>(*it) < 1000000000 || int(100*std::get<0>(*it) / total_ns) < 20)) { - log(", ..."); - break; - } - log("%s %d%% %dx %s (%d sec)", out_count ? "," : "", int(100*std::get<0>(*it) / total_ns), - std::get<1>(*it), std::get<2>(*it).c_str(), int(std::get<0>(*it) / 1000000000)); - } - log("%s\n", out_count ? "" : " no commands executed"); - } - } - -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE")) - { - string filename; - FILE *f; - - if (getenv("YOSYS_COVER_DIR")) { - filename = stringf("%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid()); - filename = make_temp_file(filename); - } else { - filename = getenv("YOSYS_COVER_FILE"); - } - - f = fopen(filename.c_str(), "a+"); - - if (f == NULL) - log_error("Can't create coverage file `%s'.\n", filename.c_str()); - - log("\n", filename.c_str()); - - for (auto &it : get_coverage_data()) - fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str()); - - fclose(f); - } -#endif - - yosys_atexit(); - - memhasher_off(); - if (call_abort) - abort(); - - log_flush(); -#if defined(_MSC_VER) - _exit(0); -#elif defined(_WIN32) - _Exit(0); -#endif - - yosys_shutdown(); - - return 0; -} - -#endif /* EMSCRIPTEN */ - diff --git a/yosys/kernel/hashlib.h b/yosys/kernel/hashlib.h deleted file mode 100644 index e7cb312ed..000000000 --- a/yosys/kernel/hashlib.h +++ /dev/null @@ -1,1065 +0,0 @@ -// This is free and unencumbered software released into the public domain. -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. - -// ------------------------------------------------------- -// Written by Clifford Wolf in 2014 -// ------------------------------------------------------- - -#ifndef HASHLIB_H -#define HASHLIB_H - -#include -#include -#include -#include - -namespace hashlib { - -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; -} - -// 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; -} - -inline unsigned int mkhash_xorshift(unsigned int a) { - if (sizeof(a) == 4) { - a ^= a << 13; - a ^= a >> 17; - a ^= a << 5; - } else if (sizeof(a) == 8) { - a ^= a << 13; - a ^= a >> 7; - a ^= a << 17; - } else - throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints"); - return a; -} - -template 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 - static inline bool cmp(T a, T b) { - return a == b; - } -}; - -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(int32_t a) { - return a; - } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(int64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); - } -}; - -template<> struct hash_ops { - 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; - } -}; - -template struct hash_ops> { - static inline bool cmp(std::pair a, std::pair b) { - return a == b; - } - static inline unsigned int hash(std::pair a) { - return mkhash(hash_ops

::hash(a.first), hash_ops::hash(a.second)); - } -}; - -template struct hash_ops> { - static inline bool cmp(std::tuple a, std::tuple b) { - return a == b; - } - template - static inline typename std::enable_if::type hash(std::tuple) { - return mkhash_init; - } - template - static inline typename std::enable_if::type hash(std::tuple a) { - typedef hash_ops>::type> element_ops_t; - return mkhash(hash(a), element_ops_t::hash(std::get(a))); - } -}; - -template struct hash_ops> { - static inline bool cmp(std::vector a, std::vector b) { - return a == b; - } - static inline unsigned int hash(std::vector a) { - unsigned int h = mkhash_init; - for (auto k : a) - h = mkhash(h, hash_ops::hash(k)); - return h; - } -}; - -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; - } - static inline unsigned int hash(const char *a) { - unsigned int hash = mkhash_init; - while (*a) - hash = mkhash(hash, *(a++)); - return hash; - } -}; - -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; - } -}; - -struct hash_obj_ops { - static inline bool cmp(const void *a, const void *b) { - return a == b; - } - template - static inline unsigned int hash(const T *a) { - return a ? a->hash() : 0; - } -}; - -template -inline unsigned int mkhash(const T &v) { - return hash_ops().hash(v); -} - -inline int hashtable_size(int min_size) -{ - static std::vector 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, - 120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697, - 897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037, - 5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411, - 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239, - 121590311, 151987889, 189984863, 237481091, 296851369, 371064217 - }; - - for (auto p : zero_and_some_primes) - if (p >= min_size) return p; - - if (sizeof(int) == 4) - throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables."); - - for (auto p : zero_and_some_primes) - if (100129 * p > min_size) return 100129 * p; - - throw std::length_error("hash table exceeded maximum size."); -} - -template> class dict; -template> class idict; -template> class pool; -template> class mfp; - -template -class dict -{ - struct entry_t - { - std::pair udata; - int next; - - entry_t() { } - entry_t(const std::pair &udata, int next) : udata(udata), next(next) { } - entry_t(std::pair &&udata, int next) : udata(std::move(udata)), next(next) { } - }; - - std::vector hashtable; - std::vector entries; - OPS ops; - -#ifdef NDEBUG - static inline void do_assert(bool) { } -#else - static inline void do_assert(bool cond) { - if (!cond) throw std::runtime_error("dict<> assert failed."); - } -#endif - - int do_hash(const K &key) const - { - unsigned int hash = 0; - if (!hashtable.empty()) - hash = ops.hash(key) % (unsigned int)(hashtable.size()); - return hash; - } - - void do_rehash() - { - hashtable.clear(); - hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1); - - 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); - entries[i].next = hashtable[hash]; - hashtable[hash] = i; - } - } - - int do_erase(int index, int hash) - { - do_assert(index < int(entries.size())); - if (hashtable.empty() || index < 0) - return 0; - - int k = hashtable[hash]; - do_assert(0 <= k && k < int(entries.size())); - - if (k == index) { - hashtable[hash] = entries[index].next; - } else { - while (entries[k].next != index) { - k = entries[k].next; - do_assert(0 <= k && k < int(entries.size())); - } - entries[k].next = entries[index].next; - } - - int back_idx = entries.size()-1; - - if (index != back_idx) - { - int back_hash = do_hash(entries[back_idx].udata.first); - - k = hashtable[back_hash]; - do_assert(0 <= k && k < int(entries.size())); - - if (k == back_idx) { - hashtable[back_hash] = index; - } else { - while (entries[k].next != back_idx) { - k = entries[k].next; - do_assert(0 <= k && k < int(entries.size())); - } - entries[k].next = index; - } - - entries[index] = std::move(entries[back_idx]); - } - - entries.pop_back(); - - if (entries.empty()) - hashtable.clear(); - - return 1; - } - - int do_lookup(const K &key, int &hash) const - { - if (hashtable.empty()) - return -1; - - if (entries.size() * hashtable_size_trigger > hashtable.size()) { - ((dict*)this)->do_rehash(); - hash = do_hash(key); - } - - int index = hashtable[hash]; - - while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) { - index = entries[index].next; - do_assert(-1 <= index && index < int(entries.size())); - } - - return index; - } - - int do_insert(const K &key, int &hash) - { - if (hashtable.empty()) { - entries.push_back(entry_t(std::pair(key, T()), -1)); - do_rehash(); - hash = do_hash(key); - } else { - entries.push_back(entry_t(std::pair(key, T()), hashtable[hash])); - hashtable[hash] = entries.size() - 1; - } - return entries.size() - 1; - } - - int do_insert(const std::pair &value, int &hash) - { - if (hashtable.empty()) { - entries.push_back(entry_t(value, -1)); - do_rehash(); - hash = do_hash(value.first); - } else { - entries.push_back(entry_t(value, hashtable[hash])); - hashtable[hash] = entries.size() - 1; - } - return entries.size() - 1; - } - -public: - class const_iterator : public std::iterator> - { - friend class dict; - protected: - const dict *ptr; - int index; - const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { } - public: - const_iterator() { } - const_iterator operator++() { index--; return *this; } - bool operator<(const const_iterator &other) const { return index > other.index; } - bool operator==(const const_iterator &other) const { return index == other.index; } - bool operator!=(const const_iterator &other) const { return index != other.index; } - const std::pair &operator*() const { return ptr->entries[index].udata; } - const std::pair *operator->() const { return &ptr->entries[index].udata; } - }; - - class iterator : public std::iterator> - { - friend class dict; - protected: - dict *ptr; - int index; - iterator(dict *ptr, int index) : ptr(ptr), index(index) { } - public: - iterator() { } - iterator operator++() { index--; return *this; } - bool operator<(const iterator &other) const { return index > other.index; } - bool operator==(const iterator &other) const { return index == other.index; } - bool operator!=(const iterator &other) const { return index != other.index; } - std::pair &operator*() { return ptr->entries[index].udata; } - std::pair *operator->() { return &ptr->entries[index].udata; } - const std::pair &operator*() const { return ptr->entries[index].udata; } - const std::pair *operator->() const { return &ptr->entries[index].udata; } - operator const_iterator() const { return const_iterator(ptr, index); } - }; - - dict() - { - } - - dict(const dict &other) - { - entries = other.entries; - do_rehash(); - } - - dict(dict &&other) - { - swap(other); - } - - dict &operator=(const dict &other) { - entries = other.entries; - do_rehash(); - return *this; - } - - dict &operator=(dict &&other) { - clear(); - swap(other); - return *this; - } - - dict(const std::initializer_list> &list) - { - for (auto &it : list) - insert(it); - } - - template - dict(InputIterator first, InputIterator last) - { - insert(first, last); - } - - template - void insert(InputIterator first, InputIterator last) - { - for (; first != last; ++first) - insert(*first); - } - - std::pair insert(const K &key) - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i >= 0) - return std::pair(iterator(this, i), false); - i = do_insert(key, hash); - return std::pair(iterator(this, i), true); - } - - std::pair insert(const std::pair &value) - { - int hash = do_hash(value.first); - int i = do_lookup(value.first, hash); - if (i >= 0) - return std::pair(iterator(this, i), false); - i = do_insert(value, hash); - return std::pair(iterator(this, i), true); - } - - int erase(const K &key) - { - int 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); - do_erase(it.index, hash); - return ++it; - } - - int count(const K &key) const - { - int 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); - int i = do_lookup(key, hash); - return i < 0 || i > it.index ? 0 : 1; - } - - iterator find(const K &key) - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i < 0) - return end(); - return iterator(this, i); - } - - const_iterator find(const K &key) const - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i < 0) - return end(); - return const_iterator(this, i); - } - - T& at(const K &key) - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i < 0) - throw std::out_of_range("dict::at()"); - return entries[i].udata.second; - } - - const T& at(const K &key) const - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i < 0) - throw std::out_of_range("dict::at()"); - return entries[i].udata.second; - } - - T at(const K &key, const T &defval) const - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i < 0) - return defval; - return entries[i].udata.second; - } - - T& operator[](const K &key) - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i < 0) - i = do_insert(std::pair(key, T()), hash); - return entries[i].udata.second; - } - - template> - void sort(Compare comp = Compare()) - { - std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); }); - do_rehash(); - } - - void swap(dict &other) - { - hashtable.swap(other.hashtable); - entries.swap(other.entries); - } - - bool operator==(const dict &other) const { - if (size() != other.size()) - return false; - for (auto &it : entries) { - auto oit = other.find(it.udata.first); - if (oit == other.end() || !(oit->second == it.udata.second)) - return false; - } - return true; - } - - bool operator!=(const dict &other) const { - return !operator==(other); - } - - void reserve(size_t n) { entries.reserve(n); } - size_t size() const { return entries.size(); } - bool empty() const { return entries.empty(); } - void clear() { hashtable.clear(); entries.clear(); } - - iterator begin() { return iterator(this, int(entries.size())-1); } - iterator element(int n) { return iterator(this, int(entries.size())-1-n); } - iterator end() { return iterator(nullptr, -1); } - - const_iterator begin() const { return const_iterator(this, int(entries.size())-1); } - const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); } - const_iterator end() const { return const_iterator(nullptr, -1); } -}; - -template -class pool -{ - template friend class idict; - -protected: - struct entry_t - { - K udata; - int next; - - entry_t() { } - entry_t(const K &udata, int next) : udata(udata), next(next) { } - }; - - std::vector hashtable; - std::vector entries; - OPS ops; - -#ifdef NDEBUG - static inline void do_assert(bool) { } -#else - static inline void do_assert(bool cond) { - if (!cond) throw std::runtime_error("pool<> assert failed."); - } -#endif - - int do_hash(const K &key) const - { - unsigned int hash = 0; - if (!hashtable.empty()) - hash = ops.hash(key) % (unsigned int)(hashtable.size()); - return hash; - } - - void do_rehash() - { - hashtable.clear(); - hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1); - - 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); - entries[i].next = hashtable[hash]; - hashtable[hash] = i; - } - } - - int do_erase(int index, int hash) - { - do_assert(index < int(entries.size())); - if (hashtable.empty() || index < 0) - return 0; - - int k = hashtable[hash]; - if (k == index) { - hashtable[hash] = entries[index].next; - } else { - while (entries[k].next != index) { - k = entries[k].next; - do_assert(0 <= k && k < int(entries.size())); - } - entries[k].next = entries[index].next; - } - - int back_idx = entries.size()-1; - - if (index != back_idx) - { - int back_hash = do_hash(entries[back_idx].udata); - - k = hashtable[back_hash]; - if (k == back_idx) { - hashtable[back_hash] = index; - } else { - while (entries[k].next != back_idx) { - k = entries[k].next; - do_assert(0 <= k && k < int(entries.size())); - } - entries[k].next = index; - } - - entries[index] = std::move(entries[back_idx]); - } - - entries.pop_back(); - - if (entries.empty()) - hashtable.clear(); - - return 1; - } - - int do_lookup(const K &key, int &hash) const - { - if (hashtable.empty()) - return -1; - - if (entries.size() * hashtable_size_trigger > hashtable.size()) { - ((pool*)this)->do_rehash(); - hash = do_hash(key); - } - - int index = hashtable[hash]; - - while (index >= 0 && !ops.cmp(entries[index].udata, key)) { - index = entries[index].next; - do_assert(-1 <= index && index < int(entries.size())); - } - - return index; - } - - int do_insert(const K &value, int &hash) - { - if (hashtable.empty()) { - entries.push_back(entry_t(value, -1)); - do_rehash(); - hash = do_hash(value); - } else { - entries.push_back(entry_t(value, hashtable[hash])); - hashtable[hash] = entries.size() - 1; - } - return entries.size() - 1; - } - -public: - class const_iterator : public std::iterator - { - friend class pool; - protected: - const pool *ptr; - int index; - const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { } - public: - const_iterator() { } - const_iterator operator++() { index--; return *this; } - bool operator==(const const_iterator &other) const { return index == other.index; } - bool operator!=(const const_iterator &other) const { return index != other.index; } - const K &operator*() const { return ptr->entries[index].udata; } - const K *operator->() const { return &ptr->entries[index].udata; } - }; - - class iterator : public std::iterator - { - friend class pool; - protected: - pool *ptr; - int index; - iterator(pool *ptr, int index) : ptr(ptr), index(index) { } - public: - iterator() { } - iterator operator++() { index--; return *this; } - bool operator==(const iterator &other) const { return index == other.index; } - bool operator!=(const iterator &other) const { return index != other.index; } - K &operator*() { return ptr->entries[index].udata; } - K *operator->() { return &ptr->entries[index].udata; } - const K &operator*() const { return ptr->entries[index].udata; } - const K *operator->() const { return &ptr->entries[index].udata; } - operator const_iterator() const { return const_iterator(ptr, index); } - }; - - pool() - { - } - - pool(const pool &other) - { - entries = other.entries; - do_rehash(); - } - - pool(pool &&other) - { - swap(other); - } - - pool &operator=(const pool &other) { - entries = other.entries; - do_rehash(); - return *this; - } - - pool &operator=(pool &&other) { - clear(); - swap(other); - return *this; - } - - pool(const std::initializer_list &list) - { - for (auto &it : list) - insert(it); - } - - template - pool(InputIterator first, InputIterator last) - { - insert(first, last); - } - - template - void insert(InputIterator first, InputIterator last) - { - for (; first != last; ++first) - insert(*first); - } - - std::pair insert(const K &value) - { - int hash = do_hash(value); - int i = do_lookup(value, hash); - if (i >= 0) - return std::pair(iterator(this, i), false); - i = do_insert(value, hash); - return std::pair(iterator(this, i), true); - } - - int erase(const K &key) - { - int hash = do_hash(key); - int index = do_lookup(key, hash); - return do_erase(index, hash); - } - - iterator erase(iterator it) - { - int hash = do_hash(*it); - do_erase(it.index, hash); - return ++it; - } - - int count(const K &key) const - { - int 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); - int i = do_lookup(key, hash); - return i < 0 || i > it.index ? 0 : 1; - } - - iterator find(const K &key) - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i < 0) - return end(); - return iterator(this, i); - } - - const_iterator find(const K &key) const - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - if (i < 0) - return end(); - return const_iterator(this, i); - } - - bool operator[](const K &key) - { - int hash = do_hash(key); - int i = do_lookup(key, hash); - return i >= 0; - } - - template> - void sort(Compare comp = Compare()) - { - std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); }); - do_rehash(); - } - - K pop() - { - iterator it = begin(); - K ret = *it; - erase(it); - return ret; - } - - void swap(pool &other) - { - hashtable.swap(other.hashtable); - entries.swap(other.entries); - } - - bool operator==(const pool &other) const { - if (size() != other.size()) - return false; - for (auto &it : entries) - if (!other.count(it.udata)) - return false; - return true; - } - - bool operator!=(const pool &other) const { - return !operator==(other); - } - - bool hash() const { - unsigned int hashval = mkhash_init; - for (auto &it : entries) - hashval ^= ops.hash(it.udata); - return hashval; - } - - void reserve(size_t n) { entries.reserve(n); } - size_t size() const { return entries.size(); } - bool empty() const { return entries.empty(); } - void clear() { hashtable.clear(); entries.clear(); } - - iterator begin() { return iterator(this, int(entries.size())-1); } - iterator element(int n) { return iterator(this, int(entries.size())-1-n); } - iterator end() { return iterator(nullptr, -1); } - - const_iterator begin() const { return const_iterator(this, int(entries.size())-1); } - const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); } - const_iterator end() const { return const_iterator(nullptr, -1); } -}; - -template -class idict -{ - pool database; - -public: - typedef typename pool::const_iterator const_iterator; - - int operator()(const K &key) - { - int hash = database.do_hash(key); - int i = database.do_lookup(key, hash); - if (i < 0) - i = database.do_insert(key, hash); - return i + offset; - } - - int at(const K &key) const - { - int hash = database.do_hash(key); - int i = database.do_lookup(key, hash); - if (i < 0) - throw std::out_of_range("idict::at()"); - return i + offset; - } - - int at(const K &key, int defval) const - { - int hash = database.do_hash(key); - int i = database.do_lookup(key, hash); - if (i < 0) - return defval; - return i + offset; - } - - int count(const K &key) const - { - int hash = database.do_hash(key); - int i = database.do_lookup(key, hash); - return i < 0 ? 0 : 1; - } - - void expect(const K &key, int i) - { - int j = (*this)(key); - if (i != j) - throw std::out_of_range("idict::expect()"); - } - - const K &operator[](int index) const - { - return database.entries.at(index - offset).udata; - } - - void swap(idict &other) - { - database.swap(other.database); - } - - void reserve(size_t n) { database.reserve(n); } - size_t size() const { return database.size(); } - bool empty() const { return database.empty(); } - void clear() { database.clear(); } - - const_iterator begin() const { return database.begin(); } - const_iterator element(int n) const { return database.element(n); } - const_iterator end() const { return database.end(); } -}; - -template -class mfp -{ - mutable idict database; - mutable std::vector parents; - -public: - typedef typename idict::const_iterator const_iterator; - - int operator()(const K &key) const - { - int i = database(key); - parents.resize(database.size(), -1); - return i; - } - - const K &operator[](int index) const - { - return database[index]; - } - - int ifind(int i) const - { - int p = i, k = i; - - while (parents[p] != -1) - p = parents[p]; - - while (k != p) { - int next_k = parents[k]; - parents[k] = p; - k = next_k; - } - - return p; - } - - void imerge(int i, int j) - { - i = ifind(i); - j = ifind(j); - - if (i != j) - parents[i] = j; - } - - void ipromote(int i) - { - int k = i; - - while (k != -1) { - int next_k = parents[k]; - parents[k] = i; - k = next_k; - } - - parents[i] = -1; - } - - int lookup(const K &a) const - { - return ifind((*this)(a)); - } - - const K &find(const K &a) const - { - int i = database.at(a, -1); - if (i < 0) - return a; - return (*this)[ifind(i)]; - } - - void merge(const K &a, const K &b) - { - imerge((*this)(a), (*this)(b)); - } - - void promote(const K &a) - { - int i = database.at(a, -1); - if (i >= 0) - ipromote(i); - } - - void swap(mfp &other) - { - database.swap(other.database); - parents.swap(other.parents); - } - - void reserve(size_t n) { database.reserve(n); } - size_t size() const { return database.size(); } - bool empty() const { return database.empty(); } - void clear() { database.clear(); parents.clear(); } - - const_iterator begin() const { return database.begin(); } - const_iterator element(int n) const { return database.element(n); } - const_iterator end() const { return database.end(); } -}; - -} /* namespace hashlib */ - -#endif diff --git a/yosys/kernel/log.cc b/yosys/kernel/log.cc deleted file mode 100644 index a7820950c..000000000 --- a/yosys/kernel/log.cc +++ /dev/null @@ -1,666 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "libs/sha1/sha1.h" -#include "backends/ilang/ilang_backend.h" - -#if !defined(_WIN32) || defined(__MINGW32__) -# include -#endif - -#if defined(__linux__) || defined(__FreeBSD__) -# include -#endif - -#include -#include -#include -#include -#include -#include - -YOSYS_NAMESPACE_BEGIN - -std::vector log_files; -std::vector log_streams; -std::map> log_hdump; -std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -std::set log_warnings; -int log_warnings_count = 0; -bool log_hdump_all = false; -FILE *log_errfile = NULL; -SHA1 *log_hasher = NULL; - -bool log_time = false; -bool log_error_stderr = false; -bool log_cmd_error_throw = false; -bool log_quiet_warnings = false; -int log_verbose_level; -string log_last_error; -void (*log_error_atexit)() = NULL; - -int log_make_debug = 0; -int log_force_debug = 0; -int log_debug_suppressed = 0; - -vector header_count; -pool log_id_cache; -vector string_buf; -int string_buf_index = -1; - -static struct timeval initial_tv = { 0, 0 }; -static bool next_print_log = false; -static int log_newline_count = 0; - -#if defined(_WIN32) && !defined(__MINGW32__) -// this will get time information and return it in timeval, simulating gettimeofday() -int gettimeofday(struct timeval *tv, struct timezone *tz) -{ - LARGE_INTEGER counter; - LARGE_INTEGER freq; - - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&counter); - - counter.QuadPart *= 1000000; - counter.QuadPart /= freq.QuadPart; - - tv->tv_sec = long(counter.QuadPart / 1000000); - tv->tv_usec = counter.QuadPart % 1000000; - - return 0; -} -#endif - -void logv(const char *format, va_list ap) -{ - while (format[0] == '\n' && format[1] != 0) { - log("\n"); - format++; - } - - if (log_make_debug && !ys_debug(1)) - return; - - std::string str = vstringf(format, ap); - - if (str.empty()) - return; - - size_t nnl_pos = str.find_last_not_of('\n'); - if (nnl_pos == std::string::npos) - log_newline_count += GetSize(str); - else - log_newline_count = GetSize(str) - nnl_pos - 1; - - if (log_hasher) - log_hasher->update(str); - - if (log_time) - { - std::string time_str; - - if (next_print_log || initial_tv.tv_sec == 0) { - next_print_log = false; - struct timeval tv; - gettimeofday(&tv, NULL); - if (initial_tv.tv_sec == 0) - initial_tv = tv; - if (tv.tv_usec < initial_tv.tv_usec) { - tv.tv_sec--; - tv.tv_usec += 1000000; - } - tv.tv_sec -= initial_tv.tv_sec; - tv.tv_usec -= initial_tv.tv_usec; - time_str += stringf("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec)); - } - - if (format[0] && format[strlen(format)-1] == '\n') - next_print_log = true; - - for (auto f : log_files) - fputs(time_str.c_str(), f); - - for (auto f : log_streams) - *f << time_str; - } - - for (auto f : log_files) - fputs(str.c_str(), f); - - for (auto f : log_streams) - *f << str; - - static std::string linebuffer; - static bool log_warn_regex_recusion_guard = false; - - if (!log_warn_regex_recusion_guard) - { - log_warn_regex_recusion_guard = true; - - if (log_warn_regexes.empty()) - { - linebuffer.clear(); - } - else - { - linebuffer += str; - - if (!linebuffer.empty() && linebuffer.back() == '\n') { - for (auto &re : log_warn_regexes) - if (std::regex_search(linebuffer, re)) - log_warning("Found log message matching -W regex:\n%s", str.c_str()); - linebuffer.clear(); - } - } - - log_warn_regex_recusion_guard = false; - } -} - -void logv_header(RTLIL::Design *design, const char *format, va_list ap) -{ - bool pop_errfile = false; - - log_spacer(); - if (header_count.size() > 0) - header_count.back()++; - - if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) { - log_files.push_back(log_errfile); - pop_errfile = true; - } - - std::string header_id; - - for (int c : header_count) - header_id += stringf("%s%d", header_id.empty() ? "" : ".", c); - - log("%s. ", header_id.c_str()); - logv(format, ap); - log_flush(); - - if (log_hdump_all) - log_hdump[header_id].insert("yosys_dump_" + header_id + ".il"); - - if (log_hdump.count(header_id) && design != nullptr) - for (auto &filename : log_hdump.at(header_id)) { - log("Dumping current design to '%s'.\n", filename.c_str()); - if (yosys_xtrace) - IdString::xtrace_db_dump(); - Pass::call(design, {"dump", "-o", filename}); - if (yosys_xtrace) - log("#X# -- end of dump --\n"); - } - - if (pop_errfile) - log_files.pop_back(); -} - -static void logv_warning_with_prefix(const char *prefix, - const char *format, va_list ap) -{ - std::string message = vstringf(format, ap); - bool suppressed = false; - - for (auto &re : log_nowarn_regexes) - if (std::regex_search(message, re)) - suppressed = true; - - if (suppressed) - { - log("Suppressed %s%s", prefix, message.c_str()); - } - else - { - int bak_log_make_debug = log_make_debug; - log_make_debug = 0; - - for (auto &re : log_werror_regexes) - if (std::regex_search(message, re)) - log_error("%s", message.c_str()); - - if (log_warnings.count(message)) - { - log("%s%s", prefix, message.c_str()); - log_flush(); - } - else - { - if (log_errfile != NULL && !log_quiet_warnings) - log_files.push_back(log_errfile); - - log("%s%s", prefix, message.c_str()); - log_flush(); - - if (log_errfile != NULL && !log_quiet_warnings) - log_files.pop_back(); - - log_warnings.insert(message); - } - - log_warnings_count++; - log_make_debug = bak_log_make_debug; - } -} - -void logv_warning(const char *format, va_list ap) -{ - logv_warning_with_prefix("Warning: ", format, ap); -} - -void logv_warning_noprefix(const char *format, va_list ap) -{ - logv_warning_with_prefix("", format, ap); -} - -void log_file_warning(const std::string &filename, int lineno, - const char *format, ...) -{ - va_list ap; - va_start(ap, format); - std::string prefix = stringf("%s:%d: Warning: ", - filename.c_str(), lineno); - logv_warning_with_prefix(prefix.c_str(), format, ap); - va_end(ap); -} - -void log_file_info(const std::string &filename, int lineno, - const char *format, ...) -{ - va_list ap; - va_start(ap, format); - std::string fmt = stringf("%s:%d: Info: %s", - filename.c_str(), lineno, format); - logv(fmt.c_str(), ap); - va_end(ap); -} - -YS_ATTRIBUTE(noreturn) -static void logv_error_with_prefix(const char *prefix, - const char *format, va_list ap) -{ -#ifdef EMSCRIPTEN - auto backup_log_files = log_files; -#endif - int bak_log_make_debug = log_make_debug; - log_make_debug = 0; - log_suppressed(); - - if (log_errfile != NULL) - log_files.push_back(log_errfile); - - if (log_error_stderr) - for (auto &f : log_files) - if (f == stdout) - f = stderr; - - log_last_error = vstringf(format, ap); - log("%s%s", prefix, log_last_error.c_str()); - log_flush(); - - log_make_debug = bak_log_make_debug; - - if (log_error_atexit) - log_error_atexit(); - -#ifdef EMSCRIPTEN - log_files = backup_log_files; - throw 0; -#elif defined(_MSC_VER) - _exit(1); -#else - _Exit(1); -#endif -} - -void logv_error(const char *format, va_list ap) -{ - logv_error_with_prefix("ERROR: ", format, ap); -} - -void log_file_error(const string &filename, int lineno, - const char *format, ...) -{ - va_list ap; - va_start(ap, format); - std::string prefix = stringf("%s:%d: ERROR: ", - filename.c_str(), lineno); - logv_error_with_prefix(prefix.c_str(), format, ap); -} - -void log(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv(format, ap); - va_end(ap); -} - -void log_header(RTLIL::Design *design, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_header(design, format, ap); - va_end(ap); -} - -void log_warning(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_warning(format, ap); - va_end(ap); -} - -void log_warning_noprefix(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_warning_noprefix(format, ap); - va_end(ap); -} - -void log_error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_error(format, ap); -} - -void log_cmd_error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - - if (log_cmd_error_throw) { - log_last_error = vstringf(format, ap); - log("ERROR: %s", log_last_error.c_str()); - log_flush(); - throw log_cmd_error_exception(); - } - - logv_error(format, ap); -} - -void log_spacer() -{ - if (log_newline_count < 2) log("\n"); - if (log_newline_count < 2) log("\n"); -} - -void log_push() -{ - header_count.push_back(0); -} - -void log_pop() -{ - header_count.pop_back(); - log_id_cache.clear(); - string_buf.clear(); - string_buf_index = -1; - log_flush(); -} - -#if (defined(__linux__) || defined(__FreeBSD__)) && defined(YOSYS_ENABLE_PLUGINS) -void log_backtrace(const char *prefix, int levels) -{ - if (levels <= 0) return; - - Dl_info dli; - void *p; - - if ((p = __builtin_extract_return_addr(__builtin_return_address(0))) && dladdr(p, &dli)) { - log("%sframe #1: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #1: ---\n", prefix); - return; - } - - if (levels <= 1) return; - -#ifndef DEBUG - log("%sframe #2: [build Yosys with ENABLE_DEBUG for deeper backtraces]\n", prefix); -#else - if ((p = __builtin_extract_return_addr(__builtin_return_address(1))) && dladdr(p, &dli)) { - log("%sframe #2: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #2: ---\n", prefix); - return; - } - - if (levels <= 2) return; - - if ((p = __builtin_extract_return_addr(__builtin_return_address(2))) && dladdr(p, &dli)) { - log("%sframe #3: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #3: ---\n", prefix); - return; - } - - if (levels <= 3) return; - - if ((p = __builtin_extract_return_addr(__builtin_return_address(3))) && dladdr(p, &dli)) { - log("%sframe #4: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #4: ---\n", prefix); - return; - } - - if (levels <= 4) return; - - if ((p = __builtin_extract_return_addr(__builtin_return_address(4))) && dladdr(p, &dli)) { - log("%sframe #5: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #5: ---\n", prefix); - return; - } - - if (levels <= 5) return; - - if ((p = __builtin_extract_return_addr(__builtin_return_address(5))) && dladdr(p, &dli)) { - log("%sframe #6: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #6: ---\n", prefix); - return; - } - - if (levels <= 6) return; - - if ((p = __builtin_extract_return_addr(__builtin_return_address(6))) && dladdr(p, &dli)) { - log("%sframe #7: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #7: ---\n", prefix); - return; - } - - if (levels <= 7) return; - - if ((p = __builtin_extract_return_addr(__builtin_return_address(7))) && dladdr(p, &dli)) { - log("%sframe #8: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #8: ---\n", prefix); - return; - } - - if (levels <= 8) return; - - if ((p = __builtin_extract_return_addr(__builtin_return_address(8))) && dladdr(p, &dli)) { - log("%sframe #9: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); - } else { - log("%sframe #9: ---\n", prefix); - return; - } - - if (levels <= 9) return; -#endif -} -#else -void log_backtrace(const char*, int) { } -#endif - -void log_reset_stack() -{ - while (header_count.size() > 1) - header_count.pop_back(); - log_id_cache.clear(); - string_buf.clear(); - string_buf_index = -1; - log_flush(); -} - -void log_flush() -{ - for (auto f : log_files) - fflush(f); - - for (auto f : log_streams) - f->flush(); -} - -void log_dump_val_worker(RTLIL::IdString v) { - log("%s", log_id(v)); -} - -void log_dump_val_worker(RTLIL::SigSpec v) { - log("%s", log_signal(v)); -} - -const char *log_signal(const RTLIL::SigSpec &sig, bool autoint) -{ - std::stringstream buf; - ILANG_BACKEND::dump_sigspec(buf, sig, autoint); - - if (string_buf.size() < 100) { - string_buf.push_back(buf.str()); - return string_buf.back().c_str(); - } else { - if (++string_buf_index == 100) - string_buf_index = 0; - string_buf[string_buf_index] = buf.str(); - return string_buf[string_buf_index].c_str(); - } -} - -const char *log_const(const RTLIL::Const &value, bool autoint) -{ - if ((value.flags & RTLIL::CONST_FLAG_STRING) == 0) - return log_signal(value, autoint); - - std::string str = "\"" + value.decode_string() + "\""; - - if (string_buf.size() < 100) { - string_buf.push_back(str); - return string_buf.back().c_str(); - } else { - if (++string_buf_index == 100) - string_buf_index = 0; - string_buf[string_buf_index] = str; - return string_buf[string_buf_index].c_str(); - } -} - -const char *log_id(RTLIL::IdString str) -{ - log_id_cache.insert(str); - const char *p = str.c_str(); - if (p[0] != '\\') - return p; - if (p[1] == '$' || p[1] == '\\' || p[1] == 0) - return p; - if (p[1] >= '0' && p[1] <= '9') - return p; - return p+1; -} - -void log_module(RTLIL::Module *module, std::string indent) -{ - std::stringstream buf; - ILANG_BACKEND::dump_module(buf, indent, module, module->design, false); - log("%s", buf.str().c_str()); -} - -void log_cell(RTLIL::Cell *cell, std::string indent) -{ - std::stringstream buf; - ILANG_BACKEND::dump_cell(buf, indent, cell); - log("%s", buf.str().c_str()); -} - -void log_wire(RTLIL::Wire *wire, std::string indent) -{ - std::stringstream buf; - ILANG_BACKEND::dump_wire(buf, indent, wire); - log("%s", buf.str().c_str()); -} - -// --------------------------------------------------- -// This is the magic behind the code coverage counters -// --------------------------------------------------- -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - -dict> extra_coverage_data; - -void cover_extra(std::string parent, std::string id, bool increment) { - if (extra_coverage_data.count(id) == 0) { - for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) - if (p->id == parent) - extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func); - log_assert(extra_coverage_data.count(id)); - } - if (increment) - extra_coverage_data[id].second++; -} - -dict> get_coverage_data() -{ - dict> coverage_data; - - for (auto &it : pass_register) { - std::string key = stringf("passes.%s", it.first.c_str()); - coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__); - coverage_data[key].second += it.second->call_counter; - } - - for (auto &it : extra_coverage_data) { - if (coverage_data.count(it.first)) - log_warning("found duplicate coverage id \"%s\".\n", it.first.c_str()); - coverage_data[it.first].first = it.second.first; - coverage_data[it.first].second += it.second.second; - } - - for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) { - if (coverage_data.count(p->id)) - log_warning("found duplicate coverage id \"%s\".\n", p->id); - coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func); - coverage_data[p->id].second += p->counter; - } - - for (auto &it : coverage_data) - if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/")) - it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/")); - - return coverage_data; -} - -#endif - -YOSYS_NAMESPACE_END diff --git a/yosys/kernel/log.h b/yosys/kernel/log.h deleted file mode 100644 index 3e1facae8..000000000 --- a/yosys/kernel/log.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" - -#ifndef LOG_H -#define LOG_H - -#include -#include - -#ifndef _WIN32 -# include -# include -#endif - -#if defined(_MSC_VER) -// At least this is not in MSVC++ 2013. -# define __PRETTY_FUNCTION__ __FUNCTION__ -#endif - -// from libs/sha1/sha1.h -class SHA1; - -YOSYS_NAMESPACE_BEGIN - -#define S__LINE__sub2(x) #x -#define S__LINE__sub1(x) S__LINE__sub2(x) -#define S__LINE__ S__LINE__sub1(__LINE__) - -struct log_cmd_error_exception { }; - -extern std::vector log_files; -extern std::vector log_streams; -extern std::map> log_hdump; -extern std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -extern std::set log_warnings; -extern int log_warnings_count; -extern bool log_hdump_all; -extern FILE *log_errfile; -extern SHA1 *log_hasher; - -extern bool log_time; -extern bool log_error_stderr; -extern bool log_cmd_error_throw; -extern bool log_quiet_warnings; -extern int log_verbose_level; -extern string log_last_error; -extern void (*log_error_atexit)(); - -extern int log_make_debug; -extern int log_force_debug; -extern int log_debug_suppressed; - -void logv(const char *format, va_list ap); -void logv_header(RTLIL::Design *design, const char *format, va_list ap); -void logv_warning(const char *format, va_list ap); -void logv_warning_noprefix(const char *format, va_list ap); -YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn); - -void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3)); -void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); - -// Log with filename to report a problem in a source file. -void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); -void log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); - -void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); -void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn); -YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); - -#ifndef NDEBUG -static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } -# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) -#else -static inline bool ys_debug(int n = 0) { return false; } -# define log_debug(_fmt, ...) do { } while (0) -#endif - -static inline void log_suppressed() { - if (log_debug_suppressed && !log_make_debug) { - log("\n", log_debug_suppressed); - log_debug_suppressed = 0; - } -} - -struct LogMakeDebugHdl { - bool status = false; - LogMakeDebugHdl(bool start_on = false) { - if (start_on) - on(); - } - ~LogMakeDebugHdl() { - off(); - } - void on() { - if (status) return; - status=true; - log_make_debug++; - } - void off_silent() { - if (!status) return; - status=false; - log_make_debug--; - } - void off() { - off_silent(); - } -}; - -void log_spacer(); -void log_push(); -void log_pop(); - -void log_backtrace(const char *prefix, int levels); -void log_reset_stack(); -void log_flush(); - -const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); -const char *log_const(const RTLIL::Const &value, bool autoint = true); -const char *log_id(RTLIL::IdString id); - -template static inline const char *log_id(T *obj, const char *nullstr = nullptr) { - if (nullstr && obj == nullptr) - return nullstr; - return log_id(obj->name); -} - -void log_module(RTLIL::Module *module, std::string indent = ""); -void log_cell(RTLIL::Cell *cell, std::string indent = ""); -void log_wire(RTLIL::Wire *wire, std::string indent = ""); - -#ifndef NDEBUG -static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) { - if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line); -} -# define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) -#else -# define log_assert(_assert_expr_) -#endif - -#define log_abort() YOSYS_NAMESPACE_PREFIX log_error("Abort in %s:%d.\n", __FILE__, __LINE__) -#define log_ping() YOSYS_NAMESPACE_PREFIX log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__) - - -// --------------------------------------------------- -// This is the magic behind the code coverage counters -// --------------------------------------------------- - -#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__)) - -#define cover(_id) do { \ - static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \ - __d.counter++; \ -} while (0) - -struct CoverData { - const char *file, *func, *id; - int line, counter; -} YS_ATTRIBUTE(packed); - -// this two symbols are created by the linker for the "yosys_cover_list" ELF section -extern "C" struct CoverData __start_yosys_cover_list[]; -extern "C" struct CoverData __stop_yosys_cover_list[]; - -extern dict> extra_coverage_data; - -void cover_extra(std::string parent, std::string id, bool increment = true); -dict> get_coverage_data(); - -#define cover_list(_id, ...) do { cover(_id); \ - std::string r = cover_list_worker(_id, __VA_ARGS__); \ - log_assert(r.empty()); \ -} while (0) - -static inline std::string cover_list_worker(std::string, std::string last) { - return last; -} - -template -std::string cover_list_worker(std::string prefix, std::string first, T... rest) { - std::string selected = cover_list_worker(prefix, rest...); - cover_extra(prefix, prefix + "." + first, first == selected); - return first == selected ? "" : selected; -} - -#else -# define cover(...) do { } while (0) -# define cover_list(...) do { } while (0) -#endif - - -// ------------------------------------------------------------ -// everything below this line are utilities for troubleshooting -// ------------------------------------------------------------ - -// simple timer for performance measurements -// toggle the '#if 1' to get a baseline for the performance penalty added by the measurement -struct PerformanceTimer -{ -#if 1 - int64_t total_ns; - - PerformanceTimer() { - total_ns = 0; - } - - static int64_t query() { -# ifdef _WIN32 - return 0; -# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) - struct timespec ts; - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); - return int64_t(ts.tv_sec)*1000000000 + ts.tv_nsec; -# elif defined(RUSAGE_SELF) - struct rusage rusage; - int64_t t; - if (getrusage(RUSAGE_SELF, &rusage) == -1) { - log_cmd_error("getrusage failed!\n"); - log_abort(); - } - t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL; - t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; - return t; -# else -# error "Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?)." -# endif - } - - void reset() { - total_ns = 0; - } - - void begin() { - total_ns -= query(); - } - - void end() { - total_ns += query(); - } - - float sec() const { - return total_ns * 1e-9f; - } -#else - static int64_t query() { return 0; } - void reset() { } - void begin() { } - void end() { } - float sec() const { return 0; } -#endif -}; - -// simple API for quickly dumping values when debugging - -static inline void log_dump_val_worker(short v) { log("%d", v); } -static inline void log_dump_val_worker(unsigned short v) { log("%u", v); } -static inline void log_dump_val_worker(int v) { log("%d", v); } -static inline void log_dump_val_worker(unsigned int v) { log("%u", v); } -static inline void log_dump_val_worker(long int v) { log("%ld", v); } -static inline void log_dump_val_worker(unsigned long int v) { log("%lu", v); } -#ifndef _WIN32 -static inline void log_dump_val_worker(long long int v) { log("%lld", v); } -static inline void log_dump_val_worker(unsigned long long int v) { log("%lld", v); } -#endif -static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); } -static inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); } -static inline void log_dump_val_worker(bool v) { log("%s", v ? "true" : "false"); } -static inline void log_dump_val_worker(double v) { log("%f", v); } -static inline void log_dump_val_worker(char *v) { log("%s", v); } -static inline void log_dump_val_worker(const char *v) { log("%s", v); } -static inline void log_dump_val_worker(std::string v) { log("%s", v.c_str()); } -static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); } -static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { log_assert(*p == 0); } -void log_dump_val_worker(RTLIL::IdString v); -void log_dump_val_worker(RTLIL::SigSpec v); - -template -static inline void log_dump_val_worker(dict &v) { - log("{"); - bool first = true; - for (auto &it : v) { - log(first ? " " : ", "); - log_dump_val_worker(it.first); - log(": "); - log_dump_val_worker(it.second); - first = false; - } - log(" }"); -} - -template -static inline void log_dump_val_worker(pool &v) { - log("{"); - bool first = true; - for (auto &it : v) { - log(first ? " " : ", "); - log_dump_val_worker(it); - first = false; - } - log(" }"); -} - -template -static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); } - -template -void log_dump_args_worker(const char *p, T first, Args ... args) -{ - int next_p_state = 0; - const char *next_p = p; - while (*next_p && (next_p_state != 0 || *next_p != ',')) { - if (*next_p == '"') - do { - next_p++; - while (*next_p == '\\' && *(next_p + 1)) - next_p += 2; - } while (*next_p && *next_p != '"'); - if (*next_p == '\'') { - next_p++; - if (*next_p == '\\') - next_p++; - if (*next_p) - next_p++; - } - if (*next_p == '(' || *next_p == '[' || *next_p == '{') - next_p_state++; - if ((*next_p == ')' || *next_p == ']' || *next_p == '}') && next_p_state > 0) - next_p_state--; - next_p++; - } - log("\n\t%.*s => ", int(next_p - p), p); - if (*next_p == ',') - next_p++; - while (*next_p == ' ' || *next_p == '\t' || *next_p == '\r' || *next_p == '\n') - next_p++; - log_dump_val_worker(first); - log_dump_args_worker(next_p, args ...); -} - -#define log_dump(...) do { \ - log("DEBUG DUMP IN %s AT %s:%d:", __PRETTY_FUNCTION__, __FILE__, __LINE__); \ - log_dump_args_worker(#__VA_ARGS__, __VA_ARGS__); \ - log("\n"); \ -} while (0) - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/macc.h b/yosys/kernel/macc.h deleted file mode 100644 index 286ce567f..000000000 --- a/yosys/kernel/macc.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef MACC_H -#define MACC_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -struct Macc -{ - struct port_t { - RTLIL::SigSpec in_a, in_b; - bool is_signed, do_subtract; - }; - - std::vector ports; - RTLIL::SigSpec bit_ports; - - void optimize(int width) - { - std::vector new_ports; - RTLIL::SigSpec new_bit_ports; - RTLIL::Const off(0, width); - - for (auto &port : ports) - { - if (GetSize(port.in_a) == 0 && GetSize(port.in_b) == 0) - continue; - - 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)) - v = const_mul(v, port.in_b.as_const(), port.is_signed, port.is_signed, width); - if (port.do_subtract) - off = const_sub(off, v, port.is_signed, port.is_signed, width); - else - off = const_add(off, v, port.is_signed, port.is_signed, width); - continue; - } - - if (port.is_signed) { - while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == port.in_a[GetSize(port.in_a)-2]) - port.in_a.remove(GetSize(port.in_a)-1); - while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2]) - port.in_b.remove(GetSize(port.in_b)-1); - } else { - while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == RTLIL::S0) - port.in_a.remove(GetSize(port.in_a)-1); - while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == RTLIL::S0) - port.in_b.remove(GetSize(port.in_b)-1); - } - - new_ports.push_back(port); - } - - for (auto &bit : bit_ports) - if (bit == RTLIL::S1) - off = const_add(off, RTLIL::Const(1, width), false, false, width); - else if (bit != RTLIL::S0) - new_bit_ports.append(bit); - - if (off.as_bool()) { - port_t port; - port.in_a = off; - port.is_signed = false; - port.do_subtract = false; - new_ports.push_back(port); - } - - new_ports.swap(ports); - bit_ports = new_bit_ports; - } - - void from_cell(RTLIL::Cell *cell) - { - RTLIL::SigSpec port_a = cell->getPort("\\A"); - - ports.clear(); - bit_ports = cell->getPort("\\B"); - - std::vector config_bits = cell->getParam("\\CONFIG").bits; - int config_cursor = 0; - -#ifndef NDEBUG - int config_width = cell->getParam("\\CONFIG_WIDTH").as_int(); - log_assert(GetSize(config_bits) >= config_width); -#endif - - int num_bits = 0; - if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1; - if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 2; - if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 4; - if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8; - - int port_a_cursor = 0; - while (port_a_cursor < GetSize(port_a)) - { - log_assert(config_cursor + 2 + 2*num_bits <= config_width); - - port_t this_port; - this_port.is_signed = config_bits[config_cursor++] == RTLIL::S1; - this_port.do_subtract = config_bits[config_cursor++] == RTLIL::S1; - - int size_a = 0; - for (int i = 0; i < num_bits; i++) - if (config_bits[config_cursor++] == RTLIL::S1) - size_a |= 1 << i; - - this_port.in_a = port_a.extract(port_a_cursor, size_a); - port_a_cursor += size_a; - - int size_b = 0; - for (int i = 0; i < num_bits; i++) - if (config_bits[config_cursor++] == RTLIL::S1) - size_b |= 1 << i; - - this_port.in_b = port_a.extract(port_a_cursor, size_b); - port_a_cursor += size_b; - - if (size_a || size_b) - ports.push_back(this_port); - } - - log_assert(config_cursor == config_width); - log_assert(port_a_cursor == GetSize(port_a)); - } - - void to_cell(RTLIL::Cell *cell) const - { - RTLIL::SigSpec port_a; - std::vector config_bits; - int max_size = 0, num_bits = 0; - - for (auto &port : ports) { - max_size = max(max_size, GetSize(port.in_a)); - max_size = max(max_size, GetSize(port.in_b)); - } - - while (max_size) - num_bits++, max_size /= 2; - - log_assert(num_bits < 16); - config_bits.push_back(num_bits & 1 ? RTLIL::S1 : RTLIL::S0); - config_bits.push_back(num_bits & 2 ? RTLIL::S1 : RTLIL::S0); - config_bits.push_back(num_bits & 4 ? RTLIL::S1 : RTLIL::S0); - config_bits.push_back(num_bits & 8 ? RTLIL::S1 : RTLIL::S0); - - for (auto &port : ports) - { - if (GetSize(port.in_a) == 0) - continue; - - config_bits.push_back(port.is_signed ? RTLIL::S1 : RTLIL::S0); - config_bits.push_back(port.do_subtract ? RTLIL::S1 : RTLIL::S0); - - int size_a = GetSize(port.in_a); - for (int i = 0; i < num_bits; i++) - config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0); - - int size_b = GetSize(port.in_b); - for (int i = 0; i < num_bits; i++) - config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0); - - port_a.append(port.in_a); - port_a.append(port.in_b); - } - - cell->setPort("\\A", port_a); - cell->setPort("\\B", bit_ports); - cell->setParam("\\CONFIG", config_bits); - cell->setParam("\\CONFIG_WIDTH", GetSize(config_bits)); - cell->setParam("\\A_WIDTH", GetSize(port_a)); - cell->setParam("\\B_WIDTH", GetSize(bit_ports)); - } - - bool eval(RTLIL::Const &result) const - { - for (auto &bit : result.bits) - bit = RTLIL::S0; - - for (auto &port : ports) - { - if (!port.in_a.is_fully_const() || !port.in_b.is_fully_const()) - return false; - - RTLIL::Const summand; - if (GetSize(port.in_b) == 0) - summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result)); - else - summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result)); - - if (port.do_subtract) - result = const_sub(result, summand, port.is_signed, port.is_signed, GetSize(result)); - else - 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; - } - - Macc(RTLIL::Cell *cell = nullptr) - { - if (cell != nullptr) - from_cell(cell); - } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/modtools.h b/yosys/kernel/modtools.h deleted file mode 100644 index 409562eb9..000000000 --- a/yosys/kernel/modtools.h +++ /dev/null @@ -1,582 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef MODTOOLS_H -#define MODTOOLS_H - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" - -YOSYS_NAMESPACE_BEGIN - -struct ModIndex : public RTLIL::Monitor -{ - struct PortInfo { - RTLIL::Cell* cell; - RTLIL::IdString port; - int offset; - - PortInfo() : cell(), port(), offset() { } - PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { } - - bool operator<(const PortInfo &other) const { - if (cell != other.cell) - return cell < other.cell; - if (offset != other.offset) - return offset < other.offset; - return port < other.port; - } - - bool operator==(const PortInfo &other) const { - return cell == other.cell && port == other.port && offset == other.offset; - } - - unsigned int hash() const { - return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); - } - }; - - struct SigBitInfo - { - bool is_input, is_output; - pool ports; - - SigBitInfo() : is_input(false), is_output(false) { } - - bool operator==(const SigBitInfo &other) const { - return is_input == other.is_input && is_output == other.is_output && ports == other.ports; - } - - void merge(const SigBitInfo &other) - { - is_input = is_input || other.is_input; - is_output = is_output || other.is_output; - ports.insert(other.ports.begin(), other.ports.end()); - } - }; - - SigMap sigmap; - RTLIL::Module *module; - std::map database; - int auto_reload_counter; - bool auto_reload_module; - - void port_add(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig) - { - for (int i = 0; i < GetSize(sig); i++) { - RTLIL::SigBit bit = sigmap(sig[i]); - if (bit.wire) - database[bit].ports.insert(PortInfo(cell, port, i)); - } - } - - void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig) - { - for (int i = 0; i < GetSize(sig); i++) { - RTLIL::SigBit bit = sigmap(sig[i]); - if (bit.wire) - database[bit].ports.erase(PortInfo(cell, port, i)); - } - } - - const SigBitInfo &info(RTLIL::SigBit bit) - { - return database[sigmap(bit)]; - } - - void reload_module(bool reset_sigmap = true) - { - if (reset_sigmap) { - sigmap.clear(); - sigmap.set(module); - } - - database.clear(); - for (auto wire : module->wires()) - if (wire->port_input || wire->port_output) - for (int i = 0; i < GetSize(wire); i++) { - RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i)); - if (bit.wire && wire->port_input) - database[bit].is_input = true; - if (bit.wire && wire->port_output) - database[bit].is_output = true; - } - for (auto cell : module->cells()) - for (auto &conn : cell->connections()) - port_add(cell, conn.first, conn.second); - - if (auto_reload_module) { - if (++auto_reload_counter > 2) - log_warning("Auto-reload in ModIndex -- possible performance bug!\n"); - auto_reload_module = false; - } - } - - void check() - { -#ifndef NDEBUG - if (auto_reload_module) - return; - - for (auto it : database) - log_assert(it.first == sigmap(it.first)); - - auto database_bak = std::move(database); - reload_module(false); - - if (!(database == database_bak)) - { - for (auto &it : database_bak) - if (!database.count(it.first)) - log("ModuleIndex::check(): Only in database_bak, not database: %s\n", log_signal(it.first)); - - for (auto &it : database) - if (!database_bak.count(it.first)) - log("ModuleIndex::check(): Only in database, not database_bak: %s\n", log_signal(it.first)); - else if (!(it.second == database_bak.at(it.first))) - log("ModuleIndex::check(): Different content for database[%s].\n", log_signal(it.first)); - - log_assert(database == database_bak); - } -#endif - } - - void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE - { - log_assert(module == cell->module); - - if (auto_reload_module) - return; - - port_del(cell, port, old_sig); - port_add(cell, port, sig); - } - - void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE - { - log_assert(module == mod); - - if (auto_reload_module) - return; - - for (int i = 0; i < GetSize(sigsig.first); i++) - { - RTLIL::SigBit lhs = sigmap(sigsig.first[i]); - RTLIL::SigBit rhs = sigmap(sigsig.second[i]); - bool has_lhs = database.count(lhs) != 0; - bool has_rhs = database.count(rhs) != 0; - - if (!has_lhs && !has_rhs) { - sigmap.add(lhs, rhs); - } else - if (!has_rhs) { - SigBitInfo new_info = database.at(lhs); - database.erase(lhs); - sigmap.add(lhs, rhs); - lhs = sigmap(lhs); - if (lhs.wire) - database[lhs] = new_info; - } else - if (!has_lhs) { - SigBitInfo new_info = database.at(rhs); - database.erase(rhs); - sigmap.add(lhs, rhs); - rhs = sigmap(rhs); - if (rhs.wire) - database[rhs] = new_info; - } else { - SigBitInfo new_info = database.at(lhs); - new_info.merge(database.at(rhs)); - database.erase(lhs); - database.erase(rhs); - sigmap.add(lhs, rhs); - rhs = sigmap(rhs); - if (rhs.wire) - database[rhs] = new_info; - } - } - } - - void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector&) YS_OVERRIDE - { - log_assert(module == mod); - auto_reload_module = true; - } - - void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE - { - log_assert(module == mod); - auto_reload_module = true; - } - - ModIndex(RTLIL::Module *_m) : sigmap(_m), module(_m) - { - auto_reload_counter = 0; - auto_reload_module = true; - module->monitors.insert(this); - } - - ~ModIndex() - { - module->monitors.erase(this); - } - - SigBitInfo *query(RTLIL::SigBit bit) - { - if (auto_reload_module) - reload_module(); - - auto it = database.find(sigmap(bit)); - if (it == database.end()) - return nullptr; - else - return &it->second; - } - - bool query_is_input(RTLIL::SigBit bit) - { - const SigBitInfo *info = query(bit); - if (info == nullptr) - return false; - return info->is_input; - } - - bool query_is_output(RTLIL::SigBit bit) - { - const SigBitInfo *info = query(bit); - if (info == nullptr) - return false; - return info->is_output; - } - - pool &query_ports(RTLIL::SigBit bit) - { - static pool empty_result_set; - SigBitInfo *info = query(bit); - if (info == nullptr) - return empty_result_set; - return info->ports; - } - - void dump_db() - { - log("--- ModIndex Dump ---\n"); - - if (auto_reload_module) { - log("AUTO-RELOAD\n"); - reload_module(); - } - - for (auto &it : database) { - log("BIT %s:\n", log_signal(it.first)); - if (it.second.is_input) - log(" PRIMARY INPUT\n"); - if (it.second.is_output) - log(" PRIMARY OUTPUT\n"); - for (auto &port : it.second.ports) - log(" PORT: %s.%s[%d] (%s)\n", log_id(port.cell), - log_id(port.port), port.offset, log_id(port.cell->type)); - } - } -}; - -struct ModWalker -{ - struct PortBit - { - RTLIL::Cell *cell; - RTLIL::IdString port; - int offset; - - bool operator<(const PortBit &other) const { - if (cell != other.cell) - return cell < other.cell; - if (port != other.port) - return port < other.port; - return offset < other.offset; - } - - bool operator==(const PortBit &other) const { - return cell == other.cell && port == other.port && offset == other.offset; - } - - unsigned int hash() const { - return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); - } - }; - - RTLIL::Design *design; - RTLIL::Module *module; - - CellTypes ct; - SigMap sigmap; - - dict> signal_drivers; - dict> signal_consumers; - pool signal_inputs, signal_outputs; - - dict> cell_outputs, cell_inputs; - - void add_wire(RTLIL::Wire *wire) - { - if (wire->port_input) { - std::vector bits = sigmap(wire); - for (auto bit : bits) - if (bit.wire != NULL) - signal_inputs.insert(bit); - } - - if (wire->port_output) { - std::vector bits = sigmap(wire); - for (auto bit : bits) - if (bit.wire != NULL) - signal_outputs.insert(bit); - } - } - - void add_cell_port(RTLIL::Cell *cell, RTLIL::IdString port, std::vector bits, bool is_output, bool is_input) - { - for (int i = 0; i < int(bits.size()); i++) - if (bits[i].wire != NULL) { - PortBit pbit = { cell, port, i }; - if (is_output) { - signal_drivers[bits[i]].insert(pbit); - cell_outputs[cell].insert(bits[i]); - } - if (is_input) { - signal_consumers[bits[i]].insert(pbit); - cell_inputs[cell].insert(bits[i]); - } - } - } - - void add_cell(RTLIL::Cell *cell) - { - if (ct.cell_known(cell->type)) { - for (auto &conn : cell->connections()) - add_cell_port(cell, conn.first, sigmap(conn.second), - ct.cell_output(cell->type, conn.first), - ct.cell_input(cell->type, conn.first)); - } else { - for (auto &conn : cell->connections()) - add_cell_port(cell, conn.first, sigmap(conn.second), true, true); - } - } - - ModWalker() : design(NULL), module(NULL) - { - } - - ModWalker(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL) - { - setup(design, module, filter_ct); - } - - void setup(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL) - { - this->design = design; - this->module = module; - - ct.clear(); - ct.setup(design); - sigmap.set(module); - - signal_drivers.clear(); - signal_consumers.clear(); - signal_inputs.clear(); - signal_outputs.clear(); - - for (auto &it : module->wires_) - add_wire(it.second); - for (auto &it : module->cells_) - if (filter_ct == NULL || filter_ct->cell_known(it.second->type)) - add_cell(it.second); - } - - // get_* methods -- single RTLIL::SigBit - - template - inline bool get_drivers(pool &result, RTLIL::SigBit bit) const - { - bool found = false; - if (signal_drivers.count(bit)) { - const pool &r = signal_drivers.at(bit); - result.insert(r.begin(), r.end()); - found = true; - } - return found; - } - - template - inline bool get_consumers(pool &result, RTLIL::SigBit bit) const - { - bool found = false; - if (signal_consumers.count(bit)) { - const pool &r = signal_consumers.at(bit); - result.insert(r.begin(), r.end()); - found = true; - } - return found; - } - - template - inline bool get_inputs(pool &result, RTLIL::SigBit bit) const - { - bool found = false; - if (signal_inputs.count(bit)) - result.insert(bit), found = true; - return found; - } - - template - inline bool get_outputs(pool &result, RTLIL::SigBit bit) const - { - bool found = false; - if (signal_outputs.count(bit)) - result.insert(bit), found = true; - return found; - } - - // get_* methods -- container of RTLIL::SigBit's (always by reference) - - template - inline bool get_drivers(pool &result, const T &bits) const - { - bool found = false; - for (RTLIL::SigBit bit : bits) - if (signal_drivers.count(bit)) { - const pool &r = signal_drivers.at(bit); - result.insert(r.begin(), r.end()); - found = true; - } - return found; - } - - template - inline bool get_consumers(pool &result, const T &bits) const - { - bool found = false; - for (RTLIL::SigBit bit : bits) - if (signal_consumers.count(bit)) { - const pool &r = signal_consumers.at(bit); - result.insert(r.begin(), r.end()); - found = true; - } - return found; - } - - template - inline bool get_inputs(pool &result, const T &bits) const - { - bool found = false; - for (RTLIL::SigBit bit : bits) - if (signal_inputs.count(bit)) - result.insert(bit), found = true; - return found; - } - - template - inline bool get_outputs(pool &result, const T &bits) const - { - bool found = false; - for (RTLIL::SigBit bit : bits) - if (signal_outputs.count(bit)) - result.insert(bit), found = true; - return found; - } - - // get_* methods -- call by RTLIL::SigSpec (always by value) - - bool get_drivers(pool &result, RTLIL::SigSpec signal) const - { - std::vector bits = sigmap(signal); - return get_drivers(result, bits); - } - - bool get_consumers(pool &result, RTLIL::SigSpec signal) const - { - std::vector bits = sigmap(signal); - return get_consumers(result, bits); - } - - bool get_inputs(pool &result, RTLIL::SigSpec signal) const - { - std::vector bits = sigmap(signal); - return get_inputs(result, bits); - } - - bool get_outputs(pool &result, RTLIL::SigSpec signal) const - { - std::vector bits = sigmap(signal); - return get_outputs(result, bits); - } - - // has_* methods -- call by reference - - template - inline bool has_drivers(const T &sig) const { - pool result; - return get_drivers(result, sig); - } - - template - inline bool has_consumers(const T &sig) const { - pool result; - return get_consumers(result, sig); - } - - template - inline bool has_inputs(const T &sig) const { - pool result; - return get_inputs(result, sig); - } - - template - inline bool has_outputs(const T &sig) const { - pool result; - return get_outputs(result, sig); - } - - // has_* methods -- call by value - - inline bool has_drivers(RTLIL::SigSpec sig) const { - pool result; - return get_drivers(result, sig); - } - - inline bool has_consumers(RTLIL::SigSpec sig) const { - pool result; - return get_consumers(result, sig); - } - - inline bool has_inputs(RTLIL::SigSpec sig) const { - pool result; - return get_inputs(result, sig); - } - - inline bool has_outputs(RTLIL::SigSpec sig) const { - pool result; - return get_outputs(result, sig); - } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/register.cc b/yosys/kernel/register.cc deleted file mode 100644 index 26da96b95..000000000 --- a/yosys/kernel/register.cc +++ /dev/null @@ -1,818 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/satgen.h" - -#include -#include -#include -#include - -YOSYS_NAMESPACE_BEGIN - -#define MAX_REG_COUNT 1000 - -bool echo_mode = false; -Pass *first_queued_pass; -Pass *current_pass; - -std::map frontend_register; -std::map pass_register; -std::map backend_register; - -std::vector Frontend::next_args; - -Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help) -{ - next_queued_pass = first_queued_pass; - first_queued_pass = this; - call_counter = 0; - runtime_ns = 0; -} - -void Pass::run_register() -{ - log_assert(pass_register.count(pass_name) == 0); - pass_register[pass_name] = this; -} - -void Pass::init_register() -{ - while (first_queued_pass) { - first_queued_pass->run_register(); - first_queued_pass = first_queued_pass->next_queued_pass; - } -} - -void Pass::done_register() -{ - frontend_register.clear(); - pass_register.clear(); - backend_register.clear(); - log_assert(first_queued_pass == NULL); -} - -Pass::~Pass() -{ -} - -Pass::pre_post_exec_state_t Pass::pre_execute() -{ - pre_post_exec_state_t state; - call_counter++; - state.begin_ns = PerformanceTimer::query(); - state.parent_pass = current_pass; - current_pass = this; - clear_flags(); - return state; -} - -void Pass::post_execute(Pass::pre_post_exec_state_t state) -{ - IdString::checkpoint(); - log_suppressed(); - - int64_t time_ns = PerformanceTimer::query() - state.begin_ns; - runtime_ns += time_ns; - current_pass = state.parent_pass; - if (current_pass) - current_pass->runtime_ns -= time_ns; -} - -void Pass::help() -{ - log("\n"); - log("No help message for command `%s'.\n", pass_name.c_str()); - log("\n"); -} - -void Pass::clear_flags() -{ -} - -void Pass::cmd_log_args(const std::vector &args) -{ - if (args.size() <= 1) - return; - log("Full command line:"); - for (size_t i = 0; i < args.size(); i++) - log(" %s", args[i].c_str()); - log("\n"); -} - -void Pass::cmd_error(const std::vector &args, size_t argidx, std::string msg) -{ - std::string command_text; - int error_pos = 0; - - for (size_t i = 0; i < args.size(); i++) { - if (i < argidx) - error_pos += args[i].size() + 1; - command_text = command_text + (command_text.empty() ? "" : " ") + args[i]; - } - - log("\nSyntax error in command `%s':\n", command_text.c_str()); - help(); - - log_cmd_error("Command syntax error: %s\n> %s\n> %*s^\n", - msg.c_str(), command_text.c_str(), error_pos, ""); -} - -void Pass::extra_args(std::vector args, size_t argidx, RTLIL::Design *design, bool select) -{ - for (; argidx < args.size(); argidx++) - { - std::string arg = args[argidx]; - - if (arg.substr(0, 1) == "-") - cmd_error(args, argidx, "Unknown option or option in arguments."); - - if (!select) - cmd_error(args, argidx, "Extra argument."); - - handle_extra_select_args(this, args, argidx, args.size(), design); - break; - } - // cmd_log_args(args); -} - -void Pass::call(RTLIL::Design *design, std::string command) -{ - std::vector args; - - std::string cmd_buf = command; - std::string tok = next_token(cmd_buf, " \t\r\n", true); - - if (tok.empty()) - return; - - if (tok[0] == '!') { - cmd_buf = command.substr(command.find('!') + 1); - while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' || - cmd_buf.back() == '\r' || cmd_buf.back() == '\n')) - cmd_buf.resize(cmd_buf.size()-1); - log_header(design, "Shell command: %s\n", cmd_buf.c_str()); - int retCode = run_command(cmd_buf); - if (retCode != 0) - log_cmd_error("Shell command returned error code %d.\n", retCode); - return; - } - - while (!tok.empty()) { - if (tok[0] == '#') { - int stop; - for (stop = 0; stop < GetSize(cmd_buf); stop++) - if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n') - break; - cmd_buf = cmd_buf.substr(stop); - } else - if (tok.back() == ';') { - int num_semikolon = 0; - while (!tok.empty() && tok.back() == ';') - tok.resize(tok.size()-1), num_semikolon++; - if (!tok.empty()) - args.push_back(tok); - call(design, args); - args.clear(); - if (num_semikolon == 2) - call(design, "clean"); - if (num_semikolon == 3) - call(design, "clean -purge"); - } else - args.push_back(tok); - bool found_nl = false; - for (auto c : cmd_buf) { - if (c == ' ' || c == '\t') - continue; - if (c == '\r' || c == '\n') - found_nl = true; - break; - } - if (found_nl) { - call(design, args); - args.clear(); - } - tok = next_token(cmd_buf, " \t\r\n", true); - } - - call(design, args); -} - -void Pass::call(RTLIL::Design *design, std::vector args) -{ - if (args.size() == 0 || args[0][0] == '#' || args[0][0] == ':') - return; - - if (echo_mode) { - log("%s", create_prompt(design, 0)); - for (size_t i = 0; i < args.size(); i++) - log("%s%s", i ? " " : "", args[i].c_str()); - log("\n"); - } - - if (pass_register.count(args[0]) == 0) - log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str()); - - size_t orig_sel_stack_pos = design->selection_stack.size(); - auto state = pass_register[args[0]]->pre_execute(); - pass_register[args[0]]->execute(args, design); - pass_register[args[0]]->post_execute(state); - while (design->selection_stack.size() > orig_sel_stack_pos) - design->selection_stack.pop_back(); - - design->check(); -} - -void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command) -{ - std::string backup_selected_active_module = design->selected_active_module; - design->selected_active_module.clear(); - design->selection_stack.push_back(selection); - - Pass::call(design, command); - - design->selection_stack.pop_back(); - design->selected_active_module = backup_selected_active_module; -} - -void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector args) -{ - std::string backup_selected_active_module = design->selected_active_module; - design->selected_active_module.clear(); - design->selection_stack.push_back(selection); - - Pass::call(design, args); - - design->selection_stack.pop_back(); - design->selected_active_module = backup_selected_active_module; -} - -void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command) -{ - std::string backup_selected_active_module = design->selected_active_module; - design->selected_active_module = module->name.str(); - design->selection_stack.push_back(RTLIL::Selection(false)); - design->selection_stack.back().select(module); - - Pass::call(design, command); - - design->selection_stack.pop_back(); - design->selected_active_module = backup_selected_active_module; -} - -void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector args) -{ - std::string backup_selected_active_module = design->selected_active_module; - design->selected_active_module = module->name.str(); - design->selection_stack.push_back(RTLIL::Selection(false)); - design->selection_stack.back().select(module); - - Pass::call(design, args); - - design->selection_stack.pop_back(); - design->selected_active_module = backup_selected_active_module; -} - -bool ScriptPass::check_label(std::string label, std::string info) -{ - if (active_design == nullptr) { - log("\n"); - if (info.empty()) - log(" %s:\n", label.c_str()); - else - log(" %s: %s\n", label.c_str(), info.c_str()); - return true; - } else { - if (!active_run_from.empty() && active_run_from == active_run_to) { - block_active = (label == active_run_from); - } else { - if (label == active_run_from) - block_active = true; - if (label == active_run_to) - block_active = false; - } - return block_active; - } -} - -void ScriptPass::run(std::string command, std::string info) -{ - if (active_design == nullptr) { - if (info.empty()) - log(" %s\n", command.c_str()); - else - log(" %s %s\n", command.c_str(), info.c_str()); - } else - Pass::call(active_design, command); -} - -void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) -{ - help_mode = false; - active_design = design; - block_active = run_from.empty(); - active_run_from = run_from; - active_run_to = run_to; - script(); -} - -void ScriptPass::help_script() -{ - clear_flags(); - help_mode = true; - active_design = nullptr; - block_active = true; - active_run_from.clear(); - active_run_to.clear(); - script(); -} - -Frontend::Frontend(std::string name, std::string short_help) : - Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help), - frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) -{ -} - -void Frontend::run_register() -{ - log_assert(pass_register.count(pass_name) == 0); - pass_register[pass_name] = this; - - log_assert(frontend_register.count(frontend_name) == 0); - frontend_register[frontend_name] = this; -} - -Frontend::~Frontend() -{ -} - -void Frontend::execute(std::vector args, RTLIL::Design *design) -{ - log_assert(next_args.empty()); - do { - std::istream *f = NULL; - next_args.clear(); - auto state = pre_execute(); - execute(f, std::string(), args, design); - post_execute(state); - args = next_args; - delete f; - } while (!args.empty()); -} - -FILE *Frontend::current_script_file = NULL; -std::string Frontend::last_here_document; - -void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector args, size_t argidx) -{ - bool called_with_fp = f != NULL; - - next_args.clear(); - - if (argidx < args.size()) - { - std::string arg = args[argidx]; - - if (arg.substr(0, 1) == "-") - cmd_error(args, argidx, "Unknown option or option in arguments."); - if (f != NULL) - cmd_error(args, argidx, "Extra filename argument in direct file mode."); - - filename = arg; - if (filename == "<<" && argidx+1 < args.size()) - filename += args[++argidx]; - if (filename.substr(0, 2) == "<<") { - if (Frontend::current_script_file == NULL) - log_error("Unexpected here document '%s' outside of script!\n", filename.c_str()); - if (filename.size() <= 2) - log_error("Missing EOT marker in here document!\n"); - std::string eot_marker = filename.substr(2); - last_here_document.clear(); - while (1) { - std::string buffer; - char block[4096]; - while (1) { - if (fgets(block, 4096, Frontend::current_script_file) == NULL) - log_error("Unexpected end of file in here document '%s'!\n", filename.c_str()); - buffer += block; - if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r')) - break; - } - size_t indent = buffer.find_first_not_of(" \t\r\n"); - if (indent != std::string::npos && buffer.substr(indent, eot_marker.size()) == eot_marker) - break; - last_here_document += buffer; - } - f = new std::istringstream(last_here_document); - } else { - rewrite_filename(filename); - vector filenames = glob_filename(filename); - filename = filenames.front(); - if (GetSize(filenames) > 1) { - next_args.insert(next_args.end(), args.begin(), args.begin()+argidx); - next_args.insert(next_args.end(), filenames.begin()+1, filenames.end()); - } - std::ifstream *ff = new std::ifstream; - ff->open(filename.c_str()); - yosys_input_files.insert(filename); - if (ff->fail()) - delete ff; - else - f = ff; - } - if (f == NULL) - log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); - - for (size_t i = argidx+1; i < args.size(); i++) - if (args[i].substr(0, 1) == "-") - cmd_error(args, i, "Found option, expected arguments."); - - if (argidx+1 < args.size()) { - if (next_args.empty()) - next_args.insert(next_args.end(), args.begin(), args.begin()+argidx); - next_args.insert(next_args.end(), args.begin()+argidx+1, args.end()); - args.erase(args.begin()+argidx+1, args.end()); - } - } - - if (f == NULL) - cmd_error(args, argidx, "No filename given."); - - if (called_with_fp) - args.push_back(filename); - args[0] = pass_name; - // cmd_log_args(args); -} - -void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command) -{ - std::vector args; - char *s = strdup(command.c_str()); - for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n")) - args.push_back(p); - free(s); - frontend_call(design, f, filename, args); -} - -void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector args) -{ - if (args.size() == 0) - return; - if (frontend_register.count(args[0]) == 0) - log_cmd_error("No such frontend: %s\n", args[0].c_str()); - - if (f != NULL) { - auto state = frontend_register[args[0]]->pre_execute(); - frontend_register[args[0]]->execute(f, filename, args, design); - frontend_register[args[0]]->post_execute(state); - } else if (filename == "-") { - std::istream *f_cin = &std::cin; - auto state = frontend_register[args[0]]->pre_execute(); - frontend_register[args[0]]->execute(f_cin, "", args, design); - frontend_register[args[0]]->post_execute(state); - } else { - if (!filename.empty()) - args.push_back(filename); - frontend_register[args[0]]->execute(args, design); - } - - design->check(); -} - -Backend::Backend(std::string name, std::string short_help) : - Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help), - backend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) -{ -} - -void Backend::run_register() -{ - log_assert(pass_register.count(pass_name) == 0); - pass_register[pass_name] = this; - - log_assert(backend_register.count(backend_name) == 0); - backend_register[backend_name] = this; -} - -Backend::~Backend() -{ -} - -void Backend::execute(std::vector args, RTLIL::Design *design) -{ - std::ostream *f = NULL; - auto state = pre_execute(); - execute(f, std::string(), args, design); - post_execute(state); - if (f != &std::cout) - delete f; -} - -void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector args, size_t argidx) -{ - bool called_with_fp = f != NULL; - - for (; argidx < args.size(); argidx++) - { - std::string arg = args[argidx]; - - if (arg.substr(0, 1) == "-" && arg != "-") - cmd_error(args, argidx, "Unknown option or option in arguments."); - if (f != NULL) - cmd_error(args, argidx, "Extra filename argument in direct file mode."); - - if (arg == "-") { - filename = ""; - f = &std::cout; - continue; - } - - filename = arg; - rewrite_filename(filename); - std::ofstream *ff = new std::ofstream; - ff->open(filename.c_str(), std::ofstream::trunc); - yosys_output_files.insert(filename); - if (ff->fail()) { - delete ff; - log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); - } - f = ff; - } - - if (called_with_fp) - args.push_back(filename); - args[0] = pass_name; - // cmd_log_args(args); - - if (f == NULL) { - filename = ""; - f = &std::cout; - } -} - -void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command) -{ - std::vector args; - char *s = strdup(command.c_str()); - for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n")) - args.push_back(p); - free(s); - backend_call(design, f, filename, args); -} - -void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector args) -{ - if (args.size() == 0) - return; - if (backend_register.count(args[0]) == 0) - log_cmd_error("No such backend: %s\n", args[0].c_str()); - - size_t orig_sel_stack_pos = design->selection_stack.size(); - - if (f != NULL) { - auto state = backend_register[args[0]]->pre_execute(); - backend_register[args[0]]->execute(f, filename, args, design); - backend_register[args[0]]->post_execute(state); - } else if (filename == "-") { - std::ostream *f_cout = &std::cout; - auto state = backend_register[args[0]]->pre_execute(); - backend_register[args[0]]->execute(f_cout, "", args, design); - backend_register[args[0]]->post_execute(state); - } else { - if (!filename.empty()) - args.push_back(filename); - backend_register[args[0]]->execute(args, design); - } - - while (design->selection_stack.size() > orig_sel_stack_pos) - design->selection_stack.pop_back(); - - design->check(); -} - -static struct CellHelpMessages { - dict cell_help, cell_code; - CellHelpMessages() { -#include "techlibs/common/simlib_help.inc" -#include "techlibs/common/simcells_help.inc" - cell_help.sort(); - cell_code.sort(); - } -} cell_help_messages; - -struct HelpPass : public Pass { - HelpPass() : Pass("help", "display help messages") { } - void help() YS_OVERRIDE - { - log("\n"); - log(" help ................ list all commands\n"); - log(" help ...... print help message for given command\n"); - log(" help -all ........... print complete command reference\n"); - log("\n"); - log(" help -cells .......... list all cell types\n"); - log(" help ..... print help message for given cell type\n"); - log(" help + .... print verilog code for given cell type\n"); - log("\n"); - } - void escape_tex(std::string &tex) - { - for (size_t pos = 0; (pos = tex.find('_', pos)) != std::string::npos; pos += 2) - tex.replace(pos, 1, "\\_"); - for (size_t pos = 0; (pos = tex.find('$', pos)) != std::string::npos; pos += 2) - tex.replace(pos, 1, "\\$"); - } - void write_tex(FILE *f, std::string cmd, std::string title, std::string text) - { - size_t begin = text.find_first_not_of("\n"), end = text.find_last_not_of("\n"); - if (begin != std::string::npos && end != std::string::npos && begin < end) - text = text.substr(begin, end-begin+1); - std::string cmd_unescaped = cmd; - escape_tex(cmd); - escape_tex(title); - fprintf(f, "\\section{%s -- %s}\n", cmd.c_str(), title.c_str()); - fprintf(f, "\\label{cmd:%s}\n", cmd_unescaped.c_str()); - fprintf(f, "\\begin{lstlisting}[numbers=left,frame=single]\n"); - fprintf(f, "%s\n\\end{lstlisting}\n\n", text.c_str()); - } - void escape_html(std::string &html) - { - size_t pos = 0; - while ((pos = html.find_first_of("<>&", pos)) != std::string::npos) - switch (html[pos]) { - case '<': - html.replace(pos, 1, "<"); - pos += 4; - break; - case '>': - html.replace(pos, 1, ">"); - pos += 4; - break; - case '&': - html.replace(pos, 1, "&"); - pos += 5; - break; - } - } - void write_html(FILE *idxf, std::string cmd, std::string title, std::string text) - { - FILE *f = fopen(stringf("cmd_%s.in", cmd.c_str()).c_str(), "wt"); - fprintf(idxf, "

  • ", cmd.c_str()); - - escape_html(cmd); - escape_html(title); - escape_html(text); - - fprintf(idxf, "%s %s\n", cmd.c_str(), title.c_str()); - - fprintf(f, "@cmd_header %s@\n", cmd.c_str()); - fprintf(f, "

    %s - %s

    \n", cmd.c_str(), title.c_str()); - fprintf(f, "
    %s
    \n", text.c_str()); - fprintf(f, "@footer@\n"); - - fclose(f); - } - void execute(std::vector args, RTLIL::Design*) YS_OVERRIDE - { - if (args.size() == 1) { - log("\n"); - for (auto &it : pass_register) - log(" %-20s %s\n", it.first.c_str(), it.second->short_help.c_str()); - log("\n"); - log("Type 'help ' for more information on a command.\n"); - log("Type 'help -cells' for a list of all cell types.\n"); - log("\n"); - return; - } - - if (args.size() == 2) { - if (args[1] == "-all") { - for (auto &it : pass_register) { - log("\n\n"); - log("%s -- %s\n", it.first.c_str(), it.second->short_help.c_str()); - for (size_t i = 0; i < it.first.size() + it.second->short_help.size() + 6; i++) - log("="); - log("\n"); - it.second->help(); - } - } - else if (args[1] == "-cells") { - log("\n"); - for (auto &it : cell_help_messages.cell_help) { - string line = split_tokens(it.second, "\n").at(0); - string cell_name = next_token(line); - log(" %-15s %s\n", cell_name.c_str(), line.c_str()); - } - log("\n"); - log("Type 'help ' for more information on a cell type.\n"); - log("\n"); - return; - } - // this option is undocumented as it is for internal use only - else if (args[1] == "-write-tex-command-reference-manual") { - FILE *f = fopen("command-reference-manual.tex", "wt"); - fprintf(f, "%% Generated using the yosys 'help -write-tex-command-reference-manual' command.\n\n"); - for (auto &it : pass_register) { - std::ostringstream buf; - log_streams.push_back(&buf); - it.second->help(); - log_streams.pop_back(); - write_tex(f, it.first, it.second->short_help, buf.str()); - } - fclose(f); - } - // this option is undocumented as it is for internal use only - else if (args[1] == "-write-web-command-reference-manual") { - FILE *f = fopen("templates/cmd_index.in", "wt"); - for (auto &it : pass_register) { - std::ostringstream buf; - log_streams.push_back(&buf); - it.second->help(); - log_streams.pop_back(); - write_html(f, it.first, it.second->short_help, buf.str()); - } - fclose(f); - } - else if (pass_register.count(args[1])) { - pass_register.at(args[1])->help(); - } - else if (cell_help_messages.cell_help.count(args[1])) { - log("%s", cell_help_messages.cell_help.at(args[1]).c_str()); - log("Run 'help %s+' to display the Verilog model for this cell type.\n", args[1].c_str()); - log("\n"); - } - else if (cell_help_messages.cell_code.count(args[1])) { - log("\n"); - log("%s", cell_help_messages.cell_code.at(args[1]).c_str()); - } - else - log("No such command or cell type: %s\n", args[1].c_str()); - return; - } - - help(); - } -} HelpPass; - -struct EchoPass : public Pass { - EchoPass() : Pass("echo", "turning echoing back of commands on and off") { } - void help() YS_OVERRIDE - { - log("\n"); - log(" echo on\n"); - log("\n"); - log("Print all commands to log before executing them.\n"); - log("\n"); - log("\n"); - log(" echo off\n"); - log("\n"); - log("Do not print all commands to log before executing them. (default)\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design*) YS_OVERRIDE - { - if (args.size() > 2) - cmd_error(args, 2, "Unexpected argument."); - - if (args.size() == 2) { - if (args[1] == "on") - echo_mode = true; - else if (args[1] == "off") - echo_mode = false; - else - cmd_error(args, 1, "Unexpected argument."); - } - - log("echo %s\n", echo_mode ? "on" : "off"); - } -} EchoPass; - -SatSolver *yosys_satsolver_list; -SatSolver *yosys_satsolver; - -struct MinisatSatSolver : public SatSolver { - MinisatSatSolver() : SatSolver("minisat") { - yosys_satsolver = this; - } - ezSAT *create() YS_OVERRIDE { - return new ezMiniSAT(); - } -} MinisatSatSolver; - -YOSYS_NAMESPACE_END diff --git a/yosys/kernel/register.h b/yosys/kernel/register.h deleted file mode 100644 index c74029823..000000000 --- a/yosys/kernel/register.h +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" - -#ifndef REGISTER_H -#define REGISTER_H - -YOSYS_NAMESPACE_BEGIN - -struct Pass -{ - std::string pass_name, short_help; - Pass(std::string name, std::string short_help = "** document me **"); - virtual ~Pass(); - - virtual void help(); - virtual void clear_flags(); - virtual void execute(std::vector args, RTLIL::Design *design) = 0; - - int call_counter; - int64_t runtime_ns; - - struct pre_post_exec_state_t { - Pass *parent_pass; - int64_t begin_ns; - }; - - pre_post_exec_state_t pre_execute(); - void post_execute(pre_post_exec_state_t state); - - void cmd_log_args(const std::vector &args); - void cmd_error(const std::vector &args, size_t argidx, std::string msg); - void extra_args(std::vector args, size_t argidx, RTLIL::Design *design, bool select = true); - - static void call(RTLIL::Design *design, std::string command); - static void call(RTLIL::Design *design, std::vector args); - - static void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command); - static void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector args); - - static void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command); - static void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector args); - - Pass *next_queued_pass; - virtual void run_register(); - static void init_register(); - static void done_register(); -}; - -struct ScriptPass : Pass -{ - bool block_active, help_mode; - RTLIL::Design *active_design; - std::string active_run_from, active_run_to; - - ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { } - - virtual void script() = 0; - - bool check_label(std::string label, std::string info = std::string()); - void run(std::string command, std::string info = std::string()); - void run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string()); - void help_script(); -}; - -struct Frontend : Pass -{ - // for reading of here documents - static FILE *current_script_file; - static std::string last_here_document; - - std::string frontend_name; - Frontend(std::string name, std::string short_help = "** document me **"); - void run_register() YS_OVERRIDE; - ~Frontend() YS_OVERRIDE; - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; - virtual void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) = 0; - - static std::vector next_args; - void extra_args(std::istream *&f, std::string &filename, std::vector args, size_t argidx); - - static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command); - static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector args); -}; - -struct Backend : Pass -{ - std::string backend_name; - Backend(std::string name, std::string short_help = "** document me **"); - void run_register() YS_OVERRIDE; - ~Backend() YS_OVERRIDE; - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; - virtual void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) = 0; - - void extra_args(std::ostream *&f, std::string &filename, std::vector args, size_t argidx); - - static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command); - static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector args); -}; - -// implemented in passes/cmds/select.cc -extern void handle_extra_select_args(Pass *pass, std::vector args, size_t argidx, size_t args_size, RTLIL::Design *design); -extern RTLIL::Selection eval_select_args(const vector &args, RTLIL::Design *design); -extern void eval_select_op(vector &work, const string &op, RTLIL::Design *design); - -extern std::map pass_register; -extern std::map frontend_register; -extern std::map backend_register; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/rtlil.cc b/yosys/kernel/rtlil.cc deleted file mode 100644 index a09f4a0d1..000000000 --- a/yosys/kernel/rtlil.cc +++ /dev/null @@ -1,4081 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/macc.h" -#include "kernel/celltypes.h" -#include "frontends/verilog/verilog_frontend.h" -#include "backends/ilang/ilang_backend.h" - -#include -#include - -YOSYS_NAMESPACE_BEGIN - -RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard; -std::vector RTLIL::IdString::global_refcount_storage_; -std::vector RTLIL::IdString::global_id_storage_; -dict RTLIL::IdString::global_id_index_; -std::vector RTLIL::IdString::global_free_idx_list_; -int RTLIL::IdString::last_created_idx_[8]; -int RTLIL::IdString::last_created_idx_ptr_; - -RTLIL::Const::Const() -{ - flags = RTLIL::CONST_FLAG_NONE; -} - -RTLIL::Const::Const(std::string str) -{ - flags = RTLIL::CONST_FLAG_STRING; - for (int i = str.size()-1; i >= 0; i--) { - unsigned char ch = str[i]; - for (int j = 0; j < 8; j++) { - bits.push_back((ch & 1) != 0 ? RTLIL::S1 : RTLIL::S0); - ch = ch >> 1; - } - } -} - -RTLIL::Const::Const(int val, int width) -{ - flags = RTLIL::CONST_FLAG_NONE; - for (int i = 0; i < width; i++) { - bits.push_back((val & 1) != 0 ? RTLIL::S1 : RTLIL::S0); - val = val >> 1; - } -} - -RTLIL::Const::Const(RTLIL::State bit, int width) -{ - flags = RTLIL::CONST_FLAG_NONE; - for (int i = 0; i < width; i++) - bits.push_back(bit); -} - -RTLIL::Const::Const(const std::vector &bits) -{ - flags = RTLIL::CONST_FLAG_NONE; - for (auto b : bits) - this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0); -} - -RTLIL::Const::Const(const RTLIL::Const &c) -{ - flags = c.flags; - for (auto b : c.bits) - this->bits.push_back(b); -} - -bool RTLIL::Const::operator <(const RTLIL::Const &other) const -{ - if (bits.size() != other.bits.size()) - return bits.size() < other.bits.size(); - for (size_t i = 0; i < bits.size(); i++) - if (bits[i] != other.bits[i]) - return bits[i] < other.bits[i]; - return false; -} - -bool RTLIL::Const::operator ==(const RTLIL::Const &other) const -{ - return bits == other.bits; -} - -bool RTLIL::Const::operator !=(const RTLIL::Const &other) const -{ - return bits != other.bits; -} - -bool RTLIL::Const::as_bool() const -{ - for (size_t i = 0; i < bits.size(); i++) - if (bits[i] == RTLIL::S1) - return true; - return false; -} - -int RTLIL::Const::as_int(bool is_signed) const -{ - int32_t ret = 0; - for (size_t i = 0; i < bits.size() && i < 32; i++) - if (bits[i] == RTLIL::S1) - ret |= 1 << i; - if (is_signed && bits.back() == RTLIL::S1) - for (size_t i = bits.size(); i < 32; i++) - ret |= 1 << i; - return ret; -} - -std::string RTLIL::Const::as_string() const -{ - std::string ret; - for (size_t i = bits.size(); i > 0; i--) - switch (bits[i-1]) { - case S0: ret += "0"; break; - case S1: ret += "1"; break; - case Sx: ret += "x"; break; - case Sz: ret += "z"; break; - case Sa: ret += "-"; break; - case Sm: ret += "m"; break; - } - return ret; -} - -RTLIL::Const RTLIL::Const::from_string(std::string str) -{ - Const c; - for (auto it = str.rbegin(); it != str.rend(); it++) - switch (*it) { - case '0': c.bits.push_back(State::S0); break; - case '1': c.bits.push_back(State::S1); break; - case 'x': c.bits.push_back(State::Sx); break; - case 'z': c.bits.push_back(State::Sz); break; - case 'm': c.bits.push_back(State::Sm); break; - default: c.bits.push_back(State::Sa); - } - return c; -} - -std::string RTLIL::Const::decode_string() const -{ - std::string string; - std::vector string_chars; - for (int i = 0; i < int (bits.size()); i += 8) { - char ch = 0; - for (int j = 0; j < 8 && i + j < int (bits.size()); j++) - if (bits[i + j] == RTLIL::State::S1) - ch |= 1 << j; - if (ch != 0) - string_chars.push_back(ch); - } - for (int i = int (string_chars.size()) - 1; i >= 0; i--) - string += string_chars[i]; - return string; -} - -bool RTLIL::Const::is_fully_zero() const -{ - cover("kernel.rtlil.const.is_fully_zero"); - - for (auto bit : bits) - if (bit != RTLIL::State::S0) - return false; - - return true; -} - -bool RTLIL::Const::is_fully_ones() const -{ - cover("kernel.rtlil.const.is_fully_ones"); - - for (auto bit : bits) - if (bit != RTLIL::State::S1) - return false; - - return true; -} - -bool RTLIL::Const::is_fully_def() const -{ - cover("kernel.rtlil.const.is_fully_def"); - - for (auto bit : bits) - if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1) - return false; - - return true; -} - -bool RTLIL::Const::is_fully_undef() const -{ - cover("kernel.rtlil.const.is_fully_undef"); - - for (auto bit : bits) - if (bit != RTLIL::State::Sx && bit != RTLIL::State::Sz) - return false; - - return true; -} - -void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) -{ - if (value) - attributes[id] = RTLIL::Const(1); - else { - const auto it = attributes.find(id); - if (it != attributes.end()) - attributes.erase(it); - } -} - -bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const -{ - const auto it = attributes.find(id); - if (it == attributes.end()) - return false; - return it->second.as_bool(); -} - -void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool &data) -{ - string attrval; - for (auto &s : data) { - if (!attrval.empty()) - attrval += "|"; - attrval += s; - } - attributes[id] = RTLIL::Const(attrval); -} - -void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool &data) -{ - pool union_data = get_strpool_attribute(id); - union_data.insert(data.begin(), data.end()); - if (!union_data.empty()) - set_strpool_attribute(id, union_data); -} - -pool RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const -{ - pool data; - if (attributes.count(id) != 0) - for (auto s : split_tokens(attributes.at(id).decode_string(), "|")) - data.insert(s); - return data; -} - -void RTLIL::AttrObject::set_src_attribute(const std::string &src) -{ - if (src.empty()) - attributes.erase("\\src"); - else - attributes["\\src"] = src; -} - -std::string RTLIL::AttrObject::get_src_attribute() const -{ - std::string src; - if (attributes.count("\\src")) - src = attributes.at("\\src").decode_string(); - return src; -} - -bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const -{ - if (full_selection) - return true; - if (selected_modules.count(mod_name) > 0) - return true; - if (selected_members.count(mod_name) > 0) - return true; - return false; -} - -bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const -{ - if (full_selection) - return true; - if (selected_modules.count(mod_name) > 0) - return true; - return false; -} - -bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const -{ - if (full_selection) - return true; - if (selected_modules.count(mod_name) > 0) - return true; - if (selected_members.count(mod_name) > 0) - if (selected_members.at(mod_name).count(memb_name) > 0) - return true; - return false; -} - -void RTLIL::Selection::optimize(RTLIL::Design *design) -{ - if (full_selection) { - selected_modules.clear(); - selected_members.clear(); - return; - } - - std::vector del_list, add_list; - - del_list.clear(); - for (auto mod_name : selected_modules) { - if (design->modules_.count(mod_name) == 0) - del_list.push_back(mod_name); - selected_members.erase(mod_name); - } - for (auto mod_name : del_list) - selected_modules.erase(mod_name); - - del_list.clear(); - for (auto &it : selected_members) - if (design->modules_.count(it.first) == 0) - del_list.push_back(it.first); - for (auto mod_name : del_list) - selected_members.erase(mod_name); - - for (auto &it : selected_members) { - del_list.clear(); - for (auto memb_name : it.second) - if (design->modules_[it.first]->count_id(memb_name) == 0) - del_list.push_back(memb_name); - for (auto memb_name : del_list) - it.second.erase(memb_name); - } - - del_list.clear(); - add_list.clear(); - for (auto &it : selected_members) - if (it.second.size() == 0) - del_list.push_back(it.first); - else if (it.second.size() == design->modules_[it.first]->wires_.size() + design->modules_[it.first]->memories.size() + - design->modules_[it.first]->cells_.size() + design->modules_[it.first]->processes.size()) - add_list.push_back(it.first); - for (auto mod_name : del_list) - selected_members.erase(mod_name); - for (auto mod_name : add_list) { - selected_members.erase(mod_name); - selected_modules.insert(mod_name); - } - - if (selected_modules.size() == design->modules_.size()) { - full_selection = true; - selected_modules.clear(); - selected_members.clear(); - } -} - -RTLIL::Design::Design() -{ - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; - - refcount_modules_ = 0; - selection_stack.push_back(RTLIL::Selection()); - -#ifdef WITH_PYTHON - RTLIL::Design::get_all_designs()->insert(std::pair(hashidx_, this)); -#endif -} - -RTLIL::Design::~Design() -{ - for (auto it = modules_.begin(); it != modules_.end(); ++it) - delete it->second; - for (auto n : verilog_packages) - delete n; - for (auto n : verilog_globals) - delete n; -#ifdef WITH_PYTHON - RTLIL::Design::get_all_designs()->erase(hashidx_); -#endif -} - -#ifdef WITH_PYTHON -static std::map all_designs; -std::map *RTLIL::Design::get_all_designs(void) -{ - return &all_designs; -} -#endif - -RTLIL::ObjRange RTLIL::Design::modules() -{ - return RTLIL::ObjRange(&modules_, &refcount_modules_); -} - -RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) -{ - return modules_.count(name) ? modules_.at(name) : NULL; -} - -RTLIL::Module *RTLIL::Design::top_module() -{ - RTLIL::Module *module = nullptr; - int module_count = 0; - - for (auto mod : selected_modules()) { - if (mod->get_bool_attribute("\\top")) - return mod; - module_count++; - module = mod; - } - - return module_count == 1 ? module : nullptr; -} - -void RTLIL::Design::add(RTLIL::Module *module) -{ - log_assert(modules_.count(module->name) == 0); - log_assert(refcount_modules_ == 0); - modules_[module->name] = module; - module->design = this; - - for (auto mon : monitors) - mon->notify_module_add(module); - - if (yosys_xtrace) { - log("#X# New Module: %s\n", log_id(module)); - log_backtrace("-X- ", yosys_xtrace-1); - } -} - -RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name) -{ - log_assert(modules_.count(name) == 0); - log_assert(refcount_modules_ == 0); - - RTLIL::Module *module = new RTLIL::Module; - modules_[name] = module; - module->design = this; - module->name = name; - - for (auto mon : monitors) - mon->notify_module_add(module); - - if (yosys_xtrace) { - log("#X# New Module: %s\n", log_id(module)); - log_backtrace("-X- ", yosys_xtrace-1); - } - - return module; -} - -void RTLIL::Design::scratchpad_unset(std::string varname) -{ - scratchpad.erase(varname); -} - -void RTLIL::Design::scratchpad_set_int(std::string varname, int value) -{ - scratchpad[varname] = stringf("%d", value); -} - -void RTLIL::Design::scratchpad_set_bool(std::string varname, bool value) -{ - scratchpad[varname] = value ? "true" : "false"; -} - -void RTLIL::Design::scratchpad_set_string(std::string varname, std::string value) -{ - scratchpad[varname] = value; -} - -int RTLIL::Design::scratchpad_get_int(std::string varname, int default_value) const -{ - if (scratchpad.count(varname) == 0) - return default_value; - - std::string str = scratchpad.at(varname); - - if (str == "0" || str == "false") - return 0; - - if (str == "1" || str == "true") - return 1; - - char *endptr = nullptr; - long int parsed_value = strtol(str.c_str(), &endptr, 10); - return *endptr ? default_value : parsed_value; -} - -bool RTLIL::Design::scratchpad_get_bool(std::string varname, bool default_value) const -{ - if (scratchpad.count(varname) == 0) - return default_value; - - std::string str = scratchpad.at(varname); - - if (str == "0" || str == "false") - return false; - - if (str == "1" || str == "true") - return true; - - return default_value; -} - -std::string RTLIL::Design::scratchpad_get_string(std::string varname, std::string default_value) const -{ - if (scratchpad.count(varname) == 0) - return default_value; - return scratchpad.at(varname); -} - -void RTLIL::Design::remove(RTLIL::Module *module) -{ - for (auto mon : monitors) - mon->notify_module_del(module); - - if (yosys_xtrace) { - log("#X# Remove Module: %s\n", log_id(module)); - log_backtrace("-X- ", yosys_xtrace-1); - } - - log_assert(modules_.at(module->name) == module); - modules_.erase(module->name); - delete module; -} - -void RTLIL::Design::rename(RTLIL::Module *module, RTLIL::IdString new_name) -{ - modules_.erase(module->name); - module->name = new_name; - add(module); -} - -void RTLIL::Design::sort() -{ - scratchpad.sort(); - modules_.sort(sort_by_id_str()); - for (auto &it : modules_) - it.second->sort(); -} - -void RTLIL::Design::check() -{ -#ifndef NDEBUG - for (auto &it : modules_) { - log_assert(this == it.second->design); - log_assert(it.first == it.second->name); - log_assert(!it.first.empty()); - it.second->check(); - } -#endif -} - -void RTLIL::Design::optimize() -{ - for (auto &it : modules_) - it.second->optimize(); - for (auto &it : selection_stack) - it.optimize(this); - for (auto &it : selection_vars) - it.second.optimize(this); -} - -bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const -{ - if (!selected_active_module.empty() && mod_name != selected_active_module) - return false; - if (selection_stack.size() == 0) - return true; - return selection_stack.back().selected_module(mod_name); -} - -bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const -{ - if (!selected_active_module.empty() && mod_name != selected_active_module) - return false; - if (selection_stack.size() == 0) - return true; - return selection_stack.back().selected_whole_module(mod_name); -} - -bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const -{ - if (!selected_active_module.empty() && mod_name != selected_active_module) - return false; - if (selection_stack.size() == 0) - return true; - return selection_stack.back().selected_member(mod_name, memb_name); -} - -bool RTLIL::Design::selected_module(RTLIL::Module *mod) const -{ - return selected_module(mod->name); -} - -bool RTLIL::Design::selected_whole_module(RTLIL::Module *mod) const -{ - return selected_whole_module(mod->name); -} - -std::vector RTLIL::Design::selected_modules() const -{ - std::vector result; - result.reserve(modules_.size()); - for (auto &it : modules_) - if (selected_module(it.first) && !it.second->get_blackbox_attribute()) - result.push_back(it.second); - return result; -} - -std::vector RTLIL::Design::selected_whole_modules() const -{ - std::vector result; - result.reserve(modules_.size()); - for (auto &it : modules_) - if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute()) - result.push_back(it.second); - return result; -} - -std::vector RTLIL::Design::selected_whole_modules_warn() const -{ - std::vector result; - result.reserve(modules_.size()); - for (auto &it : modules_) - if (it.second->get_blackbox_attribute()) - continue; - else if (selected_whole_module(it.first)) - result.push_back(it.second); - else if (selected_module(it.first)) - log_warning("Ignoring partially selected module %s.\n", log_id(it.first)); - return result; -} - -RTLIL::Module::Module() -{ - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; - - design = nullptr; - refcount_wires_ = 0; - refcount_cells_ = 0; - -#ifdef WITH_PYTHON - RTLIL::Module::get_all_modules()->insert(std::pair(hashidx_, this)); -#endif -} - -RTLIL::Module::~Module() -{ - for (auto it = wires_.begin(); it != wires_.end(); ++it) - delete it->second; - for (auto it = memories.begin(); it != memories.end(); ++it) - delete it->second; - for (auto it = cells_.begin(); it != cells_.end(); ++it) - delete it->second; - for (auto it = processes.begin(); it != processes.end(); ++it) - delete it->second; -#ifdef WITH_PYTHON - RTLIL::Module::get_all_modules()->erase(hashidx_); -#endif -} - -#ifdef WITH_PYTHON -static std::map all_modules; -std::map *RTLIL::Module::get_all_modules(void) -{ - return &all_modules; -} -#endif - -void RTLIL::Module::makeblackbox() -{ - pool delwires; - - for (auto it = wires_.begin(); it != wires_.end(); ++it) - if (!it->second->port_input && !it->second->port_output) - delwires.insert(it->second); - - for (auto it = memories.begin(); it != memories.end(); ++it) - delete it->second; - memories.clear(); - - for (auto it = cells_.begin(); it != cells_.end(); ++it) - delete it->second; - cells_.clear(); - - for (auto it = processes.begin(); it != processes.end(); ++it) - delete it->second; - processes.clear(); - - remove(delwires); - set_bool_attribute("\\blackbox"); -} - -void RTLIL::Module::reprocess_module(RTLIL::Design *, dict) -{ - log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name)); -} - -RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict, bool mayfail) -{ - if (mayfail) - return RTLIL::IdString(); - log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name)); -} - - -RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict, dict, dict, bool mayfail) -{ - if (mayfail) - return RTLIL::IdString(); - log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name)); -} - -size_t RTLIL::Module::count_id(RTLIL::IdString id) -{ - return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id); -} - -#ifndef NDEBUG -namespace { - struct InternalCellChecker - { - RTLIL::Module *module; - RTLIL::Cell *cell; - pool expected_params, expected_ports; - - InternalCellChecker(RTLIL::Module *module, RTLIL::Cell *cell) : module(module), cell(cell) { } - - void error(int linenr) - { - std::stringstream buf; - ILANG_BACKEND::dump_cell(buf, " ", cell); - - log_error("Found error in internal cell %s%s%s (%s) at %s:%d:\n%s", - module ? module->name.c_str() : "", module ? "." : "", - cell->name.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str()); - } - - int param(const char *name) - { - if (cell->parameters.count(name) == 0) - error(__LINE__); - expected_params.insert(name); - return cell->parameters.at(name).as_int(); - } - - int param_bool(const char *name) - { - int v = param(name); - if (cell->parameters.at(name).bits.size() > 32) - error(__LINE__); - if (v != 0 && v != 1) - error(__LINE__); - return v; - } - - void param_bits(const char *name, int width) - { - param(name); - if (int(cell->parameters.at(name).bits.size()) != width) - error(__LINE__); - } - - void port(const char *name, int width) - { - if (!cell->hasPort(name)) - error(__LINE__); - if (cell->getPort(name).size() != width) - error(__LINE__); - expected_ports.insert(name); - } - - void check_expected(bool check_matched_sign = true) - { - for (auto ¶ : cell->parameters) - if (expected_params.count(para.first) == 0) - error(__LINE__); - for (auto &conn : cell->connections()) - if (expected_ports.count(conn.first) == 0) - error(__LINE__); - - if (expected_params.count("\\A_SIGNED") != 0 && expected_params.count("\\B_SIGNED") && check_matched_sign) { - bool a_is_signed = param("\\A_SIGNED") != 0; - bool b_is_signed = param("\\B_SIGNED") != 0; - if (a_is_signed != b_is_signed) - error(__LINE__); - } - } - - void check_gate(const char *ports) - { - if (cell->parameters.size() != 0) - error(__LINE__); - - for (const char *p = ports; *p; p++) { - char portname[3] = { '\\', *p, 0 }; - if (!cell->hasPort(portname)) - error(__LINE__); - if (cell->getPort(portname).size() != 1) - error(__LINE__); - } - - for (auto &conn : cell->connections()) { - if (conn.first.size() != 2 || conn.first[0] != '\\') - error(__LINE__); - if (strchr(ports, conn.first[1]) == NULL) - error(__LINE__); - } - } - - void check() - { - if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" || - cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:") - return; - - if (cell->type.in("$not", "$pos", "$neg")) { - param_bool("\\A_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(); - return; - } - - if (cell->type.in("$and", "$or", "$xor", "$xnor")) { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(); - return; - } - - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) { - param_bool("\\A_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(); - return; - } - - if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(false); - return; - } - - if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(); - return; - } - - if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$pow")) { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(cell->type != "$pow"); - return; - } - - if (cell->type == "$fa") { - port("\\A", param("\\WIDTH")); - port("\\B", param("\\WIDTH")); - port("\\C", param("\\WIDTH")); - port("\\X", param("\\WIDTH")); - port("\\Y", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$lcu") { - port("\\P", param("\\WIDTH")); - port("\\G", param("\\WIDTH")); - port("\\CI", 1); - port("\\CO", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$alu") { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\CI", 1); - port("\\BI", 1); - port("\\X", param("\\Y_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - port("\\CO", param("\\Y_WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$macc") { - param("\\CONFIG"); - param("\\CONFIG_WIDTH"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(); - Macc().from_cell(cell); - return; - } - - if (cell->type == "$logic_not") { - param_bool("\\A_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$logic_and" || cell->type == "$logic_or") { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(false); - return; - } - - if (cell->type == "$slice") { - param("\\OFFSET"); - port("\\A", param("\\A_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - if (param("\\OFFSET") + param("\\Y_WIDTH") > param("\\A_WIDTH")) - error(__LINE__); - check_expected(); - return; - } - - if (cell->type == "$concat") { - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\A_WIDTH") + param("\\B_WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$mux") { - port("\\A", param("\\WIDTH")); - port("\\B", param("\\WIDTH")); - port("\\S", 1); - port("\\Y", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$pmux") { - port("\\A", param("\\WIDTH")); - port("\\B", param("\\WIDTH") * param("\\S_WIDTH")); - port("\\S", param("\\S_WIDTH")); - port("\\Y", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$lut") { - param("\\LUT"); - port("\\A", param("\\WIDTH")); - port("\\Y", 1); - check_expected(); - return; - } - - if (cell->type == "$sop") { - param("\\DEPTH"); - param("\\TABLE"); - port("\\A", param("\\WIDTH")); - port("\\Y", 1); - check_expected(); - return; - } - - if (cell->type == "$sr") { - param_bool("\\SET_POLARITY"); - param_bool("\\CLR_POLARITY"); - port("\\SET", param("\\WIDTH")); - port("\\CLR", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$ff") { - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$dff") { - param_bool("\\CLK_POLARITY"); - port("\\CLK", 1); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$dffe") { - param_bool("\\CLK_POLARITY"); - param_bool("\\EN_POLARITY"); - port("\\CLK", 1); - port("\\EN", 1); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$dffsr") { - param_bool("\\CLK_POLARITY"); - param_bool("\\SET_POLARITY"); - param_bool("\\CLR_POLARITY"); - port("\\CLK", 1); - port("\\SET", param("\\WIDTH")); - port("\\CLR", param("\\WIDTH")); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$adff") { - param_bool("\\CLK_POLARITY"); - param_bool("\\ARST_POLARITY"); - param_bits("\\ARST_VALUE", param("\\WIDTH")); - port("\\CLK", 1); - port("\\ARST", 1); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$dlatch") { - param_bool("\\EN_POLARITY"); - port("\\EN", 1); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$dlatchsr") { - param_bool("\\EN_POLARITY"); - param_bool("\\SET_POLARITY"); - param_bool("\\CLR_POLARITY"); - port("\\EN", 1); - port("\\SET", param("\\WIDTH")); - port("\\CLR", param("\\WIDTH")); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$fsm") { - param("\\NAME"); - param_bool("\\CLK_POLARITY"); - param_bool("\\ARST_POLARITY"); - param("\\STATE_BITS"); - param("\\STATE_NUM"); - param("\\STATE_NUM_LOG2"); - param("\\STATE_RST"); - param_bits("\\STATE_TABLE", param("\\STATE_BITS") * param("\\STATE_NUM")); - param("\\TRANS_NUM"); - param_bits("\\TRANS_TABLE", param("\\TRANS_NUM") * (2*param("\\STATE_NUM_LOG2") + param("\\CTRL_IN_WIDTH") + param("\\CTRL_OUT_WIDTH"))); - port("\\CLK", 1); - port("\\ARST", 1); - port("\\CTRL_IN", param("\\CTRL_IN_WIDTH")); - port("\\CTRL_OUT", param("\\CTRL_OUT_WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$memrd") { - param("\\MEMID"); - param_bool("\\CLK_ENABLE"); - param_bool("\\CLK_POLARITY"); - param_bool("\\TRANSPARENT"); - port("\\CLK", 1); - port("\\EN", 1); - port("\\ADDR", param("\\ABITS")); - port("\\DATA", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$memwr") { - param("\\MEMID"); - param_bool("\\CLK_ENABLE"); - param_bool("\\CLK_POLARITY"); - param("\\PRIORITY"); - port("\\CLK", 1); - port("\\EN", param("\\WIDTH")); - port("\\ADDR", param("\\ABITS")); - port("\\DATA", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$meminit") { - param("\\MEMID"); - param("\\PRIORITY"); - port("\\ADDR", param("\\ABITS")); - port("\\DATA", param("\\WIDTH") * param("\\WORDS")); - check_expected(); - return; - } - - if (cell->type == "$mem") { - param("\\MEMID"); - param("\\SIZE"); - param("\\OFFSET"); - param("\\INIT"); - param_bits("\\RD_CLK_ENABLE", max(1, param("\\RD_PORTS"))); - param_bits("\\RD_CLK_POLARITY", max(1, param("\\RD_PORTS"))); - param_bits("\\RD_TRANSPARENT", max(1, param("\\RD_PORTS"))); - param_bits("\\WR_CLK_ENABLE", max(1, param("\\WR_PORTS"))); - param_bits("\\WR_CLK_POLARITY", max(1, param("\\WR_PORTS"))); - port("\\RD_CLK", param("\\RD_PORTS")); - port("\\RD_EN", param("\\RD_PORTS")); - port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS")); - port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH")); - port("\\WR_CLK", param("\\WR_PORTS")); - port("\\WR_EN", param("\\WR_PORTS") * param("\\WIDTH")); - port("\\WR_ADDR", param("\\WR_PORTS") * param("\\ABITS")); - port("\\WR_DATA", param("\\WR_PORTS") * param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$tribuf") { - port("\\A", param("\\WIDTH")); - port("\\Y", param("\\WIDTH")); - port("\\EN", 1); - check_expected(); - return; - } - - if (cell->type.in("$assert", "$assume", "$live", "$fair", "$cover")) { - port("\\A", 1); - port("\\EN", 1); - check_expected(); - return; - } - - if (cell->type == "$initstate") { - port("\\Y", 1); - check_expected(); - return; - } - - if (cell->type.in("$anyconst", "$anyseq", "$allconst", "$allseq")) { - port("\\Y", param("\\WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$equiv") { - port("\\A", 1); - port("\\B", 1); - port("\\Y", 1); - check_expected(); - return; - } - - if (cell->type.in("$specify2", "$specify3")) { - param_bool("\\FULL"); - param_bool("\\SRC_DST_PEN"); - param_bool("\\SRC_DST_POL"); - param("\\T_RISE_MIN"); - param("\\T_RISE_TYP"); - param("\\T_RISE_MAX"); - param("\\T_FALL_MIN"); - param("\\T_FALL_TYP"); - param("\\T_FALL_MAX"); - port("\\EN", 1); - port("\\SRC", param("\\SRC_WIDTH")); - port("\\DST", param("\\DST_WIDTH")); - if (cell->type == "$specify3") { - param_bool("\\EDGE_EN"); - param_bool("\\EDGE_POL"); - param_bool("\\DAT_DST_PEN"); - param_bool("\\DAT_DST_POL"); - port("\\DAT", param("\\DST_WIDTH")); - } - check_expected(); - return; - } - - if (cell->type == "$specrule") { - param("\\TYPE"); - param_bool("\\SRC_PEN"); - param_bool("\\SRC_POL"); - param_bool("\\DST_PEN"); - param_bool("\\DST_POL"); - param("\\T_LIMIT"); - param("\\T_LIMIT2"); - port("\\SRC_EN", 1); - port("\\DST_EN", 1); - port("\\SRC", param("\\SRC_WIDTH")); - port("\\DST", param("\\DST_WIDTH")); - check_expected(); - return; - } - - if (cell->type == "$_BUF_") { check_gate("AY"); return; } - if (cell->type == "$_NOT_") { check_gate("AY"); return; } - if (cell->type == "$_AND_") { check_gate("ABY"); return; } - if (cell->type == "$_NAND_") { check_gate("ABY"); return; } - if (cell->type == "$_OR_") { check_gate("ABY"); return; } - if (cell->type == "$_NOR_") { check_gate("ABY"); return; } - if (cell->type == "$_XOR_") { check_gate("ABY"); return; } - if (cell->type == "$_XNOR_") { check_gate("ABY"); return; } - if (cell->type == "$_ANDNOT_") { check_gate("ABY"); return; } - if (cell->type == "$_ORNOT_") { check_gate("ABY"); return; } - if (cell->type == "$_MUX_") { check_gate("ABSY"); return; } - if (cell->type == "$_AOI3_") { check_gate("ABCY"); return; } - if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; } - if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; } - if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; } - - if (cell->type == "$_TBUF_") { check_gate("AYE"); return; } - - if (cell->type == "$_MUX4_") { check_gate("ABCDSTY"); return; } - if (cell->type == "$_MUX8_") { check_gate("ABCDEFGHSTUY"); return; } - if (cell->type == "$_MUX16_") { check_gate("ABCDEFGHIJKLMNOPSTUVY"); return; } - - if (cell->type == "$_SR_NN_") { check_gate("SRQ"); return; } - if (cell->type == "$_SR_NP_") { check_gate("SRQ"); return; } - if (cell->type == "$_SR_PN_") { check_gate("SRQ"); return; } - if (cell->type == "$_SR_PP_") { check_gate("SRQ"); return; } - - if (cell->type == "$_FF_") { check_gate("DQ"); return; } - if (cell->type == "$_DFF_N_") { check_gate("DQC"); return; } - if (cell->type == "$_DFF_P_") { check_gate("DQC"); return; } - - if (cell->type == "$_DFFE_NN_") { check_gate("DQCE"); return; } - if (cell->type == "$_DFFE_NP_") { check_gate("DQCE"); return; } - if (cell->type == "$_DFFE_PN_") { check_gate("DQCE"); return; } - if (cell->type == "$_DFFE_PP_") { check_gate("DQCE"); return; } - - if (cell->type == "$_DFF_NN0_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_NN1_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_NP0_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_NP1_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_PN0_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_PN1_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_PP0_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_PP1_") { check_gate("DQCR"); return; } - - if (cell->type == "$_DFFSR_NNN_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_NNP_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_NPN_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_NPP_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_PNN_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_PNP_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_PPN_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_PPP_") { check_gate("CSRDQ"); return; } - - if (cell->type == "$_DLATCH_N_") { check_gate("EDQ"); return; } - if (cell->type == "$_DLATCH_P_") { check_gate("EDQ"); return; } - - if (cell->type == "$_DLATCHSR_NNN_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_NNP_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_NPN_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_NPP_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_PNN_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_PNP_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_PPN_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_PPP_") { check_gate("ESRDQ"); return; } - - error(__LINE__); - } - }; -} -#endif - -void RTLIL::Module::sort() -{ - wires_.sort(sort_by_id_str()); - cells_.sort(sort_by_id_str()); - avail_parameters.sort(sort_by_id_str()); - memories.sort(sort_by_id_str()); - processes.sort(sort_by_id_str()); - for (auto &it : cells_) - it.second->sort(); - for (auto &it : wires_) - it.second->attributes.sort(sort_by_id_str()); - for (auto &it : memories) - it.second->attributes.sort(sort_by_id_str()); -} - -void RTLIL::Module::check() -{ -#ifndef NDEBUG - std::vector ports_declared; - for (auto &it : wires_) { - log_assert(this == it.second->module); - log_assert(it.first == it.second->name); - log_assert(!it.first.empty()); - log_assert(it.second->width >= 0); - log_assert(it.second->port_id >= 0); - for (auto &it2 : it.second->attributes) - log_assert(!it2.first.empty()); - if (it.second->port_id) { - log_assert(GetSize(ports) >= it.second->port_id); - log_assert(ports.at(it.second->port_id-1) == it.first); - log_assert(it.second->port_input || it.second->port_output); - if (GetSize(ports_declared) < it.second->port_id) - ports_declared.resize(it.second->port_id); - log_assert(ports_declared[it.second->port_id-1] == false); - ports_declared[it.second->port_id-1] = true; - } else - log_assert(!it.second->port_input && !it.second->port_output); - } - for (auto port_declared : ports_declared) - log_assert(port_declared == true); - log_assert(GetSize(ports) == GetSize(ports_declared)); - - for (auto &it : memories) { - log_assert(it.first == it.second->name); - log_assert(!it.first.empty()); - log_assert(it.second->width >= 0); - log_assert(it.second->size >= 0); - for (auto &it2 : it.second->attributes) - log_assert(!it2.first.empty()); - } - - for (auto &it : cells_) { - log_assert(this == it.second->module); - log_assert(it.first == it.second->name); - log_assert(!it.first.empty()); - log_assert(!it.second->type.empty()); - for (auto &it2 : it.second->connections()) { - log_assert(!it2.first.empty()); - it2.second.check(); - } - for (auto &it2 : it.second->attributes) - log_assert(!it2.first.empty()); - for (auto &it2 : it.second->parameters) - log_assert(!it2.first.empty()); - InternalCellChecker checker(this, it.second); - checker.check(); - } - - for (auto &it : processes) { - log_assert(it.first == it.second->name); - log_assert(!it.first.empty()); - log_assert(it.second->root_case.compare.empty()); - std::vector all_cases = {&it.second->root_case}; - for (size_t i = 0; i < all_cases.size(); i++) { - for (auto &switch_it : all_cases[i]->switches) { - for (auto &case_it : switch_it->cases) { - for (auto &compare_it : case_it->compare) { - log_assert(switch_it->signal.size() == compare_it.size()); - } - all_cases.push_back(case_it); - } - } - } - for (auto &sync_it : it.second->syncs) { - switch (sync_it->type) { - case SyncType::ST0: - case SyncType::ST1: - case SyncType::STp: - case SyncType::STn: - case SyncType::STe: - log_assert(!sync_it->signal.empty()); - break; - case SyncType::STa: - case SyncType::STg: - case SyncType::STi: - log_assert(sync_it->signal.empty()); - break; - } - } - } - - for (auto &it : connections_) { - log_assert(it.first.size() == it.second.size()); - log_assert(!it.first.has_const()); - it.first.check(); - it.second.check(); - } - - for (auto &it : attributes) - log_assert(!it.first.empty()); -#endif -} - -void RTLIL::Module::optimize() -{ -} - -void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const -{ - log_assert(new_mod->refcount_wires_ == 0); - log_assert(new_mod->refcount_cells_ == 0); - - new_mod->avail_parameters = avail_parameters; - - for (auto &conn : connections_) - new_mod->connect(conn); - - for (auto &attr : attributes) - new_mod->attributes[attr.first] = attr.second; - - for (auto &it : wires_) - new_mod->addWire(it.first, it.second); - - for (auto &it : memories) - new_mod->memories[it.first] = new RTLIL::Memory(*it.second); - - for (auto &it : cells_) - new_mod->addCell(it.first, it.second); - - for (auto &it : processes) - new_mod->processes[it.first] = it.second->clone(); - - struct RewriteSigSpecWorker - { - RTLIL::Module *mod; - void operator()(RTLIL::SigSpec &sig) - { - std::vector chunks = sig.chunks(); - for (auto &c : chunks) - if (c.wire != NULL) - c.wire = mod->wires_.at(c.wire->name); - sig = chunks; - } - }; - - RewriteSigSpecWorker rewriteSigSpecWorker; - rewriteSigSpecWorker.mod = new_mod; - new_mod->rewrite_sigspecs(rewriteSigSpecWorker); - new_mod->fixup_ports(); -} - -RTLIL::Module *RTLIL::Module::clone() const -{ - RTLIL::Module *new_mod = new RTLIL::Module; - new_mod->name = name; - cloneInto(new_mod); - return new_mod; -} - -bool RTLIL::Module::has_memories() const -{ - return !memories.empty(); -} - -bool RTLIL::Module::has_processes() const -{ - return !processes.empty(); -} - -bool RTLIL::Module::has_memories_warn() const -{ - if (!memories.empty()) - log_warning("Ignoring module %s because it contains memories (run 'memory' command first).\n", log_id(this)); - return !memories.empty(); -} - -bool RTLIL::Module::has_processes_warn() const -{ - if (!processes.empty()) - log_warning("Ignoring module %s because it contains processes (run 'proc' command first).\n", log_id(this)); - return !processes.empty(); -} - -std::vector RTLIL::Module::selected_wires() const -{ - std::vector result; - result.reserve(wires_.size()); - for (auto &it : wires_) - if (design->selected(this, it.second)) - result.push_back(it.second); - return result; -} - -std::vector RTLIL::Module::selected_cells() const -{ - std::vector result; - result.reserve(wires_.size()); - for (auto &it : cells_) - if (design->selected(this, it.second)) - result.push_back(it.second); - return result; -} - -void RTLIL::Module::add(RTLIL::Wire *wire) -{ - log_assert(!wire->name.empty()); - log_assert(count_id(wire->name) == 0); - log_assert(refcount_wires_ == 0); - wires_[wire->name] = wire; - wire->module = this; -} - -void RTLIL::Module::add(RTLIL::Cell *cell) -{ - log_assert(!cell->name.empty()); - log_assert(count_id(cell->name) == 0); - log_assert(refcount_cells_ == 0); - cells_[cell->name] = cell; - cell->module = this; -} - -void RTLIL::Module::remove(const pool &wires) -{ - log_assert(refcount_wires_ == 0); - - struct DeleteWireWorker - { - RTLIL::Module *module; - const pool *wires_p; - - void operator()(RTLIL::SigSpec &sig) { - std::vector chunks = sig; - for (auto &c : chunks) - if (c.wire != NULL && wires_p->count(c.wire)) { - c.wire = module->addWire(NEW_ID, c.width); - c.offset = 0; - } - sig = chunks; - } - - void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) { - log_assert(GetSize(lhs) == GetSize(rhs)); - RTLIL::SigSpec new_lhs, new_rhs; - for (int i = 0; i < GetSize(lhs); i++) { - RTLIL::SigBit lhs_bit = lhs[i]; - if (lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire)) - continue; - RTLIL::SigBit rhs_bit = rhs[i]; - if (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire)) - continue; - new_lhs.append(lhs_bit); - new_rhs.append(rhs_bit); - } - lhs = new_lhs; - rhs = new_rhs; - } - }; - - DeleteWireWorker delete_wire_worker; - delete_wire_worker.module = this; - delete_wire_worker.wires_p = &wires; - rewrite_sigspecs2(delete_wire_worker); - - for (auto &it : wires) { - log_assert(wires_.count(it->name) != 0); - wires_.erase(it->name); - delete it; - } -} - -void RTLIL::Module::remove(RTLIL::Cell *cell) -{ - while (!cell->connections_.empty()) - cell->unsetPort(cell->connections_.begin()->first); - - log_assert(cells_.count(cell->name) != 0); - log_assert(refcount_cells_ == 0); - cells_.erase(cell->name); - delete cell; -} - -void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name) -{ - log_assert(wires_[wire->name] == wire); - log_assert(refcount_wires_ == 0); - wires_.erase(wire->name); - wire->name = new_name; - add(wire); -} - -void RTLIL::Module::rename(RTLIL::Cell *cell, RTLIL::IdString new_name) -{ - log_assert(cells_[cell->name] == cell); - log_assert(refcount_wires_ == 0); - cells_.erase(cell->name); - cell->name = new_name; - add(cell); -} - -void RTLIL::Module::rename(RTLIL::IdString old_name, RTLIL::IdString new_name) -{ - log_assert(count_id(old_name) != 0); - if (wires_.count(old_name)) - rename(wires_.at(old_name), new_name); - else if (cells_.count(old_name)) - rename(cells_.at(old_name), new_name); - else - log_abort(); -} - -void RTLIL::Module::swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2) -{ - log_assert(wires_[w1->name] == w1); - log_assert(wires_[w2->name] == w2); - log_assert(refcount_wires_ == 0); - - wires_.erase(w1->name); - wires_.erase(w2->name); - - std::swap(w1->name, w2->name); - - wires_[w1->name] = w1; - wires_[w2->name] = w2; -} - -void RTLIL::Module::swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2) -{ - log_assert(cells_[c1->name] == c1); - log_assert(cells_[c2->name] == c2); - log_assert(refcount_cells_ == 0); - - cells_.erase(c1->name); - cells_.erase(c2->name); - - std::swap(c1->name, c2->name); - - cells_[c1->name] = c1; - cells_[c2->name] = c2; -} - -RTLIL::IdString RTLIL::Module::uniquify(RTLIL::IdString name) -{ - int index = 0; - return uniquify(name, index); -} - -RTLIL::IdString RTLIL::Module::uniquify(RTLIL::IdString name, int &index) -{ - if (index == 0) { - if (count_id(name) == 0) - return name; - index++; - } - - while (1) { - RTLIL::IdString new_name = stringf("%s_%d", name.c_str(), index); - if (count_id(new_name) == 0) - return new_name; - index++; - } -} - -static bool fixup_ports_compare(const RTLIL::Wire *a, const RTLIL::Wire *b) -{ - if (a->port_id && !b->port_id) - return true; - if (!a->port_id && b->port_id) - return false; - - if (a->port_id == b->port_id) - return a->name < b->name; - return a->port_id < b->port_id; -} - -void RTLIL::Module::connect(const RTLIL::SigSig &conn) -{ - for (auto mon : monitors) - mon->notify_connect(this, conn); - - if (design) - for (auto mon : design->monitors) - mon->notify_connect(this, conn); - - // ignore all attempts to assign constants to other constants - if (conn.first.has_const()) { - RTLIL::SigSig new_conn; - for (int i = 0; i < GetSize(conn.first); i++) - if (conn.first[i].wire) { - new_conn.first.append(conn.first[i]); - new_conn.second.append(conn.second[i]); - } - if (GetSize(new_conn.first)) - connect(new_conn); - return; - } - - if (yosys_xtrace) { - log("#X# Connect (SigSig) in %s: %s = %s (%d bits)\n", log_id(this), log_signal(conn.first), log_signal(conn.second), GetSize(conn.first)); - log_backtrace("-X- ", yosys_xtrace-1); - } - - log_assert(GetSize(conn.first) == GetSize(conn.second)); - connections_.push_back(conn); -} - -void RTLIL::Module::connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs) -{ - connect(RTLIL::SigSig(lhs, rhs)); -} - -void RTLIL::Module::new_connections(const std::vector &new_conn) -{ - for (auto mon : monitors) - mon->notify_connect(this, new_conn); - - if (design) - for (auto mon : design->monitors) - mon->notify_connect(this, new_conn); - - if (yosys_xtrace) { - log("#X# New connections vector in %s:\n", log_id(this)); - for (auto &conn: new_conn) - log("#X# %s = %s (%d bits)\n", log_signal(conn.first), log_signal(conn.second), GetSize(conn.first)); - log_backtrace("-X- ", yosys_xtrace-1); - } - - connections_ = new_conn; -} - -const std::vector &RTLIL::Module::connections() const -{ - return connections_; -} - -void RTLIL::Module::fixup_ports() -{ - std::vector all_ports; - - for (auto &w : wires_) - if (w.second->port_input || w.second->port_output) - all_ports.push_back(w.second); - else - w.second->port_id = 0; - - std::sort(all_ports.begin(), all_ports.end(), fixup_ports_compare); - - ports.clear(); - for (size_t i = 0; i < all_ports.size(); i++) { - ports.push_back(all_ports[i]->name); - all_ports[i]->port_id = i+1; - } -} - -RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width) -{ - RTLIL::Wire *wire = new RTLIL::Wire; - wire->name = name; - wire->width = width; - add(wire); - return wire; -} - -RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *other) -{ - RTLIL::Wire *wire = addWire(name); - wire->width = other->width; - wire->start_offset = other->start_offset; - wire->port_id = other->port_id; - wire->port_input = other->port_input; - wire->port_output = other->port_output; - wire->upto = other->upto; - wire->attributes = other->attributes; - return wire; -} - -RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type) -{ - RTLIL::Cell *cell = new RTLIL::Cell; - cell->name = name; - cell->type = type; - add(cell); - return cell; -} - -RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *other) -{ - RTLIL::Cell *cell = addCell(name, other->type); - cell->connections_ = other->connections_; - cell->parameters = other->parameters; - cell->attributes = other->attributes; - return cell; -} - -#define DEF_METHOD(_func, _y_size, _type) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters["\\A_SIGNED"] = is_signed; \ - cell->parameters["\\A_WIDTH"] = sig_a.size(); \ - cell->parameters["\\Y_WIDTH"] = sig_y.size(); \ - cell->setPort("\\A", sig_a); \ - cell->setPort("\\Y", sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed, const std::string &src) { \ - RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \ - add ## _func(name, sig_a, sig_y, is_signed, src); \ - return sig_y; \ - } -DEF_METHOD(Not, sig_a.size(), "$not") -DEF_METHOD(Pos, sig_a.size(), "$pos") -DEF_METHOD(Neg, sig_a.size(), "$neg") -DEF_METHOD(ReduceAnd, 1, "$reduce_and") -DEF_METHOD(ReduceOr, 1, "$reduce_or") -DEF_METHOD(ReduceXor, 1, "$reduce_xor") -DEF_METHOD(ReduceXnor, 1, "$reduce_xnor") -DEF_METHOD(ReduceBool, 1, "$reduce_bool") -DEF_METHOD(LogicNot, 1, "$logic_not") -#undef DEF_METHOD - -#define DEF_METHOD(_func, _y_size, _type) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters["\\A_SIGNED"] = is_signed; \ - cell->parameters["\\B_SIGNED"] = is_signed; \ - cell->parameters["\\A_WIDTH"] = sig_a.size(); \ - cell->parameters["\\B_WIDTH"] = sig_b.size(); \ - cell->parameters["\\Y_WIDTH"] = sig_y.size(); \ - cell->setPort("\\A", sig_a); \ - cell->setPort("\\B", sig_b); \ - cell->setPort("\\Y", sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed, const std::string &src) { \ - RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \ - add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \ - return sig_y; \ - } -DEF_METHOD(And, max(sig_a.size(), sig_b.size()), "$and") -DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), "$or") -DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), "$xor") -DEF_METHOD(Xnor, max(sig_a.size(), sig_b.size()), "$xnor") -DEF_METHOD(Shl, sig_a.size(), "$shl") -DEF_METHOD(Shr, sig_a.size(), "$shr") -DEF_METHOD(Sshl, sig_a.size(), "$sshl") -DEF_METHOD(Sshr, sig_a.size(), "$sshr") -DEF_METHOD(Shift, sig_a.size(), "$shift") -DEF_METHOD(Shiftx, sig_a.size(), "$shiftx") -DEF_METHOD(Lt, 1, "$lt") -DEF_METHOD(Le, 1, "$le") -DEF_METHOD(Eq, 1, "$eq") -DEF_METHOD(Ne, 1, "$ne") -DEF_METHOD(Eqx, 1, "$eqx") -DEF_METHOD(Nex, 1, "$nex") -DEF_METHOD(Ge, 1, "$ge") -DEF_METHOD(Gt, 1, "$gt") -DEF_METHOD(Add, max(sig_a.size(), sig_b.size()), "$add") -DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), "$sub") -DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), "$mul") -DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), "$div") -DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), "$mod") -DEF_METHOD(LogicAnd, 1, "$logic_and") -DEF_METHOD(LogicOr, 1, "$logic_or") -#undef DEF_METHOD - -#define DEF_METHOD(_func, _type, _pmux) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters["\\WIDTH"] = sig_a.size(); \ - if (_pmux) cell->parameters["\\S_WIDTH"] = sig_s.size(); \ - cell->setPort("\\A", sig_a); \ - cell->setPort("\\B", sig_b); \ - cell->setPort("\\S", sig_s); \ - cell->setPort("\\Y", sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, const std::string &src) { \ - RTLIL::SigSpec sig_y = addWire(NEW_ID, sig_a.size()); \ - add ## _func(name, sig_a, sig_b, sig_s, sig_y, src); \ - return sig_y; \ - } -DEF_METHOD(Mux, "$mux", 0) -DEF_METHOD(Pmux, "$pmux", 1) -#undef DEF_METHOD - -#define DEF_METHOD_2(_func, _type, _P1, _P2) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->setPort("\\" #_P1, sig1); \ - cell->setPort("\\" #_P2, sig2); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, const std::string &src) { \ - RTLIL::SigBit sig2 = addWire(NEW_ID); \ - add ## _func(name, sig1, sig2, src); \ - return sig2; \ - } -#define DEF_METHOD_3(_func, _type, _P1, _P2, _P3) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->setPort("\\" #_P1, sig1); \ - cell->setPort("\\" #_P2, sig2); \ - cell->setPort("\\" #_P3, sig3); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, const std::string &src) { \ - RTLIL::SigBit sig3 = addWire(NEW_ID); \ - add ## _func(name, sig1, sig2, sig3, src); \ - return sig3; \ - } -#define DEF_METHOD_4(_func, _type, _P1, _P2, _P3, _P4) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->setPort("\\" #_P1, sig1); \ - cell->setPort("\\" #_P2, sig2); \ - cell->setPort("\\" #_P3, sig3); \ - cell->setPort("\\" #_P4, sig4); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, const std::string &src) { \ - RTLIL::SigBit sig4 = addWire(NEW_ID); \ - add ## _func(name, sig1, sig2, sig3, sig4, src); \ - return sig4; \ - } -#define DEF_METHOD_5(_func, _type, _P1, _P2, _P3, _P4, _P5) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, RTLIL::SigBit sig5, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->setPort("\\" #_P1, sig1); \ - cell->setPort("\\" #_P2, sig2); \ - cell->setPort("\\" #_P3, sig3); \ - cell->setPort("\\" #_P4, sig4); \ - cell->setPort("\\" #_P5, sig5); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, const std::string &src) { \ - RTLIL::SigBit sig5 = addWire(NEW_ID); \ - add ## _func(name, sig1, sig2, sig3, sig4, sig5, src); \ - return sig5; \ - } -DEF_METHOD_2(BufGate, "$_BUF_", A, Y) -DEF_METHOD_2(NotGate, "$_NOT_", A, Y) -DEF_METHOD_3(AndGate, "$_AND_", A, B, Y) -DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y) -DEF_METHOD_3(OrGate, "$_OR_", A, B, Y) -DEF_METHOD_3(NorGate, "$_NOR_", A, B, Y) -DEF_METHOD_3(XorGate, "$_XOR_", A, B, Y) -DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y) -DEF_METHOD_3(AndnotGate, "$_ANDNOT_", A, B, Y) -DEF_METHOD_3(OrnotGate, "$_ORNOT_", A, B, Y) -DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, Y) -DEF_METHOD_4(Aoi3Gate, "$_AOI3_", A, B, C, Y) -DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y) -DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y) -DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y) -#undef DEF_METHOD_2 -#undef DEF_METHOD_3 -#undef DEF_METHOD_4 -#undef DEF_METHOD_5 - -RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed, bool b_signed, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$pow"); - cell->parameters["\\A_SIGNED"] = a_signed; - cell->parameters["\\B_SIGNED"] = b_signed; - cell->parameters["\\A_WIDTH"] = sig_a.size(); - cell->parameters["\\B_WIDTH"] = sig_b.size(); - cell->parameters["\\Y_WIDTH"] = sig_y.size(); - cell->setPort("\\A", sig_a); - cell->setPort("\\B", sig_b); - cell->setPort("\\Y", sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$slice"); - cell->parameters["\\A_WIDTH"] = sig_a.size(); - cell->parameters["\\Y_WIDTH"] = sig_y.size(); - cell->parameters["\\OFFSET"] = offset; - cell->setPort("\\A", sig_a); - cell->setPort("\\Y", sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$concat"); - cell->parameters["\\A_WIDTH"] = sig_a.size(); - cell->parameters["\\B_WIDTH"] = sig_b.size(); - cell->setPort("\\A", sig_a); - cell->setPort("\\B", sig_b); - cell->setPort("\\Y", sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$lut"); - cell->parameters["\\LUT"] = lut; - cell->parameters["\\WIDTH"] = sig_a.size(); - cell->setPort("\\A", sig_a); - cell->setPort("\\Y", sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$tribuf"); - cell->parameters["\\WIDTH"] = sig_a.size(); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); - cell->setPort("\\Y", sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$assert"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$assume"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addLive(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$live"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addFair(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$fair"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addCover(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$cover"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$equiv"); - cell->setPort("\\A", sig_a); - cell->setPort("\\B", sig_b); - cell->setPort("\\Y", sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$sr"); - cell->parameters["\\SET_POLARITY"] = set_polarity; - cell->parameters["\\CLR_POLARITY"] = clr_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\SET", sig_set); - cell->setPort("\\CLR", sig_clr); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addFf(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$ff"); - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$dff"); - cell->parameters["\\CLK_POLARITY"] = clk_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\CLK", sig_clk); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$dffe"); - cell->parameters["\\CLK_POLARITY"] = clk_polarity; - cell->parameters["\\EN_POLARITY"] = en_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\CLK", sig_clk); - cell->setPort("\\EN", sig_en); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, - RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$dffsr"); - cell->parameters["\\CLK_POLARITY"] = clk_polarity; - cell->parameters["\\SET_POLARITY"] = set_polarity; - cell->parameters["\\CLR_POLARITY"] = clr_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\CLK", sig_clk); - cell->setPort("\\SET", sig_set); - cell->setPort("\\CLR", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, - RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$adff"); - cell->parameters["\\CLK_POLARITY"] = clk_polarity; - cell->parameters["\\ARST_POLARITY"] = arst_polarity; - cell->parameters["\\ARST_VALUE"] = arst_value; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\CLK", sig_clk); - cell->setPort("\\ARST", sig_arst); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$dlatch"); - cell->parameters["\\EN_POLARITY"] = en_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\EN", sig_en); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, - RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$dlatchsr"); - cell->parameters["\\EN_POLARITY"] = en_polarity; - cell->parameters["\\SET_POLARITY"] = set_polarity; - cell->parameters["\\CLR_POLARITY"] = clr_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\EN", sig_en); - cell->setPort("\\SET", sig_set); - cell->setPort("\\CLR", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, "$_FF_"); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N')); - cell->setPort("\\C", sig_clk); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffeGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); - cell->setPort("\\C", sig_clk); - cell->setPort("\\E", sig_en); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, - RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); - cell->setPort("\\C", sig_clk); - cell->setPort("\\S", sig_set); - cell->setPort("\\R", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, - bool arst_value, bool clk_polarity, bool arst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0')); - cell->setPort("\\C", sig_clk); - cell->setPort("\\R", sig_arst); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c_", en_polarity ? 'P' : 'N')); - cell->setPort("\\E", sig_en); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, - RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DLATCHSR_%c%c%c_", en_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); - cell->setPort("\\E", sig_en); - cell->setPort("\\S", sig_set); - cell->setPort("\\R", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src) -{ - RTLIL::SigSpec sig = addWire(NEW_ID, width); - Cell *cell = addCell(name, "$anyconst"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\Y", sig); - cell->set_src_attribute(src); - return sig; -} - -RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std::string &src) -{ - RTLIL::SigSpec sig = addWire(NEW_ID, width); - Cell *cell = addCell(name, "$anyseq"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\Y", sig); - cell->set_src_attribute(src); - return sig; -} - -RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const std::string &src) -{ - RTLIL::SigSpec sig = addWire(NEW_ID, width); - Cell *cell = addCell(name, "$allconst"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\Y", sig); - cell->set_src_attribute(src); - return sig; -} - -RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std::string &src) -{ - RTLIL::SigSpec sig = addWire(NEW_ID, width); - Cell *cell = addCell(name, "$allseq"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\Y", sig); - cell->set_src_attribute(src); - return sig; -} - -RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string &src) -{ - RTLIL::SigSpec sig = addWire(NEW_ID); - Cell *cell = addCell(name, "$initstate"); - cell->setPort("\\Y", sig); - cell->set_src_attribute(src); - return sig; -} - -RTLIL::Wire::Wire() -{ - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; - - module = nullptr; - width = 1; - start_offset = 0; - port_id = 0; - port_input = false; - port_output = false; - upto = false; - -#ifdef WITH_PYTHON - RTLIL::Wire::get_all_wires()->insert(std::pair(hashidx_, this)); -#endif -} - -RTLIL::Wire::~Wire() -{ -#ifdef WITH_PYTHON - RTLIL::Wire::get_all_wires()->erase(hashidx_); -#endif -} - -#ifdef WITH_PYTHON -static std::map all_wires; -std::map *RTLIL::Wire::get_all_wires(void) -{ - return &all_wires; -} -#endif - -RTLIL::Memory::Memory() -{ - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; - - width = 1; - start_offset = 0; - size = 0; -#ifdef WITH_PYTHON - RTLIL::Memory::get_all_memorys()->insert(std::pair(hashidx_, this)); -#endif -} - -RTLIL::Cell::Cell() : module(nullptr) -{ - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; - - // log("#memtrace# %p\n", this); - memhasher(); - -#ifdef WITH_PYTHON - RTLIL::Cell::get_all_cells()->insert(std::pair(hashidx_, this)); -#endif -} - -RTLIL::Cell::~Cell() -{ -#ifdef WITH_PYTHON - RTLIL::Cell::get_all_cells()->erase(hashidx_); -#endif -} - -#ifdef WITH_PYTHON -static std::map all_cells; -std::map *RTLIL::Cell::get_all_cells(void) -{ - return &all_cells; -} -#endif - -bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const -{ - return connections_.count(portname) != 0; -} - -void RTLIL::Cell::unsetPort(RTLIL::IdString portname) -{ - RTLIL::SigSpec signal; - auto conn_it = connections_.find(portname); - - if (conn_it != connections_.end()) - { - for (auto mon : module->monitors) - mon->notify_connect(this, conn_it->first, conn_it->second, signal); - - if (module->design) - for (auto mon : module->design->monitors) - mon->notify_connect(this, conn_it->first, conn_it->second, signal); - - if (yosys_xtrace) { - log("#X# Unconnect %s.%s.%s\n", log_id(this->module), log_id(this), log_id(portname)); - log_backtrace("-X- ", yosys_xtrace-1); - } - - connections_.erase(conn_it); - } -} - -void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) -{ - auto conn_it = connections_.find(portname); - - if (conn_it == connections_.end()) { - connections_[portname] = RTLIL::SigSpec(); - conn_it = connections_.find(portname); - log_assert(conn_it != connections_.end()); - } else - if (conn_it->second == signal) - return; - - for (auto mon : module->monitors) - mon->notify_connect(this, conn_it->first, conn_it->second, signal); - - if (module->design) - for (auto mon : module->design->monitors) - mon->notify_connect(this, conn_it->first, conn_it->second, signal); - - if (yosys_xtrace) { - log("#X# Connect %s.%s.%s = %s (%d)\n", log_id(this->module), log_id(this), log_id(portname), log_signal(signal), GetSize(signal)); - log_backtrace("-X- ", yosys_xtrace-1); - } - - conn_it->second = signal; -} - -const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const -{ - return connections_.at(portname); -} - -const dict &RTLIL::Cell::connections() const -{ - return connections_; -} - -bool RTLIL::Cell::known() const -{ - if (yosys_celltypes.cell_known(type)) - return true; - if (module && module->design && module->design->module(type)) - return true; - return false; -} - -bool RTLIL::Cell::input(RTLIL::IdString portname) const -{ - if (yosys_celltypes.cell_known(type)) - return yosys_celltypes.cell_input(type, portname); - if (module && module->design) { - RTLIL::Module *m = module->design->module(type); - RTLIL::Wire *w = m ? m->wire(portname) : nullptr; - return w && w->port_input; - } - return false; -} - -bool RTLIL::Cell::output(RTLIL::IdString portname) const -{ - if (yosys_celltypes.cell_known(type)) - return yosys_celltypes.cell_output(type, portname); - if (module && module->design) { - RTLIL::Module *m = module->design->module(type); - RTLIL::Wire *w = m ? m->wire(portname) : nullptr; - return w && w->port_output; - } - return false; -} - -bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const -{ - return parameters.count(paramname) != 0; -} - -void RTLIL::Cell::unsetParam(RTLIL::IdString paramname) -{ - parameters.erase(paramname); -} - -void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value) -{ - parameters[paramname] = value; -} - -const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const -{ - return parameters.at(paramname); -} - -void RTLIL::Cell::sort() -{ - connections_.sort(sort_by_id_str()); - parameters.sort(sort_by_id_str()); - attributes.sort(sort_by_id_str()); -} - -void RTLIL::Cell::check() -{ -#ifndef NDEBUG - InternalCellChecker checker(NULL, this); - checker.check(); -#endif -} - -void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) -{ - if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" || - type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:") - return; - - if (type == "$mux" || type == "$pmux") { - parameters["\\WIDTH"] = GetSize(connections_["\\Y"]); - if (type == "$pmux") - parameters["\\S_WIDTH"] = GetSize(connections_["\\S"]); - check(); - return; - } - - if (type == "$lut" || type == "$sop") { - parameters["\\WIDTH"] = GetSize(connections_["\\A"]); - return; - } - - if (type == "$fa") { - parameters["\\WIDTH"] = GetSize(connections_["\\Y"]); - return; - } - - if (type == "$lcu") { - parameters["\\WIDTH"] = GetSize(connections_["\\CO"]); - return; - } - - bool signedness_ab = !type.in("$slice", "$concat", "$macc"); - - if (connections_.count("\\A")) { - if (signedness_ab) { - if (set_a_signed) - parameters["\\A_SIGNED"] = true; - else if (parameters.count("\\A_SIGNED") == 0) - parameters["\\A_SIGNED"] = false; - } - parameters["\\A_WIDTH"] = GetSize(connections_["\\A"]); - } - - if (connections_.count("\\B")) { - if (signedness_ab) { - if (set_b_signed) - parameters["\\B_SIGNED"] = true; - else if (parameters.count("\\B_SIGNED") == 0) - parameters["\\B_SIGNED"] = false; - } - parameters["\\B_WIDTH"] = GetSize(connections_["\\B"]); - } - - if (connections_.count("\\Y")) - parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]); - - if (connections_.count("\\Q")) - parameters["\\WIDTH"] = GetSize(connections_["\\Q"]); - - check(); -} - -RTLIL::SigChunk::SigChunk() -{ - wire = NULL; - width = 0; - offset = 0; -} - -RTLIL::SigChunk::SigChunk(const RTLIL::Const &value) -{ - wire = NULL; - data = value.bits; - width = GetSize(data); - offset = 0; -} - -RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire) -{ - log_assert(wire != nullptr); - this->wire = wire; - this->width = wire->width; - this->offset = 0; -} - -RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int offset, int width) -{ - log_assert(wire != nullptr); - this->wire = wire; - this->width = width; - this->offset = offset; -} - -RTLIL::SigChunk::SigChunk(const std::string &str) -{ - wire = NULL; - data = RTLIL::Const(str).bits; - width = GetSize(data); - offset = 0; -} - -RTLIL::SigChunk::SigChunk(int val, int width) -{ - wire = NULL; - data = RTLIL::Const(val, width).bits; - this->width = GetSize(data); - offset = 0; -} - -RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width) -{ - wire = NULL; - data = RTLIL::Const(bit, width).bits; - this->width = GetSize(data); - offset = 0; -} - -RTLIL::SigChunk::SigChunk(RTLIL::SigBit bit) -{ - wire = bit.wire; - offset = 0; - if (wire == NULL) - data = RTLIL::Const(bit.data).bits; - else - offset = bit.offset; - width = 1; -} - -RTLIL::SigChunk::SigChunk(const RTLIL::SigChunk &sigchunk) : data(sigchunk.data) -{ - wire = sigchunk.wire; - data = sigchunk.data; - width = sigchunk.width; - offset = sigchunk.offset; -} - -RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const -{ - RTLIL::SigChunk ret; - if (wire) { - ret.wire = wire; - ret.offset = this->offset + offset; - ret.width = length; - } else { - for (int i = 0; i < length; i++) - ret.data.push_back(data[offset+i]); - ret.width = length; - } - return ret; -} - -bool RTLIL::SigChunk::operator <(const RTLIL::SigChunk &other) const -{ - if (wire && other.wire) - if (wire->name != other.wire->name) - return wire->name < other.wire->name; - - if (wire != other.wire) - return wire < other.wire; - - if (offset != other.offset) - return offset < other.offset; - - if (width != other.width) - return width < other.width; - - return data < other.data; -} - -bool RTLIL::SigChunk::operator ==(const RTLIL::SigChunk &other) const -{ - return wire == other.wire && width == other.width && offset == other.offset && data == other.data; -} - -bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const -{ - if (*this == other) - return false; - return true; -} - -RTLIL::SigSpec::SigSpec() -{ - width_ = 0; - hash_ = 0; -} - -RTLIL::SigSpec::SigSpec(const RTLIL::SigSpec &other) -{ - *this = other; -} - -RTLIL::SigSpec::SigSpec(std::initializer_list parts) -{ - cover("kernel.rtlil.sigspec.init.list"); - - width_ = 0; - hash_ = 0; - - std::vector parts_vec(parts.begin(), parts.end()); - for (auto it = parts_vec.rbegin(); it != parts_vec.rend(); it++) - append(*it); -} - -const RTLIL::SigSpec &RTLIL::SigSpec::operator=(const RTLIL::SigSpec &other) -{ - cover("kernel.rtlil.sigspec.assign"); - - width_ = other.width_; - hash_ = other.hash_; - chunks_ = other.chunks_; - bits_.clear(); - - if (!other.bits_.empty()) - { - RTLIL::SigChunk *last = NULL; - int last_end_offset = 0; - - for (auto &bit : other.bits_) { - if (last && bit.wire == last->wire) { - if (bit.wire == NULL) { - last->data.push_back(bit.data); - last->width++; - continue; - } else if (last_end_offset == bit.offset) { - last_end_offset++; - last->width++; - continue; - } - } - chunks_.push_back(bit); - last = &chunks_.back(); - last_end_offset = bit.offset + 1; - } - - check(); - } - - return *this; -} - -RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) -{ - cover("kernel.rtlil.sigspec.init.const"); - - chunks_.push_back(RTLIL::SigChunk(value)); - width_ = chunks_.back().width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) -{ - cover("kernel.rtlil.sigspec.init.chunk"); - - chunks_.push_back(chunk); - width_ = chunks_.back().width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) -{ - cover("kernel.rtlil.sigspec.init.wire"); - - chunks_.push_back(RTLIL::SigChunk(wire)); - width_ = chunks_.back().width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) -{ - cover("kernel.rtlil.sigspec.init.wire_part"); - - chunks_.push_back(RTLIL::SigChunk(wire, offset, width)); - width_ = chunks_.back().width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(const std::string &str) -{ - cover("kernel.rtlil.sigspec.init.str"); - - chunks_.push_back(RTLIL::SigChunk(str)); - width_ = chunks_.back().width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(int val, int width) -{ - cover("kernel.rtlil.sigspec.init.int"); - - chunks_.push_back(RTLIL::SigChunk(val, width)); - width_ = width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) -{ - cover("kernel.rtlil.sigspec.init.state"); - - chunks_.push_back(RTLIL::SigChunk(bit, width)); - width_ = width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::SigBit bit, int width) -{ - cover("kernel.rtlil.sigspec.init.bit"); - - if (bit.wire == NULL) - chunks_.push_back(RTLIL::SigChunk(bit.data, width)); - else - for (int i = 0; i < width; i++) - chunks_.push_back(bit); - width_ = width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(std::vector chunks) -{ - cover("kernel.rtlil.sigspec.init.stdvec_chunks"); - - width_ = 0; - hash_ = 0; - for (auto &c : chunks) - append(c); - check(); -} - -RTLIL::SigSpec::SigSpec(std::vector bits) -{ - cover("kernel.rtlil.sigspec.init.stdvec_bits"); - - width_ = 0; - hash_ = 0; - for (auto &bit : bits) - append_bit(bit); - check(); -} - -RTLIL::SigSpec::SigSpec(pool bits) -{ - cover("kernel.rtlil.sigspec.init.pool_bits"); - - width_ = 0; - hash_ = 0; - for (auto &bit : bits) - append_bit(bit); - check(); -} - -RTLIL::SigSpec::SigSpec(std::set bits) -{ - cover("kernel.rtlil.sigspec.init.stdset_bits"); - - width_ = 0; - hash_ = 0; - for (auto &bit : bits) - append_bit(bit); - check(); -} - -RTLIL::SigSpec::SigSpec(bool bit) -{ - cover("kernel.rtlil.sigspec.init.bool"); - - width_ = 0; - hash_ = 0; - append_bit(bit); - check(); -} - -void RTLIL::SigSpec::pack() const -{ - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->bits_.empty()) - return; - - cover("kernel.rtlil.sigspec.convert.pack"); - log_assert(that->chunks_.empty()); - - std::vector old_bits; - old_bits.swap(that->bits_); - - RTLIL::SigChunk *last = NULL; - int last_end_offset = 0; - - for (auto &bit : old_bits) { - if (last && bit.wire == last->wire) { - if (bit.wire == NULL) { - last->data.push_back(bit.data); - last->width++; - continue; - } else if (last_end_offset == bit.offset) { - last_end_offset++; - last->width++; - continue; - } - } - that->chunks_.push_back(bit); - last = &that->chunks_.back(); - last_end_offset = bit.offset + 1; - } - - check(); -} - -void RTLIL::SigSpec::unpack() const -{ - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->chunks_.empty()) - return; - - cover("kernel.rtlil.sigspec.convert.unpack"); - log_assert(that->bits_.empty()); - - that->bits_.reserve(that->width_); - for (auto &c : that->chunks_) - for (int i = 0; i < c.width; i++) - that->bits_.push_back(RTLIL::SigBit(c, i)); - - that->chunks_.clear(); - that->hash_ = 0; -} - -void RTLIL::SigSpec::updhash() const -{ - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->hash_ != 0) - return; - - cover("kernel.rtlil.sigspec.hash"); - that->pack(); - - that->hash_ = mkhash_init; - for (auto &c : that->chunks_) - if (c.wire == NULL) { - for (auto &v : c.data) - that->hash_ = mkhash(that->hash_, 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); - } - - if (that->hash_ == 0) - that->hash_ = 1; -} - -void RTLIL::SigSpec::sort() -{ - unpack(); - cover("kernel.rtlil.sigspec.sort"); - std::sort(bits_.begin(), bits_.end()); -} - -void RTLIL::SigSpec::sort_and_unify() -{ - unpack(); - cover("kernel.rtlil.sigspec.sort_and_unify"); - - // A copy of the bits vector is used to prevent duplicating the logic from - // SigSpec::SigSpec(std::vector). This incurrs an extra copy but - // that isn't showing up as significant in profiles. - std::vector unique_bits = bits_; - std::sort(unique_bits.begin(), unique_bits.end()); - auto last = std::unique(unique_bits.begin(), unique_bits.end()); - unique_bits.erase(last, unique_bits.end()); - - *this = unique_bits; -} - -void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) -{ - replace(pattern, with, this); -} - -void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const -{ - log_assert(other != NULL); - log_assert(width_ == other->width_); - log_assert(pattern.width_ == with.width_); - - pattern.unpack(); - with.unpack(); - unpack(); - other->unpack(); - - for (int i = 0; i < GetSize(pattern.bits_); i++) { - if (pattern.bits_[i].wire != NULL) { - for (int j = 0; j < GetSize(bits_); j++) { - if (bits_[j] == pattern.bits_[i]) { - other->bits_[j] = with.bits_[i]; - } - } - } - } - - other->check(); -} - -void RTLIL::SigSpec::replace(const dict &rules) -{ - replace(rules, this); -} - -void RTLIL::SigSpec::replace(const dict &rules, RTLIL::SigSpec *other) const -{ - cover("kernel.rtlil.sigspec.replace_dict"); - - log_assert(other != NULL); - log_assert(width_ == other->width_); - - unpack(); - other->unpack(); - - for (int i = 0; i < GetSize(bits_); i++) { - auto it = rules.find(bits_[i]); - if (it != rules.end()) - other->bits_[i] = it->second; - } - - other->check(); -} - -void RTLIL::SigSpec::replace(const std::map &rules) -{ - replace(rules, this); -} - -void RTLIL::SigSpec::replace(const std::map &rules, RTLIL::SigSpec *other) const -{ - cover("kernel.rtlil.sigspec.replace_map"); - - log_assert(other != NULL); - log_assert(width_ == other->width_); - - unpack(); - other->unpack(); - - for (int i = 0; i < GetSize(bits_); i++) { - auto it = rules.find(bits_[i]); - if (it != rules.end()) - other->bits_[i] = it->second; - } - - other->check(); -} - -void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern) -{ - remove2(pattern, NULL); -} - -void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const -{ - RTLIL::SigSpec tmp = *this; - tmp.remove2(pattern, other); -} - -void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) -{ - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - - unpack(); - if (other != NULL) { - log_assert(width_ == other->width_); - other->unpack(); - } - - for (int i = GetSize(bits_) - 1; i >= 0; i--) - { - if (bits_[i].wire == NULL) continue; - - for (auto &pattern_chunk : pattern.chunks()) - if (bits_[i].wire == pattern_chunk.wire && - bits_[i].offset >= pattern_chunk.offset && - bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) { - bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { - other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } - break; - } - } - - check(); -} - -void RTLIL::SigSpec::remove(const pool &pattern) -{ - remove2(pattern, NULL); -} - -void RTLIL::SigSpec::remove(const pool &pattern, RTLIL::SigSpec *other) const -{ - RTLIL::SigSpec tmp = *this; - tmp.remove2(pattern, other); -} - -void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec *other) -{ - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - - unpack(); - - if (other != NULL) { - log_assert(width_ == other->width_); - other->unpack(); - } - - for (int i = GetSize(bits_) - 1; i >= 0; i--) { - if (bits_[i].wire != NULL && pattern.count(bits_[i])) { - bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { - other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } - } - } - - check(); -} - -void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigSpec *other) -{ - if (other) - cover("kernel.rtlil.sigspec.remove_other"); - else - cover("kernel.rtlil.sigspec.remove"); - - unpack(); - - if (other != NULL) { - log_assert(width_ == other->width_); - other->unpack(); - } - - for (int i = GetSize(bits_) - 1; i >= 0; i--) { - if (bits_[i].wire != NULL && pattern.count(bits_[i])) { - bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { - other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } - } - } - - check(); -} - -RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const -{ - if (other) - cover("kernel.rtlil.sigspec.extract_other"); - else - cover("kernel.rtlil.sigspec.extract"); - - log_assert(other == NULL || width_ == other->width_); - - RTLIL::SigSpec ret; - std::vector bits_match = to_sigbit_vector(); - - for (auto& pattern_chunk : pattern.chunks()) { - if (other) { - std::vector bits_other = other->to_sigbit_vector(); - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && - bits_match[i].wire == pattern_chunk.wire && - bits_match[i].offset >= pattern_chunk.offset && - bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width) - ret.append_bit(bits_other[i]); - } else { - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && - bits_match[i].wire == pattern_chunk.wire && - bits_match[i].offset >= pattern_chunk.offset && - bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width) - ret.append_bit(bits_match[i]); - } - } - - ret.check(); - return ret; -} - -RTLIL::SigSpec RTLIL::SigSpec::extract(const pool &pattern, const RTLIL::SigSpec *other) const -{ - if (other) - cover("kernel.rtlil.sigspec.extract_other"); - else - cover("kernel.rtlil.sigspec.extract"); - - log_assert(other == NULL || width_ == other->width_); - - std::vector bits_match = to_sigbit_vector(); - RTLIL::SigSpec ret; - - if (other) { - std::vector bits_other = other->to_sigbit_vector(); - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && pattern.count(bits_match[i])) - ret.append_bit(bits_other[i]); - } else { - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && pattern.count(bits_match[i])) - ret.append_bit(bits_match[i]); - } - - ret.check(); - return ret; -} - -void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) -{ - cover("kernel.rtlil.sigspec.replace_pos"); - - unpack(); - with.unpack(); - - log_assert(offset >= 0); - log_assert(with.width_ >= 0); - log_assert(offset+with.width_ <= width_); - - for (int i = 0; i < with.width_; i++) - bits_.at(offset + i) = with.bits_.at(i); - - check(); -} - -void RTLIL::SigSpec::remove_const() -{ - if (packed()) - { - cover("kernel.rtlil.sigspec.remove_const.packed"); - - std::vector new_chunks; - new_chunks.reserve(GetSize(chunks_)); - - width_ = 0; - for (auto &chunk : chunks_) - if (chunk.wire != NULL) { - new_chunks.push_back(chunk); - width_ += chunk.width; - } - - chunks_.swap(new_chunks); - } - else - { - cover("kernel.rtlil.sigspec.remove_const.unpacked"); - - std::vector new_bits; - new_bits.reserve(width_); - - for (auto &bit : bits_) - if (bit.wire != NULL) - new_bits.push_back(bit); - - bits_.swap(new_bits); - width_ = bits_.size(); - } - - check(); -} - -void RTLIL::SigSpec::remove(int offset, int length) -{ - cover("kernel.rtlil.sigspec.remove_pos"); - - unpack(); - - log_assert(offset >= 0); - log_assert(length >= 0); - log_assert(offset + length <= width_); - - bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); - width_ = bits_.size(); - - check(); -} - -RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const -{ - unpack(); - cover("kernel.rtlil.sigspec.extract_pos"); - return std::vector(bits_.begin() + offset, bits_.begin() + offset + length); -} - -void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) -{ - if (signal.width_ == 0) - return; - - if (width_ == 0) { - *this = signal; - return; - } - - cover("kernel.rtlil.sigspec.append"); - - if (packed() != signal.packed()) { - pack(); - signal.pack(); - } - - if (packed()) - for (auto &other_c : signal.chunks_) - { - auto &my_last_c = chunks_.back(); - if (my_last_c.wire == NULL && other_c.wire == NULL) { - auto &this_data = my_last_c.data; - auto &other_data = other_c.data; - this_data.insert(this_data.end(), other_data.begin(), other_data.end()); - my_last_c.width += other_c.width; - } else - if (my_last_c.wire == other_c.wire && my_last_c.offset + my_last_c.width == other_c.offset) { - my_last_c.width += other_c.width; - } else - chunks_.push_back(other_c); - } - else - bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); - - width_ += signal.width_; - check(); -} - -void RTLIL::SigSpec::append_bit(const RTLIL::SigBit &bit) -{ - if (packed()) - { - cover("kernel.rtlil.sigspec.append_bit.packed"); - - if (chunks_.size() == 0) - chunks_.push_back(bit); - else - if (bit.wire == NULL) - if (chunks_.back().wire == NULL) { - chunks_.back().data.push_back(bit.data); - chunks_.back().width++; - } else - chunks_.push_back(bit); - else - if (chunks_.back().wire == bit.wire && chunks_.back().offset + chunks_.back().width == bit.offset) - chunks_.back().width++; - else - chunks_.push_back(bit); - } - else - { - cover("kernel.rtlil.sigspec.append_bit.unpacked"); - bits_.push_back(bit); - } - - width_++; - check(); -} - -void RTLIL::SigSpec::extend_u0(int width, bool is_signed) -{ - cover("kernel.rtlil.sigspec.extend_u0"); - - pack(); - - if (width_ > width) - remove(width, width_ - width); - - if (width_ < width) { - RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx; - if (!is_signed) - padding = RTLIL::State::S0; - while (width_ < width) - append(padding); - } - -} - -RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const -{ - cover("kernel.rtlil.sigspec.repeat"); - - RTLIL::SigSpec sig; - for (int i = 0; i < num; i++) - sig.append(*this); - return sig; -} - -#ifndef NDEBUG -void RTLIL::SigSpec::check() const -{ - if (width_ > 64) - { - cover("kernel.rtlil.sigspec.check.skip"); - } - else if (packed()) - { - cover("kernel.rtlil.sigspec.check.packed"); - - int w = 0; - for (size_t i = 0; i < chunks_.size(); i++) { - const RTLIL::SigChunk chunk = chunks_[i]; - if (chunk.wire == NULL) { - if (i > 0) - log_assert(chunks_[i-1].wire != NULL); - log_assert(chunk.offset == 0); - log_assert(chunk.data.size() == (size_t)chunk.width); - } else { - if (i > 0 && chunks_[i-1].wire == chunk.wire) - log_assert(chunk.offset != chunks_[i-1].offset + chunks_[i-1].width); - log_assert(chunk.offset >= 0); - log_assert(chunk.width >= 0); - log_assert(chunk.offset + chunk.width <= chunk.wire->width); - log_assert(chunk.data.size() == 0); - } - w += chunk.width; - } - log_assert(w == width_); - log_assert(bits_.empty()); - } - else - { - cover("kernel.rtlil.sigspec.check.unpacked"); - - log_assert(width_ == GetSize(bits_)); - log_assert(chunks_.empty()); - } -} -#endif - -bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const -{ - cover("kernel.rtlil.sigspec.comp_lt"); - - if (this == &other) - return false; - - if (width_ != other.width_) - return width_ < other.width_; - - pack(); - other.pack(); - - if (chunks_.size() != other.chunks_.size()) - return chunks_.size() < other.chunks_.size(); - - updhash(); - other.updhash(); - - if (hash_ != other.hash_) - return hash_ < other.hash_; - - for (size_t i = 0; i < chunks_.size(); i++) - if (chunks_[i] != other.chunks_[i]) { - cover("kernel.rtlil.sigspec.comp_lt.hash_collision"); - return chunks_[i] < other.chunks_[i]; - } - - cover("kernel.rtlil.sigspec.comp_lt.equal"); - return false; -} - -bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const -{ - cover("kernel.rtlil.sigspec.comp_eq"); - - if (this == &other) - return true; - - if (width_ != other.width_) - return false; - - pack(); - other.pack(); - - if (chunks_.size() != other.chunks_.size()) - return false; - - updhash(); - other.updhash(); - - if (hash_ != other.hash_) - return false; - - for (size_t i = 0; i < chunks_.size(); i++) - if (chunks_[i] != other.chunks_[i]) { - cover("kernel.rtlil.sigspec.comp_eq.hash_collision"); - return false; - } - - cover("kernel.rtlil.sigspec.comp_eq.equal"); - return true; -} - -bool RTLIL::SigSpec::is_wire() const -{ - cover("kernel.rtlil.sigspec.is_wire"); - - pack(); - return GetSize(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_; -} - -bool RTLIL::SigSpec::is_chunk() const -{ - cover("kernel.rtlil.sigspec.is_chunk"); - - pack(); - return GetSize(chunks_) == 1; -} - -bool RTLIL::SigSpec::is_fully_const() const -{ - cover("kernel.rtlil.sigspec.is_fully_const"); - - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire != NULL) - return false; - return true; -} - -bool RTLIL::SigSpec::is_fully_zero() const -{ - cover("kernel.rtlil.sigspec.is_fully_zero"); - - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) - return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S0) - return false; - } - return true; -} - -bool RTLIL::SigSpec::is_fully_ones() const -{ - cover("kernel.rtlil.sigspec.is_fully_ones"); - - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) - return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S1) - return false; - } - return true; -} - -bool RTLIL::SigSpec::is_fully_def() const -{ - cover("kernel.rtlil.sigspec.is_fully_def"); - - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) - return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S0 && it->data[i] != RTLIL::State::S1) - return false; - } - return true; -} - -bool RTLIL::SigSpec::is_fully_undef() const -{ - cover("kernel.rtlil.sigspec.is_fully_undef"); - - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) - return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::Sx && it->data[i] != RTLIL::State::Sz) - return false; - } - return true; -} - -bool RTLIL::SigSpec::has_const() const -{ - cover("kernel.rtlil.sigspec.has_const"); - - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire == NULL) - return true; - return false; -} - -bool RTLIL::SigSpec::has_marked_bits() const -{ - cover("kernel.rtlil.sigspec.has_marked_bits"); - - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire == NULL) { - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] == RTLIL::State::Sm) - return true; - } - return false; -} - -bool RTLIL::SigSpec::as_bool() const -{ - cover("kernel.rtlil.sigspec.as_bool"); - - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).as_bool(); - return false; -} - -int RTLIL::SigSpec::as_int(bool is_signed) const -{ - cover("kernel.rtlil.sigspec.as_int"); - - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).as_int(is_signed); - return 0; -} - -std::string RTLIL::SigSpec::as_string() const -{ - cover("kernel.rtlil.sigspec.as_string"); - - pack(); - std::string str; - for (size_t i = chunks_.size(); i > 0; i--) { - const RTLIL::SigChunk &chunk = chunks_[i-1]; - if (chunk.wire != NULL) - for (int j = 0; j < chunk.width; j++) - str += "?"; - else - str += RTLIL::Const(chunk.data).as_string(); - } - return str; -} - -RTLIL::Const RTLIL::SigSpec::as_const() const -{ - cover("kernel.rtlil.sigspec.as_const"); - - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return chunks_[0].data; - return RTLIL::Const(); -} - -RTLIL::Wire *RTLIL::SigSpec::as_wire() const -{ - cover("kernel.rtlil.sigspec.as_wire"); - - pack(); - log_assert(is_wire()); - return chunks_[0].wire; -} - -RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const -{ - cover("kernel.rtlil.sigspec.as_chunk"); - - pack(); - log_assert(is_chunk()); - return chunks_[0]; -} - -RTLIL::SigBit RTLIL::SigSpec::as_bit() const -{ - cover("kernel.rtlil.sigspec.as_bit"); - - log_assert(width_ == 1); - if (packed()) - return RTLIL::SigBit(*chunks_.begin()); - else - return bits_[0]; -} - -bool RTLIL::SigSpec::match(std::string pattern) const -{ - cover("kernel.rtlil.sigspec.match"); - - pack(); - std::string str = as_string(); - log_assert(pattern.size() == str.size()); - - for (size_t i = 0; i < pattern.size(); i++) { - if (pattern[i] == ' ') - continue; - if (pattern[i] == '*') { - if (str[i] != 'z' && str[i] != 'x') - return false; - continue; - } - if (pattern[i] != str[i]) - return false; - } - - return true; -} - -std::set RTLIL::SigSpec::to_sigbit_set() const -{ - cover("kernel.rtlil.sigspec.to_sigbit_set"); - - pack(); - std::set sigbits; - for (auto &c : chunks_) - for (int i = 0; i < c.width; i++) - sigbits.insert(RTLIL::SigBit(c, i)); - return sigbits; -} - -pool RTLIL::SigSpec::to_sigbit_pool() const -{ - cover("kernel.rtlil.sigspec.to_sigbit_pool"); - - pack(); - pool sigbits; - for (auto &c : chunks_) - for (int i = 0; i < c.width; i++) - sigbits.insert(RTLIL::SigBit(c, i)); - return sigbits; -} - -std::vector RTLIL::SigSpec::to_sigbit_vector() const -{ - cover("kernel.rtlil.sigspec.to_sigbit_vector"); - - unpack(); - return bits_; -} - -std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL::SigSpec &other) const -{ - cover("kernel.rtlil.sigspec.to_sigbit_map"); - - unpack(); - other.unpack(); - - log_assert(width_ == other.width_); - - std::map new_map; - for (int i = 0; i < width_; i++) - new_map[bits_[i]] = other.bits_[i]; - - return new_map; -} - -dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::SigSpec &other) const -{ - cover("kernel.rtlil.sigspec.to_sigbit_dict"); - - unpack(); - other.unpack(); - - log_assert(width_ == other.width_); - - dict new_map; - for (int i = 0; i < width_; i++) - new_map[bits_[i]] = other.bits_[i]; - - return new_map; -} - -static void sigspec_parse_split(std::vector &tokens, const std::string &text, char sep) -{ - size_t start = 0, end = 0; - while ((end = text.find(sep, start)) != std::string::npos) { - tokens.push_back(text.substr(start, end - start)); - start = end + 1; - } - tokens.push_back(text.substr(start)); -} - -static int sigspec_parse_get_dummy_line_num() -{ - return 0; -} - -bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) -{ - cover("kernel.rtlil.sigspec.parse"); - - AST::current_filename = "input"; - AST::use_internal_line_num(); - AST::set_line_num(0); - - std::vector tokens; - sigspec_parse_split(tokens, str, ','); - - sig = RTLIL::SigSpec(); - for (int tokidx = int(tokens.size())-1; tokidx >= 0; tokidx--) - { - std::string netname = tokens[tokidx]; - std::string indices; - - if (netname.size() == 0) - continue; - - if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { - cover("kernel.rtlil.sigspec.parse.const"); - AST::get_line_num = sigspec_parse_get_dummy_line_num; - AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname); - if (ast == NULL) - return false; - sig.append(RTLIL::Const(ast->bits)); - delete ast; - continue; - } - - if (module == NULL) - return false; - - cover("kernel.rtlil.sigspec.parse.net"); - - if (netname[0] != '$' && netname[0] != '\\') - netname = "\\" + netname; - - if (module->wires_.count(netname) == 0) { - size_t indices_pos = netname.size()-1; - if (indices_pos > 2 && netname[indices_pos] == ']') - { - indices_pos--; - while (indices_pos > 0 && ('0' <= netname[indices_pos] && netname[indices_pos] <= '9')) indices_pos--; - if (indices_pos > 0 && netname[indices_pos] == ':') { - indices_pos--; - while (indices_pos > 0 && ('0' <= netname[indices_pos] && netname[indices_pos] <= '9')) indices_pos--; - } - if (indices_pos > 0 && netname[indices_pos] == '[') { - indices = netname.substr(indices_pos); - netname = netname.substr(0, indices_pos); - } - } - } - - if (module->wires_.count(netname) == 0) - return false; - - RTLIL::Wire *wire = module->wires_.at(netname); - if (!indices.empty()) { - std::vector index_tokens; - sigspec_parse_split(index_tokens, indices.substr(1, indices.size()-2), ':'); - if (index_tokens.size() == 1) { - cover("kernel.rtlil.sigspec.parse.bit_sel"); - int a = atoi(index_tokens.at(0).c_str()); - if (a < 0 || a >= wire->width) - return false; - sig.append(RTLIL::SigSpec(wire, a)); - } else { - cover("kernel.rtlil.sigspec.parse.part_sel"); - int a = atoi(index_tokens.at(0).c_str()); - int b = atoi(index_tokens.at(1).c_str()); - if (a > b) { - int tmp = a; - a = b, b = tmp; - } - if (a < 0 || a >= wire->width) - return false; - if (b < 0 || b >= wire->width) - return false; - sig.append(RTLIL::SigSpec(wire, a, b-a+1)); - } - } else - sig.append(wire); - } - - return true; -} - -bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str) -{ - if (str.empty() || str[0] != '@') - return parse(sig, module, str); - - cover("kernel.rtlil.sigspec.parse.sel"); - - str = RTLIL::escape_id(str.substr(1)); - if (design->selection_vars.count(str) == 0) - return false; - - sig = RTLIL::SigSpec(); - RTLIL::Selection &sel = design->selection_vars.at(str); - for (auto &it : module->wires_) - if (sel.selected_member(module->name, it.first)) - sig.append(it.second); - - return true; -} - -bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) -{ - if (str == "0") { - cover("kernel.rtlil.sigspec.parse.rhs_zeros"); - sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.width_); - return true; - } - - if (str == "~0") { - cover("kernel.rtlil.sigspec.parse.rhs_ones"); - sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.width_); - return true; - } - - if (lhs.chunks_.size() == 1) { - char *p = (char*)str.c_str(), *endptr; - long int val = strtol(p, &endptr, 10); - if (endptr && endptr != p && *endptr == 0) { - sig = RTLIL::SigSpec(val, lhs.width_); - cover("kernel.rtlil.sigspec.parse.rhs_dec"); - return true; - } - } - - return parse(sig, module, str); -} - -RTLIL::CaseRule::~CaseRule() -{ - for (auto it = switches.begin(); it != switches.end(); it++) - delete *it; -} - -bool RTLIL::CaseRule::empty() const -{ - return actions.empty() && switches.empty(); -} - -RTLIL::CaseRule *RTLIL::CaseRule::clone() const -{ - RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule; - new_caserule->compare = compare; - new_caserule->actions = actions; - for (auto &it : switches) - new_caserule->switches.push_back(it->clone()); - return new_caserule; -} - -RTLIL::SwitchRule::~SwitchRule() -{ - for (auto it = cases.begin(); it != cases.end(); it++) - delete *it; -} - -bool RTLIL::SwitchRule::empty() const -{ - return cases.empty(); -} - -RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const -{ - RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule; - new_switchrule->signal = signal; - new_switchrule->attributes = attributes; - for (auto &it : cases) - new_switchrule->cases.push_back(it->clone()); - return new_switchrule; - -} - -RTLIL::SyncRule *RTLIL::SyncRule::clone() const -{ - RTLIL::SyncRule *new_syncrule = new RTLIL::SyncRule; - new_syncrule->type = type; - new_syncrule->signal = signal; - new_syncrule->actions = actions; - return new_syncrule; -} - -RTLIL::Process::~Process() -{ - for (auto it = syncs.begin(); it != syncs.end(); it++) - delete *it; -} - -RTLIL::Process *RTLIL::Process::clone() const -{ - RTLIL::Process *new_proc = new RTLIL::Process; - - new_proc->name = name; - new_proc->attributes = attributes; - - RTLIL::CaseRule *rc_ptr = root_case.clone(); - new_proc->root_case = *rc_ptr; - rc_ptr->switches.clear(); - delete rc_ptr; - - for (auto &it : syncs) - new_proc->syncs.push_back(it->clone()); - - return new_proc; -} - -#ifdef WITH_PYTHON -RTLIL::Memory::~Memory() -{ - RTLIL::Memory::get_all_memorys()->erase(hashidx_); -} -static std::map all_memorys; -std::map *RTLIL::Memory::get_all_memorys(void) -{ - return &all_memorys; -} -#endif -YOSYS_NAMESPACE_END diff --git a/yosys/kernel/rtlil.h b/yosys/kernel/rtlil.h deleted file mode 100644 index 7b7367fba..000000000 --- a/yosys/kernel/rtlil.h +++ /dev/null @@ -1,1530 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" - -#ifndef RTLIL_H -#define RTLIL_H - -YOSYS_NAMESPACE_BEGIN - -namespace RTLIL -{ - enum State : unsigned char { - S0 = 0, - S1 = 1, - Sx = 2, // undefined value or conflict - Sz = 3, // high-impedance / not-connected - Sa = 4, // don't care (used only in cases) - Sm = 5 // marker (used internally by some passes) - }; - - enum SyncType : unsigned char { - ST0 = 0, // level sensitive: 0 - ST1 = 1, // level sensitive: 1 - STp = 2, // edge sensitive: posedge - STn = 3, // edge sensitive: negedge - STe = 4, // edge sensitive: both edges - STa = 5, // always active - STg = 6, // global clock - STi = 7 // init - }; - - enum ConstFlags : unsigned char { - CONST_FLAG_NONE = 0, - CONST_FLAG_STRING = 1, - CONST_FLAG_SIGNED = 2, // only used for parameters - CONST_FLAG_REAL = 4 // only used for parameters - }; - - struct Const; - struct AttrObject; - struct Selection; - struct Monitor; - struct Design; - struct Module; - struct Wire; - struct Memory; - struct Cell; - struct SigChunk; - struct SigBit; - struct SigSpecIterator; - struct SigSpecConstIterator; - struct SigSpec; - struct CaseRule; - struct SwitchRule; - struct SyncRule; - struct Process; - - typedef std::pair SigSig; - - struct IdString - { - #undef YOSYS_XTRACE_GET_PUT - #undef YOSYS_SORT_ID_FREE_LIST - - // the global id string cache - - static struct destruct_guard_t { - bool ok; // POD, will be initialized to zero - destruct_guard_t() { ok = true; } - ~destruct_guard_t() { ok = false; } - } destruct_guard; - - static std::vector global_refcount_storage_; - static std::vector global_id_storage_; - static dict global_id_index_; - static std::vector global_free_idx_list_; - - static int last_created_idx_ptr_; - static int last_created_idx_[8]; - - 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 void checkpoint() - { - 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; - } - #ifdef YOSYS_SORT_ID_FREE_LIST - std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater()); - #endif - } - - static inline int get_reference(int idx) - { - global_refcount_storage_.at(idx)++; - #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 inline int get_reference(const char *p) - { - log_assert(destruct_guard.ok); - - if (p[0]) { - log_assert(p[1] != 0); - log_assert(p[0] == '$' || p[0] == '\\'); - } - - auto it = global_id_index_.find((char*)p); - if (it != global_id_index_.end()) { - global_refcount_storage_.at(it->second)++; - #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; - } - - if (global_free_idx_list_.empty()) { - 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)++; - - // 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; - - 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 - return idx; - } - - 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) - 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 - - log_assert(global_refcount_storage_.at(idx) > 0); - - if (--global_refcount_storage_.at(idx) != 0) - return; - - 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); - } - - // the actual IdString object is just is a single int - - int index_; - - IdString() : index_(get_reference("")) { } - IdString(const char *str) : index_(get_reference(str)) { } - IdString(const IdString &str) : index_(get_reference(str.index_)) { } - IdString(const std::string &str) : index_(get_reference(str.c_str())) { } - ~IdString() { put_reference(index_); } - - void operator=(const IdString &rhs) { - put_reference(index_); - index_ = get_reference(rhs.index_); - } - - void operator=(const char *rhs) { - IdString id(rhs); - *this = id; - } - - void operator=(const std::string &rhs) { - IdString id(rhs); - *this = id; - } - - const char *c_str() const { - return global_id_storage_.at(index_); - } - - std::string str() const { - return std::string(global_id_storage_.at(index_)); - } - - bool operator<(const IdString &rhs) const { - return index_ < rhs.index_; - } - - bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } - 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 str() == rhs; } - bool operator!=(const std::string &rhs) const { return 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(); - for (; i != 0; i--, p++) - log_assert(*p != 0); - return *p; - } - - 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); - } - - size_t size() const { - return str().size(); - } - - 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 - // use std::set> if the order of cells in the - // set has an influence on the algorithm. - - template 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 - bool in(T first, Args... rest) const { - return in(first) || in(rest...); - } - - bool in(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 &rhs) const { return rhs.count(*this) != 0; } - }; - - static inline std::string escape_id(std::string str) { - if (str.size() > 0 && str[0] != '\\' && str[0] != '$') - return "\\" + str; - return str; - } - - static inline std::string unescape_id(std::string str) { - if (str.size() < 2) - return str; - if (str[0] != '\\') - return str; - if (str[1] == '$' || str[1] == '\\') - return str; - if (str[1] >= '0' && str[1] <= '9') - return str; - return str.substr(1); - } - - static inline std::string unescape_id(RTLIL::IdString str) { - return unescape_id(str.str()); - } - - static inline const char *id2cstr(const RTLIL::IdString &str) { - return log_id(str); - } - - template struct sort_by_name_id { - bool operator()(T *a, T *b) const { - return a->name < b->name; - } - }; - - template struct sort_by_name_str { - bool operator()(T *a, T *b) const { - return strcmp(a->name.c_str(), b->name.c_str()) < 0; - } - }; - - struct sort_by_id_str { - bool operator()(RTLIL::IdString a, RTLIL::IdString b) const { - return strcmp(a.c_str(), b.c_str()) < 0; - } - }; - - // see calc.cc for the implementation of this functions - RTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - - RTLIL::Const const_reduce_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_reduce_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_reduce_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_reduce_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_reduce_bool (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - - RTLIL::Const const_logic_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_logic_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_logic_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - - RTLIL::Const const_shl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_shr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_sshl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_sshr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_shift (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_shiftx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - - RTLIL::Const const_lt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_le (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_eq (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_ne (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_eqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_nex (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_ge (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_gt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - - RTLIL::Const const_add (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - - RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - - - // This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells(). - // It maintains a reference counter that is used to make sure that the container is not modified while being iterated over. - - template - struct ObjIterator - { - typename dict::iterator it; - dict *list_p; - int *refcount_p; - - ObjIterator() : list_p(nullptr), refcount_p(nullptr) { - } - - ObjIterator(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { - if (list_p->empty()) { - this->list_p = nullptr; - this->refcount_p = nullptr; - } else { - it = list_p->begin(); - (*refcount_p)++; - } - } - - ObjIterator(const RTLIL::ObjIterator &other) { - it = other.it; - list_p = other.list_p; - refcount_p = other.refcount_p; - if (refcount_p) - (*refcount_p)++; - } - - ObjIterator &operator=(const RTLIL::ObjIterator &other) { - if (refcount_p) - (*refcount_p)--; - it = other.it; - list_p = other.list_p; - refcount_p = other.refcount_p; - if (refcount_p) - (*refcount_p)++; - return *this; - } - - ~ObjIterator() { - if (refcount_p) - (*refcount_p)--; - } - - inline T operator*() const { - log_assert(list_p != nullptr); - return it->second; - } - - inline bool operator!=(const RTLIL::ObjIterator &other) const { - if (list_p == nullptr || other.list_p == nullptr) - return list_p != other.list_p; - return it != other.it; - } - - inline void operator++() { - log_assert(list_p != nullptr); - if (++it == list_p->end()) { - (*refcount_p)--; - list_p = nullptr; - refcount_p = nullptr; - } - } - }; - - template - struct ObjRange - { - dict *list_p; - int *refcount_p; - - ObjRange(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { } - RTLIL::ObjIterator begin() { return RTLIL::ObjIterator(list_p, refcount_p); } - RTLIL::ObjIterator end() { return RTLIL::ObjIterator(); } - - size_t size() const { - return list_p->size(); - } - - operator pool() const { - pool result; - for (auto &it : *list_p) - result.insert(it.second); - return result; - } - - operator std::vector() const { - std::vector result; - result.reserve(list_p->size()); - for (auto &it : *list_p) - result.push_back(it.second); - return result; - } - - pool to_pool() const { return *this; } - std::vector to_vector() const { return *this; } - }; -}; - -struct RTLIL::Const -{ - int flags; - std::vector bits; - - Const(); - Const(std::string str); - Const(int val, int width = 32); - Const(RTLIL::State bit, int width = 1); - Const(const std::vector &bits) : bits(bits) { flags = CONST_FLAG_NONE; } - Const(const std::vector &bits); - Const(const RTLIL::Const &c); - RTLIL::Const &operator =(const RTLIL::Const &other) = default; - - bool operator <(const RTLIL::Const &other) const; - bool operator ==(const RTLIL::Const &other) const; - bool operator !=(const RTLIL::Const &other) const; - - bool as_bool() const; - int as_int(bool is_signed = false) const; - std::string as_string() const; - static Const from_string(std::string str); - - std::string decode_string() const; - - inline int size() const { return bits.size(); } - inline RTLIL::State &operator[](int index) { return bits.at(index); } - inline const RTLIL::State &operator[](int index) const { return bits.at(index); } - - bool is_fully_zero() const; - bool is_fully_ones() const; - bool is_fully_def() const; - bool is_fully_undef() const; - - inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const { - RTLIL::Const ret; - ret.bits.reserve(len); - for (int i = offset; i < offset + len; i++) - ret.bits.push_back(i < GetSize(bits) ? bits[i] : padding); - return ret; - } - - void extu(int width) { - bits.resize(width, RTLIL::State::S0); - } - - void exts(int width) { - bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back()); - } - - inline unsigned int hash() const { - unsigned int h = mkhash_init; - for (auto b : bits) - mkhash(h, b); - return h; - } -}; - -struct RTLIL::AttrObject -{ - dict attributes; - - void set_bool_attribute(RTLIL::IdString id, bool value=true); - bool get_bool_attribute(RTLIL::IdString id) const; - - bool get_blackbox_attribute(bool ignore_wb=false) const { - return get_bool_attribute("\\blackbox") || (!ignore_wb && get_bool_attribute("\\whitebox")); - } - - void set_strpool_attribute(RTLIL::IdString id, const pool &data); - void add_strpool_attribute(RTLIL::IdString id, const pool &data); - pool get_strpool_attribute(RTLIL::IdString id) const; - - void set_src_attribute(const std::string &src); - std::string get_src_attribute() const; -}; - -struct RTLIL::SigChunk -{ - RTLIL::Wire *wire; - std::vector data; // only used if wire == NULL, LSB at index 0 - int width, offset; - - SigChunk(); - SigChunk(const RTLIL::Const &value); - SigChunk(RTLIL::Wire *wire); - SigChunk(RTLIL::Wire *wire, int offset, int width = 1); - SigChunk(const std::string &str); - SigChunk(int val, int width = 32); - SigChunk(RTLIL::State bit, int width = 1); - SigChunk(RTLIL::SigBit bit); - SigChunk(const RTLIL::SigChunk &sigchunk); - RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default; - - RTLIL::SigChunk extract(int offset, int length) const; - inline int size() const { return width; } - - bool operator <(const RTLIL::SigChunk &other) const; - bool operator ==(const RTLIL::SigChunk &other) const; - bool operator !=(const RTLIL::SigChunk &other) const; -}; - -struct RTLIL::SigBit -{ - RTLIL::Wire *wire; - union { - RTLIL::State data; // used if wire == NULL - int offset; // used if wire != NULL - }; - - SigBit(); - SigBit(RTLIL::State bit); - SigBit(bool bit); - SigBit(RTLIL::Wire *wire); - SigBit(RTLIL::Wire *wire, int offset); - SigBit(const RTLIL::SigChunk &chunk); - SigBit(const RTLIL::SigChunk &chunk, int index); - SigBit(const RTLIL::SigSpec &sig); - SigBit(const RTLIL::SigBit &sigbit); - RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default; - - 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; -}; - -struct RTLIL::SigSpecIterator : public std::iterator -{ - RTLIL::SigSpec *sig_p; - int index; - - inline RTLIL::SigBit &operator*() const; - inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; } - inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; } - inline void operator++() { index++; } -}; - -struct RTLIL::SigSpecConstIterator : public std::iterator -{ - const RTLIL::SigSpec *sig_p; - int index; - - inline const RTLIL::SigBit &operator*() const; - inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; } - inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; } - inline void operator++() { index++; } -}; - -struct RTLIL::SigSpec -{ -private: - int width_; - unsigned long hash_; - std::vector chunks_; // LSB at index 0 - std::vector bits_; // LSB at index 0 - - void pack() const; - void unpack() const; - void updhash() const; - - inline bool packed() const { - return bits_.empty(); - } - - inline void inline_unpack() const { - if (!chunks_.empty()) - unpack(); - } - -public: - SigSpec(); - SigSpec(const RTLIL::SigSpec &other); - SigSpec(std::initializer_list parts); - const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other); - - SigSpec(const RTLIL::Const &value); - SigSpec(const RTLIL::SigChunk &chunk); - SigSpec(RTLIL::Wire *wire); - SigSpec(RTLIL::Wire *wire, int offset, int width = 1); - SigSpec(const std::string &str); - SigSpec(int val, int width = 32); - SigSpec(RTLIL::State bit, int width = 1); - SigSpec(RTLIL::SigBit bit, int width = 1); - SigSpec(std::vector chunks); - SigSpec(std::vector bits); - SigSpec(pool bits); - SigSpec(std::set bits); - SigSpec(bool bit); - - SigSpec(RTLIL::SigSpec &&other) { - width_ = other.width_; - hash_ = other.hash_; - chunks_ = std::move(other.chunks_); - bits_ = std::move(other.bits_); - } - - const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) { - width_ = other.width_; - hash_ = other.hash_; - chunks_ = std::move(other.chunks_); - bits_ = std::move(other.bits_); - return *this; - } - - size_t get_hash() const { - if (!hash_) hash(); - return hash_; - } - - inline const std::vector &chunks() const { pack(); return chunks_; } - inline const std::vector &bits() const { inline_unpack(); return bits_; } - - inline int size() const { return width_; } - inline bool empty() const { return width_ == 0; } - - inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); } - inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } - - inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } - inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; } - - inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; } - inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; } - - void sort(); - void sort_and_unify(); - - void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with); - void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const; - - void replace(const dict &rules); - void replace(const dict &rules, RTLIL::SigSpec *other) const; - - void replace(const std::map &rules); - void replace(const std::map &rules, RTLIL::SigSpec *other) const; - - void replace(int offset, const RTLIL::SigSpec &with); - - void remove(const RTLIL::SigSpec &pattern); - void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const; - void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other); - - void remove(const pool &pattern); - void remove(const pool &pattern, RTLIL::SigSpec *other) const; - void remove2(const pool &pattern, RTLIL::SigSpec *other); - void remove2(const std::set &pattern, RTLIL::SigSpec *other); - - void remove(int offset, int length = 1); - void remove_const(); - - RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; - RTLIL::SigSpec extract(const pool &pattern, const RTLIL::SigSpec *other = NULL) const; - RTLIL::SigSpec extract(int offset, int length = 1) const; - - void append(const RTLIL::SigSpec &signal); - void append_bit(const RTLIL::SigBit &bit); - - void extend_u0(int width, bool is_signed = false); - - RTLIL::SigSpec repeat(int num) const; - - bool operator <(const RTLIL::SigSpec &other) const; - bool operator ==(const RTLIL::SigSpec &other) const; - inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); } - - bool is_wire() const; - bool is_chunk() const; - inline bool is_bit() const { return width_ == 1; } - - bool is_fully_const() const; - bool is_fully_zero() const; - bool is_fully_ones() const; - bool is_fully_def() const; - bool is_fully_undef() const; - bool has_const() const; - bool has_marked_bits() const; - - bool as_bool() const; - int as_int(bool is_signed = false) const; - std::string as_string() const; - RTLIL::Const as_const() const; - RTLIL::Wire *as_wire() const; - RTLIL::SigChunk as_chunk() const; - RTLIL::SigBit as_bit() const; - - bool match(std::string pattern) const; - - std::set to_sigbit_set() const; - pool to_sigbit_pool() const; - std::vector to_sigbit_vector() const; - std::map to_sigbit_map(const RTLIL::SigSpec &other) const; - dict to_sigbit_dict(const RTLIL::SigSpec &other) const; - - static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); - static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str); - static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); - - operator std::vector() const { return chunks(); } - operator std::vector() const { return bits(); } - - unsigned int hash() const { if (!hash_) updhash(); return hash_; }; - -#ifndef NDEBUG - void check() const; -#else - void check() const { } -#endif -}; - -struct RTLIL::Selection -{ - bool full_selection; - pool selected_modules; - dict> selected_members; - - Selection(bool full = true) : full_selection(full) { } - - bool selected_module(RTLIL::IdString mod_name) const; - bool selected_whole_module(RTLIL::IdString mod_name) const; - bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; - void optimize(RTLIL::Design *design); - - template void select(T1 *module) { - if (!full_selection && selected_modules.count(module->name) == 0) { - selected_modules.insert(module->name); - selected_members.erase(module->name); - } - } - - template void select(T1 *module, T2 *member) { - if (!full_selection && selected_modules.count(module->name) == 0) - selected_members[module->name].insert(member->name); - } - - bool empty() const { - return !full_selection && selected_modules.empty() && selected_members.empty(); - } -}; - -struct RTLIL::Monitor -{ - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - - Monitor() { - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; - } - - virtual ~Monitor() { } - virtual void notify_module_add(RTLIL::Module*) { } - virtual void notify_module_del(RTLIL::Module*) { } - virtual void notify_connect(RTLIL::Cell*, const RTLIL::IdString&, const RTLIL::SigSpec&, RTLIL::SigSpec&) { } - virtual void notify_connect(RTLIL::Module*, const RTLIL::SigSig&) { } - virtual void notify_connect(RTLIL::Module*, const std::vector&) { } - virtual void notify_blackout(RTLIL::Module*) { } -}; - -struct RTLIL::Design -{ - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - - pool monitors; - dict scratchpad; - - int refcount_modules_; - dict modules_; - std::vector verilog_packages, verilog_globals; - dict> verilog_defines; - - std::vector selection_stack; - dict selection_vars; - std::string selected_active_module; - - Design(); - ~Design(); - - RTLIL::ObjRange modules(); - RTLIL::Module *module(RTLIL::IdString name); - RTLIL::Module *top_module(); - - bool has(RTLIL::IdString id) const { - return modules_.count(id) != 0; - } - - void add(RTLIL::Module *module); - RTLIL::Module *addModule(RTLIL::IdString name); - void remove(RTLIL::Module *module); - void rename(RTLIL::Module *module, RTLIL::IdString new_name); - - void scratchpad_unset(std::string varname); - - void scratchpad_set_int(std::string varname, int value); - void scratchpad_set_bool(std::string varname, bool value); - void scratchpad_set_string(std::string varname, std::string value); - - int scratchpad_get_int(std::string varname, int default_value = 0) const; - bool scratchpad_get_bool(std::string varname, bool default_value = false) const; - std::string scratchpad_get_string(std::string varname, std::string default_value = std::string()) const; - - void sort(); - void check(); - void optimize(); - - bool selected_module(RTLIL::IdString mod_name) const; - bool selected_whole_module(RTLIL::IdString mod_name) const; - bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; - - bool selected_module(RTLIL::Module *mod) const; - bool selected_whole_module(RTLIL::Module *mod) const; - - RTLIL::Selection &selection() { - return selection_stack.back(); - } - - const RTLIL::Selection &selection() const { - return selection_stack.back(); - } - - bool full_selection() const { - return selection_stack.back().full_selection; - } - - template bool selected(T1 *module) const { - return selected_module(module->name); - } - - template bool selected(T1 *module, T2 *member) const { - return selected_member(module->name, member->name); - } - - template void select(T1 *module, T2 *member) { - if (selection_stack.size() > 0) { - RTLIL::Selection &sel = selection_stack.back(); - sel.select(module, member); - } - } - - - std::vector selected_modules() const; - std::vector selected_whole_modules() const; - std::vector selected_whole_modules_warn() const; -#ifdef WITH_PYTHON - static std::map *get_all_designs(void); -#endif -}; - -struct RTLIL::Module : public RTLIL::AttrObject -{ - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - -protected: - void add(RTLIL::Wire *wire); - void add(RTLIL::Cell *cell); - -public: - RTLIL::Design *design; - pool monitors; - - int refcount_wires_; - int refcount_cells_; - - dict wires_; - dict cells_; - std::vector connections_; - - RTLIL::IdString name; - pool avail_parameters; - dict memories; - dict processes; - - Module(); - virtual ~Module(); - virtual RTLIL::IdString derive(RTLIL::Design *design, dict parameters, bool mayfail = false); - virtual RTLIL::IdString derive(RTLIL::Design *design, dict parameters, dict interfaces, dict modports, bool mayfail = false); - virtual size_t count_id(RTLIL::IdString id); - virtual void reprocess_module(RTLIL::Design *design, dict local_interfaces); - - virtual void sort(); - virtual void check(); - virtual void optimize(); - virtual void makeblackbox(); - - void connect(const RTLIL::SigSig &conn); - void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs); - void new_connections(const std::vector &new_conn); - const std::vector &connections() const; - - std::vector ports; - void fixup_ports(); - - template void rewrite_sigspecs(T &functor); - template void rewrite_sigspecs2(T &functor); - void cloneInto(RTLIL::Module *new_mod) const; - virtual RTLIL::Module *clone() const; - - bool has_memories() const; - bool has_processes() const; - - bool has_memories_warn() const; - bool has_processes_warn() const; - - std::vector selected_wires() const; - std::vector selected_cells() const; - - template bool selected(T *member) const { - return design->selected_member(name, member->name); - } - - RTLIL::Wire* wire(RTLIL::IdString id) { return wires_.count(id) ? wires_.at(id) : nullptr; } - RTLIL::Cell* cell(RTLIL::IdString id) { return cells_.count(id) ? cells_.at(id) : nullptr; } - - RTLIL::ObjRange wires() { return RTLIL::ObjRange(&wires_, &refcount_wires_); } - RTLIL::ObjRange cells() { return RTLIL::ObjRange(&cells_, &refcount_cells_); } - - // Removing wires is expensive. If you have to remove wires, remove them all at once. - void remove(const pool &wires); - void remove(RTLIL::Cell *cell); - - void rename(RTLIL::Wire *wire, RTLIL::IdString new_name); - void rename(RTLIL::Cell *cell, RTLIL::IdString new_name); - void rename(RTLIL::IdString old_name, RTLIL::IdString new_name); - - void swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2); - void swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2); - - RTLIL::IdString uniquify(RTLIL::IdString name); - RTLIL::IdString uniquify(RTLIL::IdString name, int &index); - - RTLIL::Wire *addWire(RTLIL::IdString name, int width = 1); - RTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other); - - RTLIL::Cell *addCell(RTLIL::IdString name, RTLIL::IdString type); - RTLIL::Cell *addCell(RTLIL::IdString name, const RTLIL::Cell *other); - - // The add* methods create a cell and return the created cell. All signals must exist in advance. - - RTLIL::Cell* addNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addPos (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNeg (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addShl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addLt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addEq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addEqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addGe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addGt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addAdd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addMul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addDiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addMod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addPow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); - - RTLIL::Cell* addLogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addMux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src = ""); - RTLIL::Cell* addPmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src = ""); - - RTLIL::Cell* addSlice (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset, const std::string &src = ""); - RTLIL::Cell* addConcat (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src = ""); - RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut, const std::string &src = ""); - RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y, const std::string &src = ""); - RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = ""); - RTLIL::Cell* addAssume (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = ""); - RTLIL::Cell* addLive (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = ""); - RTLIL::Cell* addFair (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = ""); - RTLIL::Cell* addCover (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src = ""); - RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src = ""); - - RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addFf (RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src = ""); - RTLIL::Cell* addDff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffe (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsr (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, - RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, - RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatch (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchsr (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, - RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - - RTLIL::Cell* addBufGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addNotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addAndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addNandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addOrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addNorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addXorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addXnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addAndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addOrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addMuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y, const std::string &src = ""); - RTLIL::Cell* addOai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y, const std::string &src = ""); - - RTLIL::Cell* addFfGate (RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src = ""); - RTLIL::Cell* addDffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffeGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, - RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, - bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchGate (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, - RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - - // The methods without the add* prefix create a cell and an output signal. They return the newly created output signal. - - RTLIL::SigSpec Not (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Pos (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Bu0 (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Neg (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec And (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Or (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Xor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Xnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec ReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec Shl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec Lt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Le (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Eq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Ne (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Eqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Nex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Ge (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Gt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec Add (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Mul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Div (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Mod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Pow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = ""); - - RTLIL::SigSpec LogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec LogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec LogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec Mux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, const std::string &src = ""); - RTLIL::SigSpec Pmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, const std::string &src = ""); - - RTLIL::SigBit BufGate (RTLIL::IdString name, RTLIL::SigBit sig_a, const std::string &src = ""); - RTLIL::SigBit NotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, const std::string &src = ""); - RTLIL::SigBit AndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); - RTLIL::SigBit NandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); - RTLIL::SigBit OrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); - RTLIL::SigBit NorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); - RTLIL::SigBit XorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); - RTLIL::SigBit XnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); - RTLIL::SigBit AndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); - RTLIL::SigBit OrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); - RTLIL::SigBit MuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = ""); - RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = ""); - RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = ""); - RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, const std::string &src = ""); - RTLIL::SigBit Oai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, const std::string &src = ""); - - RTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1, const std::string &src = ""); - RTLIL::SigSpec Anyseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); - RTLIL::SigSpec Allconst (RTLIL::IdString name, int width = 1, const std::string &src = ""); - RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); - RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); - -#ifdef WITH_PYTHON - static std::map *get_all_modules(void); -#endif -}; - -struct RTLIL::Wire : public RTLIL::AttrObject -{ - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - -protected: - // use module->addWire() and module->remove() to create or destroy wires - friend struct RTLIL::Module; - Wire(); - ~Wire(); - -public: - // do not simply copy wires - Wire(RTLIL::Wire &other) = delete; - void operator=(RTLIL::Wire &other) = delete; - - RTLIL::Module *module; - RTLIL::IdString name; - int width, start_offset, port_id; - bool port_input, port_output, upto; - -#ifdef WITH_PYTHON - static std::map *get_all_wires(void); -#endif -}; - -struct RTLIL::Memory : public RTLIL::AttrObject -{ - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - - Memory(); - - RTLIL::IdString name; - int width, start_offset, size; -#ifdef WITH_PYTHON - ~Memory(); - static std::map *get_all_memorys(void); -#endif -}; - -struct RTLIL::Cell : public RTLIL::AttrObject -{ - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - -protected: - // use module->addCell() and module->remove() to create or destroy cells - friend struct RTLIL::Module; - Cell(); - ~Cell(); - -public: - // do not simply copy cells - Cell(RTLIL::Cell &other) = delete; - void operator=(RTLIL::Cell &other) = delete; - - RTLIL::Module *module; - RTLIL::IdString name; - RTLIL::IdString type; - dict connections_; - dict parameters; - - // access cell ports - bool hasPort(RTLIL::IdString portname) const; - void unsetPort(RTLIL::IdString portname); - void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal); - const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const; - const dict &connections() const; - - // information about cell ports - bool known() const; - bool input(RTLIL::IdString portname) const; - bool output(RTLIL::IdString portname) const; - - // access cell parameters - bool hasParam(RTLIL::IdString paramname) const; - void unsetParam(RTLIL::IdString paramname); - void setParam(RTLIL::IdString paramname, RTLIL::Const value); - const RTLIL::Const &getParam(RTLIL::IdString paramname) const; - - void sort(); - void check(); - void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false); - - bool has_keep_attr() const { - return get_bool_attribute("\\keep") || (module && module->design && module->design->module(type) && - module->design->module(type)->get_bool_attribute("\\keep")); - } - - template void rewrite_sigspecs(T &functor); - template void rewrite_sigspecs2(T &functor); - -#ifdef WITH_PYTHON - static std::map *get_all_cells(void); -#endif -}; - -struct RTLIL::CaseRule : public RTLIL::AttrObject -{ - std::vector compare; - std::vector actions; - std::vector switches; - - ~CaseRule(); - void optimize(); - - bool empty() const; - - template void rewrite_sigspecs(T &functor); - template void rewrite_sigspecs2(T &functor); - RTLIL::CaseRule *clone() const; -}; - -struct RTLIL::SwitchRule : public RTLIL::AttrObject -{ - RTLIL::SigSpec signal; - std::vector cases; - - ~SwitchRule(); - - bool empty() const; - - template void rewrite_sigspecs(T &functor); - template void rewrite_sigspecs2(T &functor); - RTLIL::SwitchRule *clone() const; -}; - -struct RTLIL::SyncRule -{ - RTLIL::SyncType type; - RTLIL::SigSpec signal; - std::vector actions; - - template void rewrite_sigspecs(T &functor); - template void rewrite_sigspecs2(T &functor); - RTLIL::SyncRule *clone() const; -}; - -struct RTLIL::Process : public RTLIL::AttrObject -{ - RTLIL::IdString name; - RTLIL::CaseRule root_case; - std::vector syncs; - - ~Process(); - - template void rewrite_sigspecs(T &functor); - template void rewrite_sigspecs2(T &functor); - RTLIL::Process *clone() const; -}; - - -inline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { } -inline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { } -inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? RTLIL::S1 : RTLIL::S0) { } -inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); } -inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); } -inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } -inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } -inline RTLIL::SigBit::SigBit(const RTLIL::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){if(wire) offset = sigbit.offset;} - -inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { - if (wire == other.wire) - return wire ? (offset < other.offset) : (data < other.data); - if (wire != nullptr && other.wire != nullptr) - return wire->name < other.wire->name; - return (wire != nullptr) < (other.wire != nullptr); -} - -inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const { - return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data)); -} - -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 RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const { - return (*sig_p)[index]; -} - -inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const { - return (*sig_p)[index]; -} - -inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) { - log_assert(sig.size() == 1 && sig.chunks().size() == 1); - *this = SigBit(sig.chunks().front()); -} - -template -void RTLIL::Module::rewrite_sigspecs(T &functor) -{ - for (auto &it : cells_) - it.second->rewrite_sigspecs(functor); - for (auto &it : processes) - it.second->rewrite_sigspecs(functor); - for (auto &it : connections_) { - functor(it.first); - functor(it.second); - } -} - -template -void RTLIL::Module::rewrite_sigspecs2(T &functor) -{ - for (auto &it : cells_) - it.second->rewrite_sigspecs2(functor); - for (auto &it : processes) - it.second->rewrite_sigspecs2(functor); - for (auto &it : connections_) { - functor(it.first, it.second); - } -} - -template -void RTLIL::Cell::rewrite_sigspecs(T &functor) { - for (auto &it : connections_) - functor(it.second); -} - -template -void RTLIL::Cell::rewrite_sigspecs2(T &functor) { - for (auto &it : connections_) - functor(it.second); -} - -template -void RTLIL::CaseRule::rewrite_sigspecs(T &functor) { - for (auto &it : compare) - functor(it); - for (auto &it : actions) { - functor(it.first); - functor(it.second); - } - for (auto it : switches) - it->rewrite_sigspecs(functor); -} - -template -void RTLIL::CaseRule::rewrite_sigspecs2(T &functor) { - for (auto &it : compare) - functor(it); - for (auto &it : actions) { - functor(it.first, it.second); - } - for (auto it : switches) - it->rewrite_sigspecs2(functor); -} - -template -void RTLIL::SwitchRule::rewrite_sigspecs(T &functor) -{ - functor(signal); - for (auto it : cases) - it->rewrite_sigspecs(functor); -} - -template -void RTLIL::SwitchRule::rewrite_sigspecs2(T &functor) -{ - functor(signal); - for (auto it : cases) - it->rewrite_sigspecs2(functor); -} - -template -void RTLIL::SyncRule::rewrite_sigspecs(T &functor) -{ - functor(signal); - for (auto &it : actions) { - functor(it.first); - functor(it.second); - } -} - -template -void RTLIL::SyncRule::rewrite_sigspecs2(T &functor) -{ - functor(signal); - for (auto &it : actions) { - functor(it.first, it.second); - } -} - -template -void RTLIL::Process::rewrite_sigspecs(T &functor) -{ - root_case.rewrite_sigspecs(functor); - for (auto it : syncs) - it->rewrite_sigspecs(functor); -} - -template -void RTLIL::Process::rewrite_sigspecs2(T &functor) -{ - root_case.rewrite_sigspecs2(functor); - for (auto it : syncs) - it->rewrite_sigspecs2(functor); -} - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/satgen.h b/yosys/kernel/satgen.h deleted file mode 100644 index 210cca3f3..000000000 --- a/yosys/kernel/satgen.h +++ /dev/null @@ -1,1418 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef SATGEN_H -#define SATGEN_H - -#include "kernel/rtlil.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/macc.h" - -#include "libs/ezsat/ezminisat.h" - -YOSYS_NAMESPACE_BEGIN - -// defined in kernel/register.cc -extern struct SatSolver *yosys_satsolver_list; -extern struct SatSolver *yosys_satsolver; - -struct SatSolver -{ - string name; - SatSolver *next; - virtual ezSAT *create() = 0; - - SatSolver(string name) : name(name) { - next = yosys_satsolver_list; - yosys_satsolver_list = this; - } - - virtual ~SatSolver() { - auto p = &yosys_satsolver_list; - while (*p) { - if (*p == this) - *p = next; - else - p = &(*p)->next; - } - if (yosys_satsolver == this) - yosys_satsolver = yosys_satsolver_list; - } -}; - -struct ezSatPtr : public std::unique_ptr { - ezSatPtr() : unique_ptr(yosys_satsolver->create()) { } -}; - -struct SatGen -{ - ezSAT *ez; - SigMap *sigmap; - std::string prefix; - SigPool initial_state; - std::map asserts_a, asserts_en; - std::map assumes_a, assumes_en; - std::map> imported_signals; - std::map, bool> initstates; - bool ignore_div_by_zero; - bool model_undef; - - SatGen(ezSAT *ez, SigMap *sigmap, std::string prefix = std::string()) : - ez(ez), sigmap(sigmap), prefix(prefix), ignore_div_by_zero(false), model_undef(false) - { - } - - void setContext(SigMap *sigmap, std::string prefix = std::string()) - { - this->sigmap = sigmap; - this->prefix = prefix; - } - - std::vector importSigSpecWorker(RTLIL::SigSpec sig, std::string &pf, bool undef_mode, bool dup_undef) - { - log_assert(!undef_mode || model_undef); - sigmap->apply(sig); - - std::vector vec; - vec.reserve(GetSize(sig)); - - for (auto &bit : sig) - if (bit.wire == NULL) { - if (model_undef && dup_undef && bit == RTLIL::State::Sx) - vec.push_back(ez->frozen_literal()); - else - vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->CONST_TRUE : ez->CONST_FALSE); - } else { - std::string name = pf + (bit.wire->width == 1 ? stringf("%s", log_id(bit.wire)) : stringf("%s [%d]", log_id(bit.wire->name), bit.offset)); - vec.push_back(ez->frozen_literal(name)); - imported_signals[pf][bit] = vec.back(); - } - return vec; - } - - std::vector importSigSpec(RTLIL::SigSpec sig, int timestep = -1) - { - log_assert(timestep != 0); - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - return importSigSpecWorker(sig, pf, false, false); - } - - std::vector importDefSigSpec(RTLIL::SigSpec sig, int timestep = -1) - { - log_assert(timestep != 0); - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - return importSigSpecWorker(sig, pf, false, true); - } - - std::vector importUndefSigSpec(RTLIL::SigSpec sig, int timestep = -1) - { - log_assert(timestep != 0); - std::string pf = "undef:" + prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - return importSigSpecWorker(sig, pf, true, false); - } - - int importSigBit(RTLIL::SigBit bit, int timestep = -1) - { - log_assert(timestep != 0); - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - return importSigSpecWorker(bit, pf, false, false).front(); - } - - int importDefSigBit(RTLIL::SigBit bit, int timestep = -1) - { - log_assert(timestep != 0); - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - return importSigSpecWorker(bit, pf, false, true).front(); - } - - int importUndefSigBit(RTLIL::SigBit bit, int timestep = -1) - { - log_assert(timestep != 0); - std::string pf = "undef:" + prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - return importSigSpecWorker(bit, pf, true, false).front(); - } - - bool importedSigBit(RTLIL::SigBit bit, int timestep = -1) - { - log_assert(timestep != 0); - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - return imported_signals[pf].count(bit) != 0; - } - - void getAsserts(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1) - { - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - sig_a = asserts_a[pf]; - sig_en = asserts_en[pf]; - } - - void getAssumes(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1) - { - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - sig_a = assumes_a[pf]; - sig_en = assumes_en[pf]; - } - - int importAsserts(int timestep = -1) - { - std::vector check_bits, enable_bits; - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - if (model_undef) { - check_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(asserts_a[pf], timestep)), importDefSigSpec(asserts_a[pf], timestep)); - enable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(asserts_en[pf], timestep)), importDefSigSpec(asserts_en[pf], timestep)); - } else { - check_bits = importDefSigSpec(asserts_a[pf], timestep); - enable_bits = importDefSigSpec(asserts_en[pf], timestep); - } - return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits))); - } - - int importAssumes(int timestep = -1) - { - std::vector check_bits, enable_bits; - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - if (model_undef) { - check_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_a[pf], timestep)), importDefSigSpec(assumes_a[pf], timestep)); - enable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_en[pf], timestep)), importDefSigSpec(assumes_en[pf], timestep)); - } else { - check_bits = importDefSigSpec(assumes_a[pf], timestep); - enable_bits = importDefSigSpec(assumes_en[pf], timestep); - } - return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits))); - } - - int signals_eq(RTLIL::SigSpec lhs, RTLIL::SigSpec rhs, int timestep_lhs = -1, int timestep_rhs = -1) - { - if (timestep_rhs < 0) - timestep_rhs = timestep_lhs; - - log_assert(lhs.size() == rhs.size()); - - std::vector vec_lhs = importSigSpec(lhs, timestep_lhs); - std::vector vec_rhs = importSigSpec(rhs, timestep_rhs); - - if (!model_undef) - return ez->vec_eq(vec_lhs, vec_rhs); - - std::vector undef_lhs = importUndefSigSpec(lhs, timestep_lhs); - std::vector undef_rhs = importUndefSigSpec(rhs, timestep_rhs); - - std::vector eq_bits; - for (int i = 0; i < lhs.size(); i++) - eq_bits.push_back(ez->AND(ez->IFF(undef_lhs.at(i), undef_rhs.at(i)), - ez->IFF(ez->OR(vec_lhs.at(i), undef_lhs.at(i)), ez->OR(vec_rhs.at(i), undef_rhs.at(i))))); - return ez->expression(ezSAT::OpAnd, eq_bits); - } - - void extendSignalWidth(std::vector &vec_a, std::vector &vec_b, RTLIL::Cell *cell, size_t y_width = 0, bool forced_signed = false) - { - bool is_signed = forced_signed; - if (!forced_signed && cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters.count("\\B_SIGNED") > 0) - is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool(); - while (vec_a.size() < vec_b.size() || vec_a.size() < y_width) - vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE); - while (vec_b.size() < vec_a.size() || vec_b.size() < y_width) - vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->CONST_FALSE); - } - - void extendSignalWidth(std::vector &vec_a, std::vector &vec_b, std::vector &vec_y, RTLIL::Cell *cell, bool forced_signed = false) - { - extendSignalWidth(vec_a, vec_b, cell, vec_y.size(), forced_signed); - while (vec_y.size() < vec_a.size()) - vec_y.push_back(ez->literal()); - } - - void extendSignalWidthUnary(std::vector &vec_a, std::vector &vec_y, RTLIL::Cell *cell, bool forced_signed = false) - { - bool is_signed = forced_signed || (cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool()); - while (vec_a.size() < vec_y.size()) - vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE); - while (vec_y.size() < vec_a.size()) - vec_y.push_back(ez->literal()); - } - - void undefGating(std::vector &vec_y, std::vector &vec_yy, std::vector &vec_undef) - { - log_assert(model_undef); - log_assert(vec_y.size() == vec_yy.size()); - if (vec_y.size() > vec_undef.size()) { - std::vector trunc_y(vec_y.begin(), vec_y.begin() + vec_undef.size()); - std::vector trunc_yy(vec_yy.begin(), vec_yy.begin() + vec_undef.size()); - ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(trunc_y, trunc_yy)))); - } else { - log_assert(vec_y.size() == vec_undef.size()); - ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy)))); - } - } - - void undefGating(int y, int yy, int undef) - { - ez->assume(ez->OR(undef, ez->IFF(y, yy))); - } - - void setInitState(int timestep) - { - auto key = make_pair(prefix, timestep); - log_assert(initstates.count(key) == 0 || initstates.at(key) == true); - initstates[key] = true; - } - - bool importCell(RTLIL::Cell *cell, int timestep = -1) - { - bool arith_undef_handled = false; - bool is_arith_compare = cell->type.in("$lt", "$le", "$ge", "$gt"); - - if (model_undef && (cell->type.in("$add", "$sub", "$mul", "$div", "$mod") || is_arith_compare)) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - if (is_arith_compare) - extendSignalWidth(undef_a, undef_b, cell, true); - else - extendSignalWidth(undef_a, undef_b, undef_y, cell, true); - - int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); - int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - int undef_y_bit = ez->OR(undef_any_a, undef_any_b); - - if (cell->type == "$div" || cell->type == "$mod") { - std::vector b = importSigSpec(cell->getPort("\\B"), timestep); - undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); - } - - if (is_arith_compare) { - for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - ez->SET(undef_y_bit, undef_y.at(0)); - } else { - std::vector undef_y_bits(undef_y.size(), undef_y_bit); - ez->assume(ez->vec_eq(undef_y_bits, undef_y)); - } - - arith_undef_handled = true; - } - - if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", - "$and", "$or", "$xor", "$xnor", "$add", "$sub")) - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidth(a, b, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == "$and" || cell->type == "$_AND_") - ez->assume(ez->vec_eq(ez->vec_and(a, b), yy)); - if (cell->type == "$_NAND_") - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy)); - if (cell->type == "$or" || cell->type == "$_OR_") - ez->assume(ez->vec_eq(ez->vec_or(a, b), yy)); - if (cell->type == "$_NOR_") - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy)); - if (cell->type == "$xor" || cell->type == "$_XOR_") - ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy)); - if (cell->type == "$xnor" || cell->type == "$_XNOR_") - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy)); - if (cell->type == "$_ANDNOT_") - ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy)); - if (cell->type == "$_ORNOT_") - ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy)); - if (cell->type == "$add") - ez->assume(ez->vec_eq(ez->vec_add(a, b), yy)); - if (cell->type == "$sub") - ez->assume(ez->vec_eq(ez->vec_sub(a, b), yy)); - - if (model_undef && !arith_undef_handled) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidth(undef_a, undef_b, undef_y, cell, false); - - if (cell->type.in("$and", "$_AND_", "$_NAND_")) { - std::vector a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); - std::vector b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); - std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b0))); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else if (cell->type.in("$or", "$_OR_", "$_NOR_")) { - std::vector a1 = ez->vec_and(a, ez->vec_not(undef_a)); - std::vector b1 = ez->vec_and(b, ez->vec_not(undef_b)); - std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b1))); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else if (cell->type.in("$xor", "$xnor", "$_XOR_", "$_XNOR_")) { - std::vector yX = ez->vec_or(undef_a, undef_b); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else if (cell->type == "$_ANDNOT_") { - std::vector a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); - std::vector b1 = ez->vec_and(b, ez->vec_not(undef_b)); - std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b1))); - ez->assume(ez->vec_eq(yX, undef_y)); - } - - else if (cell->type == "$_ORNOT_") { - std::vector a1 = ez->vec_and(a, ez->vec_not(undef_a)); - std::vector b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); - std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b0))); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else - log_abort(); - - undefGating(y, yy, undef_y); - } - else if (model_undef) - { - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) - { - bool aoi_mode = cell->type.in("$_AOI3_", "$_AOI4_"); - bool three_mode = cell->type.in("$_AOI3_", "$_OAI3_"); - - int a = importDefSigSpec(cell->getPort("\\A"), timestep).at(0); - int b = importDefSigSpec(cell->getPort("\\B"), timestep).at(0); - int c = importDefSigSpec(cell->getPort("\\C"), timestep).at(0); - int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0); - int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); - int yy = model_undef ? ez->literal() : y; - - if (cell->type.in("$_AOI3_", "$_AOI4_")) - ez->assume(ez->IFF(ez->NOT(ez->OR(ez->AND(a, b), ez->AND(c, d))), yy)); - else - ez->assume(ez->IFF(ez->NOT(ez->AND(ez->OR(a, b), ez->OR(c, d))), yy)); - - if (model_undef) - { - int undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep).at(0); - int undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep).at(0); - int undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep).at(0); - int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0); - int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0); - - if (aoi_mode) - { - int a0 = ez->AND(ez->NOT(a), ez->NOT(undef_a)); - int b0 = ez->AND(ez->NOT(b), ez->NOT(undef_b)); - int c0 = ez->AND(ez->NOT(c), ez->NOT(undef_c)); - int d0 = ez->AND(ez->NOT(d), ez->NOT(undef_d)); - - int ab = ez->AND(a, b), cd = ez->AND(c, d); - int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a0, b0))); - int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c0, d0))); - - int ab1 = ez->AND(ab, ez->NOT(undef_ab)); - int cd1 = ez->AND(cd, ez->NOT(undef_cd)); - int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab1, cd1))); - - ez->assume(ez->IFF(yX, undef_y)); - } - else - { - int a1 = ez->AND(a, ez->NOT(undef_a)); - int b1 = ez->AND(b, ez->NOT(undef_b)); - int c1 = ez->AND(c, ez->NOT(undef_c)); - int d1 = ez->AND(d, ez->NOT(undef_d)); - - int ab = ez->OR(a, b), cd = ez->OR(c, d); - int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a1, b1))); - int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c1, d1))); - - int ab0 = ez->AND(ez->NOT(ab), ez->NOT(undef_ab)); - int cd0 = ez->AND(ez->NOT(cd), ez->NOT(undef_cd)); - int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab0, cd0))); - - ez->assume(ez->IFF(yX, undef_y)); - } - - undefGating(y, yy, undef_y); - } - - return true; - } - - if (cell->type == "$_NOT_" || cell->type == "$not") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidthUnary(a, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - ez->assume(ez->vec_eq(ez->vec_not(a), yy)); - - if (model_undef) { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell, false); - ez->assume(ez->vec_eq(undef_a, undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$_MUX_" || cell->type == "$mux") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector s = importDefSigSpec(cell->getPort("\\S"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - - std::vector unequal_ab = ez->vec_not(ez->vec_iff(a, b)); - std::vector undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b)); - std::vector yX = ez->vec_ite(undef_s.at(0), undef_ab, ez->vec_ite(s.at(0), undef_b, undef_a)); - ez->assume(ez->vec_eq(yX, undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$pmux") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector s = importDefSigSpec(cell->getPort("\\S"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - std::vector tmp = a; - for (size_t i = 0; i < s.size(); i++) { - std::vector part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size()); - tmp = ez->vec_ite(s.at(i), part_of_b, tmp); - } - ez->assume(ez->vec_eq(tmp, yy)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - - int maybe_a = ez->CONST_TRUE; - - std::vector bits_set = std::vector(undef_y.size(), ez->CONST_FALSE); - std::vector bits_clr = std::vector(undef_y.size(), ez->CONST_FALSE); - - for (size_t i = 0; i < s.size(); i++) - { - std::vector part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size()); - std::vector part_of_undef_b(undef_b.begin()+i*a.size(), undef_b.begin()+(i+1)*a.size()); - - int maybe_s = ez->OR(s.at(i), undef_s.at(i)); - int sure_s = ez->AND(s.at(i), ez->NOT(undef_s.at(i))); - - maybe_a = ez->AND(maybe_a, ez->NOT(sure_s)); - - bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b)), bits_set); - bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b)), bits_clr); - } - - bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set); - bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr); - - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(bits_set, bits_clr)), undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$pos" || cell->type == "$neg") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidthUnary(a, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == "$pos") { - ez->assume(ez->vec_eq(a, yy)); - } else { - std::vector zero(a.size(), ez->CONST_FALSE); - ez->assume(ez->vec_eq(ez->vec_sub(zero, a), yy)); - } - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell); - - if (cell->type == "$pos") { - ez->assume(ez->vec_eq(undef_a, undef_y)); - } else { - int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); - std::vector undef_y_bits(undef_y.size(), undef_any_a); - ez->assume(ez->vec_eq(undef_y_bits, undef_y)); - } - - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_xor" || - cell->type == "$reduce_xnor" || cell->type == "$reduce_bool" || cell->type == "$logic_not") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == "$reduce_and") - ez->SET(ez->expression(ez->OpAnd, a), yy.at(0)); - if (cell->type == "$reduce_or" || cell->type == "$reduce_bool") - ez->SET(ez->expression(ez->OpOr, a), yy.at(0)); - if (cell->type == "$reduce_xor") - ez->SET(ez->expression(ez->OpXor, a), yy.at(0)); - if (cell->type == "$reduce_xnor") - ez->SET(ez->NOT(ez->expression(ez->OpXor, a)), yy.at(0)); - if (cell->type == "$logic_not") - ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0)); - for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->CONST_FALSE, yy.at(i)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - int aX = ez->expression(ezSAT::OpOr, undef_a); - - if (cell->type == "$reduce_and") { - int a0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a))); - ez->assume(ez->IFF(ez->AND(ez->NOT(a0), aX), undef_y.at(0))); - } - else if (cell->type == "$reduce_or" || cell->type == "$reduce_bool" || cell->type == "$logic_not") { - int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(a, ez->vec_not(undef_a))); - ez->assume(ez->IFF(ez->AND(ez->NOT(a1), aX), undef_y.at(0))); - } - else if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") { - ez->assume(ez->IFF(aX, undef_y.at(0))); - } else - log_abort(); - - for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$logic_and" || cell->type == "$logic_or") - { - std::vector vec_a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector vec_b = importDefSigSpec(cell->getPort("\\B"), timestep); - - int a = ez->expression(ez->OpOr, vec_a); - int b = ez->expression(ez->OpOr, vec_b); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == "$logic_and") - ez->SET(ez->expression(ez->OpAnd, a, b), yy.at(0)); - else - ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0)); - for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->CONST_FALSE, yy.at(i)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - - int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a))); - int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b))); - int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(vec_a, ez->vec_not(undef_a))); - int b1 = ez->expression(ezSAT::OpOr, ez->vec_and(vec_b, ez->vec_not(undef_b))); - int aX = ez->expression(ezSAT::OpOr, undef_a); - int bX = ez->expression(ezSAT::OpOr, undef_b); - - if (cell->type == "$logic_and") - ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a1, b1)), ez->NOT(a0), ez->NOT(b0)), undef_y.at(0)); - else if (cell->type == "$logic_or") - ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a0, b0)), ez->NOT(a1), ez->NOT(b1)), undef_y.at(0)); - else - log_abort(); - - for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt") - { - bool is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool(); - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidth(a, b, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - extendSignalWidth(undef_a, undef_b, cell, true); - a = ez->vec_or(a, undef_a); - b = ez->vec_or(b, undef_b); - } - - if (cell->type == "$lt") - ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), yy.at(0)); - if (cell->type == "$le") - ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), yy.at(0)); - if (cell->type == "$eq" || cell->type == "$eqx") - ez->SET(ez->vec_eq(a, b), yy.at(0)); - if (cell->type == "$ne" || cell->type == "$nex") - ez->SET(ez->vec_ne(a, b), yy.at(0)); - if (cell->type == "$ge") - ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), yy.at(0)); - if (cell->type == "$gt") - ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0)); - for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->CONST_FALSE, yy.at(i)); - - if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidth(undef_a, undef_b, cell, true); - - if (cell->type == "$eqx") - yy.at(0) = ez->AND(yy.at(0), ez->vec_eq(undef_a, undef_b)); - else - yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b)); - - for (size_t i = 0; i < y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - - ez->assume(ez->vec_eq(y, yy)); - } - else if (model_undef && (cell->type == "$eq" || cell->type == "$ne")) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidth(undef_a, undef_b, cell, true); - - int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); - int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - int undef_any = ez->OR(undef_any_a, undef_any_b); - - std::vector masked_a_bits = ez->vec_or(a, ez->vec_or(undef_a, undef_b)); - std::vector masked_b_bits = ez->vec_or(b, ez->vec_or(undef_a, undef_b)); - - int masked_ne = ez->vec_ne(masked_a_bits, masked_b_bits); - int undef_y_bit = ez->AND(undef_any, ez->NOT(masked_ne)); - - for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - ez->SET(undef_y_bit, undef_y.at(0)); - - undefGating(y, yy, undef_y); - } - else - { - if (model_undef) { - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - undefGating(y, yy, undef_y); - } - log_assert(!model_undef || arith_undef_handled); - } - return true; - } - - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - - int extend_bit = ez->CONST_FALSE; - - if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool()) - extend_bit = a.back(); - - while (y.size() < a.size()) - y.push_back(ez->literal()); - while (y.size() > a.size()) - a.push_back(extend_bit); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - std::vector shifted_a; - - if (cell->type == "$shl" || cell->type == "$sshl") - shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == "$shr") - shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == "$sshr") - shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == "$shift" || cell->type == "$shiftx") - shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); - - ez->assume(ez->vec_eq(shifted_a, yy)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - std::vector undef_a_shifted; - - extend_bit = cell->type == "$shiftx" ? ez->CONST_TRUE : ez->CONST_FALSE; - if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool()) - extend_bit = undef_a.back(); - - while (undef_y.size() < undef_a.size()) - undef_y.push_back(ez->literal()); - while (undef_y.size() > undef_a.size()) - undef_a.push_back(extend_bit); - - if (cell->type == "$shl" || cell->type == "$sshl") - undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == "$shr") - undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == "$sshr") - undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == "$shift") - undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == "$shiftx") - undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE); - - int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - std::vector undef_all_y_bits(undef_y.size(), undef_any_b); - ez->assume(ez->vec_eq(ez->vec_or(undef_a_shifted, undef_all_y_bits), undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$mul") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidth(a, b, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - std::vector tmp(a.size(), ez->CONST_FALSE); - for (int i = 0; i < int(a.size()); i++) - { - std::vector shifted_a(a.size(), ez->CONST_FALSE); - for (int j = i; j < int(a.size()); j++) - shifted_a.at(j) = a.at(j-i); - tmp = ez->vec_ite(b.at(i), ez->vec_add(tmp, shifted_a), tmp); - } - ez->assume(ez->vec_eq(tmp, yy)); - - if (model_undef) { - log_assert(arith_undef_handled); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$macc") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - - Macc macc; - macc.from_cell(cell); - - std::vector tmp(GetSize(y), ez->CONST_FALSE); - - for (auto &port : macc.ports) - { - std::vector in_a = importDefSigSpec(port.in_a, timestep); - std::vector in_b = importDefSigSpec(port.in_b, timestep); - - while (GetSize(in_a) < GetSize(y)) - in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->CONST_FALSE); - in_a.resize(GetSize(y)); - - if (GetSize(in_b)) - { - while (GetSize(in_b) < GetSize(y)) - in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->CONST_FALSE); - in_b.resize(GetSize(y)); - - for (int i = 0; i < GetSize(in_b); i++) { - std::vector shifted_a(in_a.size(), ez->CONST_FALSE); - for (int j = i; j < int(in_a.size()); j++) - shifted_a.at(j) = in_a.at(j-i); - if (port.do_subtract) - tmp = ez->vec_ite(in_b.at(i), ez->vec_sub(tmp, shifted_a), tmp); - else - tmp = ez->vec_ite(in_b.at(i), ez->vec_add(tmp, shifted_a), tmp); - } - } - else - { - if (port.do_subtract) - tmp = ez->vec_sub(tmp, in_a); - else - tmp = ez->vec_add(tmp, in_a); - } - } - - for (int i = 0; i < GetSize(b); i++) { - std::vector val(GetSize(y), ez->CONST_FALSE); - val.at(0) = b.at(i); - tmp = ez->vec_add(tmp, val); - } - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - - int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); - int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - ez->assume(ez->vec_eq(undef_y, std::vector(GetSize(y), ez->OR(undef_any_a, undef_any_b)))); - - undefGating(y, tmp, undef_y); - } - else - ez->assume(ez->vec_eq(y, tmp)); - - return true; - } - - if (cell->type == "$div" || cell->type == "$mod") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidth(a, b, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - std::vector a_u, b_u; - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) { - a_u = ez->vec_ite(a.back(), ez->vec_neg(a), a); - b_u = ez->vec_ite(b.back(), ez->vec_neg(b), b); - } else { - a_u = a; - b_u = b; - } - - std::vector chain_buf = a_u; - std::vector y_u(a_u.size(), ez->CONST_FALSE); - for (int i = int(a.size())-1; i >= 0; i--) - { - chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->CONST_FALSE); - - std::vector b_shl(i, ez->CONST_FALSE); - b_shl.insert(b_shl.end(), b_u.begin(), b_u.end()); - b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->CONST_FALSE); - - y_u.at(i) = ez->vec_ge_unsigned(chain_buf, b_shl); - chain_buf = ez->vec_ite(y_u.at(i), ez->vec_sub(chain_buf, b_shl), chain_buf); - - chain_buf.erase(chain_buf.begin() + a_u.size(), chain_buf.end()); - } - - std::vector y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size()); - if (cell->type == "$div") { - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u))); - else - ez->assume(ez->vec_eq(y_tmp, y_u)); - } else { - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf))); - else - ez->assume(ez->vec_eq(y_tmp, chain_buf)); - } - - if (ignore_div_by_zero) { - ez->assume(ez->expression(ezSAT::OpOr, b)); - } else { - std::vector div_zero_result; - if (cell->type == "$div") { - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) { - std::vector all_ones(y.size(), ez->CONST_TRUE); - std::vector only_first_one(y.size(), ez->CONST_FALSE); - only_first_one.at(0) = ez->CONST_TRUE; - div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones); - } else { - div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->CONST_TRUE); - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); - } - } else { - int copy_a_bits = min(cell->getPort("\\A").size(), cell->getPort("\\B").size()); - div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back()); - else - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); - } - ez->assume(ez->vec_eq(yy, ez->vec_ite(ez->expression(ezSAT::OpOr, b), y_tmp, div_zero_result))); - } - - if (model_undef) { - log_assert(arith_undef_handled); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$lut") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - - std::vector lut; - for (auto bit : cell->getParam("\\LUT").bits) - lut.push_back(bit == RTLIL::S1 ? ez->CONST_TRUE : ez->CONST_FALSE); - while (GetSize(lut) < (1 << GetSize(a))) - lut.push_back(ez->CONST_FALSE); - lut.resize(1 << GetSize(a)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector t(lut), u(GetSize(t), ez->CONST_FALSE); - - for (int i = GetSize(a)-1; i >= 0; i--) - { - std::vector t0(t.begin(), t.begin() + GetSize(t)/2); - std::vector t1(t.begin() + GetSize(t)/2, t.end()); - - std::vector u0(u.begin(), u.begin() + GetSize(u)/2); - std::vector u1(u.begin() + GetSize(u)/2, u.end()); - - t = ez->vec_ite(a[i], t1, t0); - u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0)); - } - - log_assert(GetSize(t) == 1); - log_assert(GetSize(u) == 1); - undefGating(y, t, u); - ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u)); - } - else - { - std::vector t = lut; - for (int i = GetSize(a)-1; i >= 0; i--) - { - std::vector t0(t.begin(), t.begin() + GetSize(t)/2); - std::vector t1(t.begin() + GetSize(t)/2, t.end()); - t = ez->vec_ite(a[i], t1, t0); - } - - log_assert(GetSize(t) == 1); - ez->assume(ez->vec_eq(y, t)); - } - return true; - } - - if (cell->type == "$sop") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); - - int width = cell->getParam("\\WIDTH").as_int(); - int depth = cell->getParam("\\DEPTH").as_int(); - - vector table_raw = cell->getParam("\\TABLE").bits; - while (GetSize(table_raw) < 2*width*depth) - table_raw.push_back(State::S0); - - vector> table(depth); - - for (int i = 0; i < depth; i++) - for (int j = 0; j < width; j++) - { - bool pat0 = (table_raw[2*width*i + 2*j + 0] == State::S1); - bool pat1 = (table_raw[2*width*i + 2*j + 1] == State::S1); - - if (pat0 && !pat1) - table.at(i).push_back(0); - else if (!pat0 && pat1) - table.at(i).push_back(1); - else - table.at(i).push_back(-1); - } - - if (model_undef) - { - std::vector products, undef_products; - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0); - - for (int i = 0; i < depth; i++) - { - std::vector cmp_a, cmp_ua, cmp_b; - - for (int j = 0; j < width; j++) - if (table.at(i).at(j) >= 0) { - cmp_a.push_back(a.at(j)); - cmp_ua.push_back(undef_a.at(j)); - cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); - } - - std::vector masked_a = ez->vec_or(cmp_a, cmp_ua); - std::vector masked_b = ez->vec_or(cmp_b, cmp_ua); - - int masked_eq = ez->vec_eq(masked_a, masked_b); - int any_undef = ez->expression(ezSAT::OpOr, cmp_ua); - - undef_products.push_back(ez->AND(any_undef, masked_eq)); - products.push_back(ez->AND(ez->NOT(any_undef), masked_eq)); - } - - int yy = ez->expression(ezSAT::OpOr, products); - ez->SET(undef_y, ez->AND(ez->NOT(yy), ez->expression(ezSAT::OpOr, undef_products))); - undefGating(y, yy, undef_y); - } - else - { - std::vector products; - - for (int i = 0; i < depth; i++) - { - std::vector cmp_a, cmp_b; - - for (int j = 0; j < width; j++) - if (table.at(i).at(j) >= 0) { - cmp_a.push_back(a.at(j)); - cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); - } - - products.push_back(ez->vec_eq(cmp_a, cmp_b)); - } - - ez->SET(y, ez->expression(ezSAT::OpOr, products)); - } - - return true; - } - - if (cell->type == "$fa") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector c = importDefSigSpec(cell->getPort("\\C"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - std::vector x = importDefSigSpec(cell->getPort("\\X"), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - std::vector xx = model_undef ? ez->vec_var(x.size()) : x; - - std::vector t1 = ez->vec_xor(a, b); - ez->assume(ez->vec_eq(yy, ez->vec_xor(t1, c))); - - std::vector t2 = ez->vec_and(a, b); - std::vector t3 = ez->vec_and(c, t1); - ez->assume(ez->vec_eq(xx, ez->vec_or(t2, t3))); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep); - - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - std::vector undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep); - - ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c))); - ez->assume(ez->vec_eq(undef_x, undef_y)); - - undefGating(y, yy, undef_y); - undefGating(x, xx, undef_x); - } - return true; - } - - if (cell->type == "$lcu") - { - std::vector p = importDefSigSpec(cell->getPort("\\P"), timestep); - std::vector g = importDefSigSpec(cell->getPort("\\G"), timestep); - std::vector ci = importDefSigSpec(cell->getPort("\\CI"), timestep); - std::vector co = importDefSigSpec(cell->getPort("\\CO"), timestep); - - std::vector yy = model_undef ? ez->vec_var(co.size()) : co; - - for (int i = 0; i < GetSize(co); i++) - ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0]))); - - if (model_undef) - { - std::vector undef_p = importUndefSigSpec(cell->getPort("\\P"), timestep); - std::vector undef_g = importUndefSigSpec(cell->getPort("\\G"), timestep); - std::vector undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep); - std::vector undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep); - - int undef_any_p = ez->expression(ezSAT::OpOr, undef_p); - int undef_any_g = ez->expression(ezSAT::OpOr, undef_g); - int undef_any_ci = ez->expression(ezSAT::OpOr, undef_ci); - int undef_co_bit = ez->OR(undef_any_p, undef_any_g, undef_any_ci); - - std::vector undef_co_bits(undef_co.size(), undef_co_bit); - ez->assume(ez->vec_eq(undef_co_bits, undef_co)); - - undefGating(co, yy, undef_co); - } - return true; - } - - if (cell->type == "$alu") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - std::vector x = importDefSigSpec(cell->getPort("\\X"), timestep); - std::vector ci = importDefSigSpec(cell->getPort("\\CI"), timestep); - std::vector bi = importDefSigSpec(cell->getPort("\\BI"), timestep); - std::vector co = importDefSigSpec(cell->getPort("\\CO"), timestep); - - extendSignalWidth(a, b, y, cell); - extendSignalWidth(a, b, x, cell); - extendSignalWidth(a, b, co, cell); - - std::vector def_y = model_undef ? ez->vec_var(y.size()) : y; - std::vector def_x = model_undef ? ez->vec_var(x.size()) : x; - std::vector def_co = model_undef ? ez->vec_var(co.size()) : co; - - log_assert(GetSize(y) == GetSize(x)); - log_assert(GetSize(y) == GetSize(co)); - log_assert(GetSize(ci) == 1); - log_assert(GetSize(bi) == 1); - - for (int i = 0; i < GetSize(y); i++) - { - int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0); - ez->SET(def_x.at(i), ez->XOR(s1, s2)); - ez->SET(def_y.at(i), ez->XOR(def_x.at(i), s3)); - ez->SET(def_co.at(i), ez->OR(ez->AND(s1, s2), ez->AND(s1, s3), ez->AND(s2, s3))); - } - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep); - std::vector undef_bi = importUndefSigSpec(cell->getPort("\\BI"), timestep); - - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - std::vector undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep); - std::vector undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep); - - extendSignalWidth(undef_a, undef_b, undef_y, cell); - extendSignalWidth(undef_a, undef_b, undef_x, cell); - extendSignalWidth(undef_a, undef_b, undef_co, cell); - - std::vector all_inputs_undef; - all_inputs_undef.insert(all_inputs_undef.end(), undef_a.begin(), undef_a.end()); - all_inputs_undef.insert(all_inputs_undef.end(), undef_b.begin(), undef_b.end()); - all_inputs_undef.insert(all_inputs_undef.end(), undef_ci.begin(), undef_ci.end()); - all_inputs_undef.insert(all_inputs_undef.end(), undef_bi.begin(), undef_bi.end()); - int undef_any = ez->expression(ezSAT::OpOr, all_inputs_undef); - - for (int i = 0; i < GetSize(undef_y); i++) { - ez->SET(undef_y.at(i), undef_any); - ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0))); - ez->SET(undef_co.at(i), undef_any); - } - - undefGating(y, def_y, undef_y); - undefGating(x, def_x, undef_x); - undefGating(co, def_co, undef_co); - } - return true; - } - - if (cell->type == "$slice") - { - RTLIL::SigSpec a = cell->getPort("\\A"); - RTLIL::SigSpec y = cell->getPort("\\Y"); - ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.size()), y, timestep)); - return true; - } - - if (cell->type == "$concat") - { - RTLIL::SigSpec a = cell->getPort("\\A"); - RTLIL::SigSpec b = cell->getPort("\\B"); - RTLIL::SigSpec y = cell->getPort("\\Y"); - - RTLIL::SigSpec ab = a; - ab.append(b); - - ez->assume(signals_eq(ab, y, timestep)); - return true; - } - - if (timestep > 0 && cell->type.in("$ff", "$dff", "$_FF_", "$_DFF_N_", "$_DFF_P_")) - { - if (timestep == 1) - { - initial_state.add((*sigmap)(cell->getPort("\\Q"))); - } - else - { - std::vector d = importDefSigSpec(cell->getPort("\\D"), timestep-1); - std::vector q = importDefSigSpec(cell->getPort("\\Q"), timestep); - - std::vector qq = model_undef ? ez->vec_var(q.size()) : q; - ez->assume(ez->vec_eq(d, qq)); - - if (model_undef) - { - std::vector undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1); - std::vector undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep); - - ez->assume(ez->vec_eq(undef_d, undef_q)); - undefGating(q, qq, undef_q); - } - } - return true; - } - - if (cell->type == "$anyconst") - { - if (timestep < 2) - return true; - - std::vector d = importDefSigSpec(cell->getPort("\\Y"), timestep-1); - std::vector q = importDefSigSpec(cell->getPort("\\Y"), timestep); - - std::vector qq = model_undef ? ez->vec_var(q.size()) : q; - ez->assume(ez->vec_eq(d, qq)); - - if (model_undef) - { - std::vector undef_d = importUndefSigSpec(cell->getPort("\\Y"), timestep-1); - std::vector undef_q = importUndefSigSpec(cell->getPort("\\Y"), timestep); - - ez->assume(ez->vec_eq(undef_d, undef_q)); - undefGating(q, qq, undef_q); - } - return true; - } - - if (cell->type == "$anyseq") - { - return true; - } - - if (cell->type == "$_BUF_" || cell->type == "$equiv") - { - std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidthUnary(a, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - ez->assume(ez->vec_eq(a, yy)); - - if (model_undef) { - std::vector undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell, false); - ez->assume(ez->vec_eq(undef_a, undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == "$initstate") - { - auto key = make_pair(prefix, timestep); - if (initstates.count(key) == 0) - initstates[key] = false; - - std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); - log_assert(GetSize(y) == 1); - ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE); - - if (model_undef) { - std::vector undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - log_assert(GetSize(undef_y) == 1); - ez->SET(undef_y[0], ez->CONST_FALSE); - } - - return true; - } - - if (cell->type == "$assert") - { - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - asserts_a[pf].append((*sigmap)(cell->getPort("\\A"))); - asserts_en[pf].append((*sigmap)(cell->getPort("\\EN"))); - return true; - } - - if (cell->type == "$assume") - { - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - assumes_a[pf].append((*sigmap)(cell->getPort("\\A"))); - assumes_en[pf].append((*sigmap)(cell->getPort("\\EN"))); - return true; - } - - // Unsupported internal cell types: $pow $lut - // .. and all sequential cells except $dff and $_DFF_[NP]_ - return false; - } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/sigtools.h b/yosys/kernel/sigtools.h deleted file mode 100644 index 4e97bb775..000000000 --- a/yosys/kernel/sigtools.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef SIGTOOLS_H -#define SIGTOOLS_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -struct SigPool -{ - struct bitDef_t : public std::pair { - bitDef_t() : std::pair(NULL, 0) { } - bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - unsigned int hash() const { return first->name.hash() + second; } - }; - - pool bits; - - void clear() - { - bits.clear(); - } - - void add(RTLIL::SigSpec sig) - { - for (auto &bit : sig) - if (bit.wire != NULL) - bits.insert(bit); - } - - void add(const SigPool &other) - { - for (auto &bit : other.bits) - bits.insert(bit); - } - - void del(RTLIL::SigSpec sig) - { - for (auto &bit : sig) - if (bit.wire != NULL) - bits.erase(bit); - } - - void del(const SigPool &other) - { - for (auto &bit : other.bits) - bits.erase(bit); - } - - void expand(RTLIL::SigSpec from, RTLIL::SigSpec to) - { - log_assert(GetSize(from) == GetSize(to)); - for (int i = 0; i < GetSize(from); i++) { - bitDef_t bit_from(from[i]), bit_to(to[i]); - if (bit_from.first != NULL && bit_to.first != NULL && bits.count(bit_from) > 0) - bits.insert(bit_to); - } - } - - RTLIL::SigSpec extract(RTLIL::SigSpec sig) - { - RTLIL::SigSpec result; - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit)) - result.append_bit(bit); - return result; - } - - RTLIL::SigSpec remove(RTLIL::SigSpec sig) - { - RTLIL::SigSpec result; - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit) == 0) - result.append(bit); - return result; - } - - bool check(RTLIL::SigBit bit) - { - return bit.wire != NULL && bits.count(bit); - } - - bool check_any(RTLIL::SigSpec sig) - { - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit)) - return true; - return false; - } - - bool check_all(RTLIL::SigSpec sig) - { - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit) == 0) - return false; - return true; - } - - RTLIL::SigSpec export_one() - { - for (auto &bit : bits) - return RTLIL::SigSpec(bit.first, bit.second); - return RTLIL::SigSpec(); - } - - RTLIL::SigSpec export_all() - { - pool sig; - for (auto &bit : bits) - sig.insert(RTLIL::SigBit(bit.first, bit.second)); - return sig; - } - - size_t size() const - { - return bits.size(); - } -}; - -template > -struct SigSet -{ - struct bitDef_t : public std::pair { - bitDef_t() : std::pair(NULL, 0) { } - bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - unsigned int hash() const { return first->name.hash() + second; } - }; - - dict> bits; - - void clear() - { - bits.clear(); - } - - void insert(RTLIL::SigSpec sig, T data) - { - for (auto &bit : sig) - if (bit.wire != NULL) - bits[bit].insert(data); - } - - void insert(RTLIL::SigSpec sig, const std::set &data) - { - for (auto &bit : sig) - if (bit.wire != NULL) - bits[bit].insert(data.begin(), data.end()); - } - - void erase(RTLIL::SigSpec sig) - { - for (auto &bit : sig) - if (bit.wire != NULL) - bits[bit].clear(); - } - - void erase(RTLIL::SigSpec sig, T data) - { - for (auto &bit : sig) - if (bit.wire != NULL) - bits[bit].erase(data); - } - - void erase(RTLIL::SigSpec sig, const std::set &data) - { - for (auto &bit : sig) - if (bit.wire != NULL) - bits[bit].erase(data.begin(), data.end()); - } - - void find(RTLIL::SigSpec sig, std::set &result) - { - for (auto &bit : sig) - if (bit.wire != NULL) { - auto &data = bits[bit]; - result.insert(data.begin(), data.end()); - } - } - - void find(RTLIL::SigSpec sig, pool &result) - { - for (auto &bit : sig) - if (bit.wire != NULL) { - auto &data = bits[bit]; - result.insert(data.begin(), data.end()); - } - } - - std::set find(RTLIL::SigSpec sig) - { - std::set result; - find(sig, result); - return result; - } - - bool has(RTLIL::SigSpec sig) - { - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit)) - return true; - return false; - } -}; - -struct SigMap -{ - mfp database; - - SigMap(RTLIL::Module *module = NULL) - { - if (module != NULL) - set(module); - } - - void swap(SigMap &other) - { - database.swap(other.database); - } - - void clear() - { - database.clear(); - } - - void set(RTLIL::Module *module) - { - int bitcount = 0; - for (auto &it : module->connections()) - bitcount += it.first.size(); - - database.clear(); - database.reserve(bitcount); - - for (auto &it : module->connections()) - add(it.first, it.second); - } - - void add(RTLIL::SigSpec from, RTLIL::SigSpec to) - { - log_assert(GetSize(from) == GetSize(to)); - - for (int i = 0; i < GetSize(from); i++) - { - int bfi = database.lookup(from[i]); - int bti = database.lookup(to[i]); - - const RTLIL::SigBit &bf = database[bfi]; - const RTLIL::SigBit &bt = database[bti]; - - if (bf.wire || bt.wire) - { - database.imerge(bfi, bti); - - if (bf.wire == nullptr) - database.ipromote(bfi); - - if (bt.wire == nullptr) - database.ipromote(bti); - } - } - } - - void add(RTLIL::SigSpec sig) - { - for (auto &bit : sig) { - RTLIL::SigBit b = database.find(bit); - if (b.wire != nullptr) - database.promote(bit); - } - } - - void apply(RTLIL::SigBit &bit) const - { - bit = database.find(bit); - } - - void apply(RTLIL::SigSpec &sig) const - { - for (auto &bit : sig) - apply(bit); - } - - RTLIL::SigBit operator()(RTLIL::SigBit bit) const - { - apply(bit); - return bit; - } - - RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const - { - apply(sig); - return sig; - } - - RTLIL::SigSpec operator()(RTLIL::Wire *wire) const - { - SigSpec sig(wire); - apply(sig); - return sig; - } - - RTLIL::SigSpec allbits() const - { - RTLIL::SigSpec sig; - for (auto &bit : database) - if (bit.wire != nullptr) - sig.append(bit); - return sig; - } -}; - -YOSYS_NAMESPACE_END - -#endif /* SIGTOOLS_H */ diff --git a/yosys/kernel/utils.h b/yosys/kernel/utils.h deleted file mode 100644 index 8942905fe..000000000 --- a/yosys/kernel/utils.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// This file contains various c++ utility routines and helper classes that -// do not depend on any other components of yosys (except stuff like log_*). - -#include "kernel/yosys.h" - -#ifndef UTILS_H -#define UTILS_H - -YOSYS_NAMESPACE_BEGIN - -// ------------------------------------------------ -// A map-like container, but you can save and restore the state -// ------------------------------------------------ - -template> -struct stackmap -{ -private: - std::vector> backup_state; - dict current_state; - static T empty_tuple; - -public: - stackmap() { } - stackmap(const dict &other) : current_state(other) { } - - template - void operator=(const Other &other) - { - for (auto &it : current_state) - if (!backup_state.empty() && backup_state.back().count(it.first) == 0) - backup_state.back()[it.first] = new T(it.second); - current_state.clear(); - - for (auto &it : other) - set(it.first, it.second); - } - - bool has(const Key &k) - { - return current_state.count(k) != 0; - } - - void set(const Key &k, const T &v) - { - if (!backup_state.empty() && backup_state.back().count(k) == 0) - backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr; - current_state[k] = v; - } - - void unset(const Key &k) - { - if (!backup_state.empty() && backup_state.back().count(k) == 0) - backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr; - current_state.erase(k); - } - - const T &get(const Key &k) - { - if (current_state.count(k) == 0) - return empty_tuple; - return current_state.at(k); - } - - void reset(const Key &k) - { - for (int i = GetSize(backup_state)-1; i >= 0; i--) - if (backup_state[i].count(k) != 0) { - if (backup_state[i].at(k) == nullptr) - current_state.erase(k); - else - current_state[k] = *backup_state[i].at(k); - return; - } - current_state.erase(k); - } - - const dict &stdmap() - { - return current_state; - } - - void save() - { - backup_state.resize(backup_state.size()+1); - } - - void restore() - { - log_assert(!backup_state.empty()); - for (auto &it : backup_state.back()) - if (it.second != nullptr) { - current_state[it.first] = *it.second; - delete it.second; - } else - current_state.erase(it.first); - backup_state.pop_back(); - } - - ~stackmap() - { - while (!backup_state.empty()) - restore(); - } -}; - - -// ------------------------------------------------ -// A simple class for topological sorting -// ------------------------------------------------ - -template> -struct TopoSort -{ - bool analyze_loops, found_loops; - std::map, C> database; - std::set> loops; - std::vector sorted; - - TopoSort() - { - analyze_loops = true; - found_loops = false; - } - - void node(T n) - { - if (database.count(n) == 0) - database[n] = std::set(); - } - - void edge(T left, T right) - { - node(left); - database[right].insert(left); - } - - void sort_worker(const T &n, std::set &marked_cells, std::set &active_cells, std::vector &active_stack) - { - if (active_cells.count(n)) { - found_loops = true; - if (analyze_loops) { - std::set loop; - for (int i = GetSize(active_stack)-1; i >= 0; i--) { - loop.insert(active_stack[i]); - if (active_stack[i] == n) - break; - } - loops.insert(loop); - } - return; - } - - if (marked_cells.count(n)) - return; - - if (!database.at(n).empty()) - { - if (analyze_loops) - active_stack.push_back(n); - active_cells.insert(n); - - for (auto &left_n : database.at(n)) - sort_worker(left_n, marked_cells, active_cells, active_stack); - - if (analyze_loops) - active_stack.pop_back(); - active_cells.erase(n); - } - - marked_cells.insert(n); - sorted.push_back(n); - } - - bool sort() - { - loops.clear(); - sorted.clear(); - found_loops = false; - - std::set marked_cells; - std::set active_cells; - std::vector active_stack; - - for (auto &it : database) - sort_worker(it.first, marked_cells, active_cells, active_stack); - - log_assert(GetSize(sorted) == GetSize(database)); - return !found_loops; - } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/yosys.cc b/yosys/kernel/yosys.cc deleted file mode 100644 index 69a141768..000000000 --- a/yosys/kernel/yosys.cc +++ /dev/null @@ -1,1285 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/celltypes.h" - -#ifdef YOSYS_ENABLE_READLINE -# include -# include -#endif - -#ifdef YOSYS_ENABLE_EDITLINE -# include -#endif - -#ifdef YOSYS_ENABLE_PLUGINS -# include -#endif - -#if defined(_WIN32) -# include -# include -#elif defined(__APPLE__) -# include -# include -# include -# include -#else -# include -# include -# include -# include -# include -#endif - -#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB) -# include -#endif - -#ifdef __FreeBSD__ -# include -#endif - -#ifdef WITH_PYTHON -#if PY_MAJOR_VERSION >= 3 -# define INIT_MODULE PyInit_libyosys - extern "C" PyObject* INIT_MODULE(); -#else -# define INIT_MODULE initlibyosys - extern "C" void INIT_MODULE(); -#endif -#endif - -#include -#include - -YOSYS_NAMESPACE_BEGIN - -int autoidx = 1; -int yosys_xtrace = 0; -RTLIL::Design *yosys_design = NULL; -CellTypes yosys_celltypes; - -#ifdef YOSYS_ENABLE_TCL -Tcl_Interp *yosys_tcl_interp = NULL; -#endif - -std::set yosys_input_files, yosys_output_files; - -bool memhasher_active = false; -uint32_t memhasher_rng = 123456; -std::vector memhasher_store; - -void memhasher_on() -{ -#if defined(__linux__) || defined(__FreeBSD__) - memhasher_rng += time(NULL) << 16 ^ getpid(); -#endif - memhasher_store.resize(0x10000); - memhasher_active = true; -} - -void memhasher_off() -{ - for (auto p : memhasher_store) - if (p) free(p); - memhasher_store.clear(); - memhasher_active = false; -} - -void memhasher_do() -{ - memhasher_rng ^= memhasher_rng << 13; - memhasher_rng ^= memhasher_rng >> 17; - memhasher_rng ^= memhasher_rng << 5; - - int size, index = (memhasher_rng >> 4) & 0xffff; - switch (memhasher_rng & 7) { - case 0: size = 16; break; - case 1: size = 256; break; - case 2: size = 1024; break; - case 3: size = 4096; break; - default: size = 0; - } - if (index < 16) size *= 16; - memhasher_store[index] = realloc(memhasher_store[index], size); -} - -void yosys_banner() -{ - log("\n"); - log(" /----------------------------------------------------------------------------\\\n"); - log(" | |\n"); - log(" | yosys -- Yosys Open SYnthesis Suite |\n"); - log(" | |\n"); - log(" | Copyright (C) 2012 - 2019 Clifford Wolf |\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"); - log(" | copyright notice and this permission notice appear in all copies. |\n"); - log(" | |\n"); - log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n"); - log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n"); - log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n"); - log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n"); - log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n"); - log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n"); - log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n"); - log(" | |\n"); - log(" \\----------------------------------------------------------------------------/\n"); - log("\n"); - log(" %s\n", yosys_version_str); - log("\n"); -} - -int ceil_log2(int x) -{ -#if defined(__GNUC__) - return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0; -#else - if (x <= 0) - return 0; - for (int i = 0; i < 32; i++) - if (((x-1) >> i) == 0) - return i; - log_abort(); -#endif -} - -std::string stringf(const char *fmt, ...) -{ - std::string string; - va_list ap; - - va_start(ap, fmt); - string = vstringf(fmt, ap); - va_end(ap); - - return string; -} - -std::string vstringf(const char *fmt, va_list ap) -{ - std::string string; - char *str = NULL; - -#if defined(_WIN32 )|| defined(__CYGWIN__) - int sz = 64, rc; - while (1) { - va_list apc; - va_copy(apc, ap); - str = (char*)realloc(str, sz); - rc = vsnprintf(str, sz, fmt, apc); - va_end(apc); - if (rc >= 0 && rc < sz) - break; - sz *= 2; - } -#else - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; -#endif - - if (str != NULL) { - string = str; - free(str); - } - - return string; -} - -int readsome(std::istream &f, char *s, int n) -{ - int rc = int(f.readsome(s, n)); - - // f.readsome() sometimes returns 0 on a non-empty stream.. - if (rc == 0) { - int c = f.get(); - if (c != EOF) { - *s = c; - rc = 1; - } - } - - return rc; -} - -std::string next_token(std::string &text, const char *sep, bool long_strings) -{ - size_t pos_begin = text.find_first_not_of(sep); - - if (pos_begin == std::string::npos) - pos_begin = text.size(); - - if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') { - string sep_string = sep; - for (size_t i = pos_begin+1; i < text.size(); i++) { - if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) { - std::string token = text.substr(pos_begin, i-pos_begin+1); - text = text.substr(i+1); - return token; - } - if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) { - std::string token = text.substr(pos_begin, i-pos_begin+1); - text = text.substr(i+2); - return token + ";"; - } - } - } - - size_t pos_end = text.find_first_of(sep, pos_begin); - - if (pos_end == std::string::npos) - pos_end = text.size(); - - std::string token = text.substr(pos_begin, pos_end-pos_begin); - text = text.substr(pos_end); - return token; -} - -std::vector split_tokens(const std::string &text, const char *sep) -{ - std::vector tokens; - std::string current_token; - for (char c : text) { - if (strchr(sep, c)) { - if (!current_token.empty()) { - tokens.push_back(current_token); - current_token.clear(); - } - } else - current_token += c; - } - if (!current_token.empty()) { - tokens.push_back(current_token); - current_token.clear(); - } - return tokens; -} - -// this is very similar to fnmatch(). the exact rules used by this -// function are: -// -// ? matches any character except -// * matches any sequence of characters -// [...] matches any of the characters in the list -// [!..] matches any of the characters not in the list -// -// a backslash may be used to escape the next characters in the -// pattern. each special character can also simply match itself. -// -bool patmatch(const char *pattern, const char *string) -{ - if (*pattern == 0) - return *string == 0; - - if (*pattern == '\\') { - if (pattern[1] == string[0] && patmatch(pattern+2, string+1)) - return true; - } - - if (*pattern == '?') { - if (*string == 0) - return false; - return patmatch(pattern+1, string+1); - } - - if (*pattern == '*') { - while (*string) { - if (patmatch(pattern+1, string++)) - return true; - } - return pattern[1] == 0; - } - - if (*pattern == '[') { - bool found_match = false; - bool inverted_list = pattern[1] == '!'; - const char *p = pattern + (inverted_list ? 1 : 0); - - while (*++p) { - if (*p == ']') { - if (found_match != inverted_list && patmatch(p+1, string+1)) - return true; - break; - } - - if (*p == '\\') { - if (*++p == *string) - found_match = true; - } else - if (*p == *string) - found_match = true; - } - } - - if (*pattern == *string) - return patmatch(pattern+1, string+1); - - return false; -} - -int run_command(const std::string &command, std::function process_line) -{ - if (!process_line) - return system(command.c_str()); - - FILE *f = popen(command.c_str(), "r"); - if (f == nullptr) - return -1; - - std::string line; - char logbuf[128]; - while (fgets(logbuf, 128, f) != NULL) { - line += logbuf; - if (!line.empty() && line.back() == '\n') - process_line(line), line.clear(); - } - if (!line.empty()) - process_line(line); - - int ret = pclose(f); - if (ret < 0) - return -1; -#ifdef _WIN32 - return ret; -#else - return WEXITSTATUS(ret); -#endif -} - -std::string make_temp_file(std::string template_str) -{ -#ifdef _WIN32 - if (template_str.rfind("/tmp/", 0) == 0) { -# ifdef __MINGW32__ - char longpath[MAX_PATH + 1]; - char shortpath[MAX_PATH + 1]; -# else - WCHAR longpath[MAX_PATH + 1]; - TCHAR shortpath[MAX_PATH + 1]; -# endif - if (!GetTempPath(MAX_PATH+1, longpath)) - log_error("GetTempPath() failed.\n"); - if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1)) - log_error("GetShortPathName() failed.\n"); - std::string path; - for (int i = 0; shortpath[i]; i++) - path += char(shortpath[i]); - template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5); - } - - size_t pos = template_str.rfind("XXXXXX"); - log_assert(pos != std::string::npos); - - while (1) { - for (int i = 0; i < 6; i++) { - static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - static uint32_t x = 314159265 ^ uint32_t(time(NULL)); - x ^= x << 13, x ^= x >> 17, x ^= x << 5; - template_str[pos+i] = y[x % y.size()]; - } - if (_access(template_str.c_str(), 0) != 0) - break; - } -#else - size_t pos = template_str.rfind("XXXXXX"); - log_assert(pos != std::string::npos); - - int suffixlen = GetSize(template_str) - pos - 6; - - char *p = strdup(template_str.c_str()); - close(mkstemps(p, suffixlen)); - template_str = p; - free(p); -#endif - - return template_str; -} - -std::string make_temp_dir(std::string template_str) -{ -#ifdef _WIN32 - template_str = make_temp_file(template_str); - mkdir(template_str.c_str()); - return template_str; -#else -# ifndef NDEBUG - size_t pos = template_str.rfind("XXXXXX"); - log_assert(pos != std::string::npos); - - int suffixlen = GetSize(template_str) - pos - 6; - log_assert(suffixlen == 0); -# endif - - char *p = strdup(template_str.c_str()); - p = mkdtemp(p); - log_assert(p != NULL); - template_str = p; - free(p); - - return template_str; -#endif -} - -#ifdef _WIN32 -bool check_file_exists(std::string filename, bool) -{ - return _access(filename.c_str(), 0) == 0; -} -#else -bool check_file_exists(std::string filename, bool is_exec) -{ - return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0; -} -#endif - -bool is_absolute_path(std::string filename) -{ -#ifdef _WIN32 - return filename[0] == '/' || filename[0] == '\\' || (filename[0] != 0 && filename[1] == ':'); -#else - return filename[0] == '/'; -#endif -} - -void remove_directory(std::string dirname) -{ -#ifdef _WIN32 - run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str())); -#else - struct stat stbuf; - struct dirent **namelist; - int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort); - log_assert(n >= 0); - for (int i = 0; i < n; i++) { - if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) { - std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name); - if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) { - remove(buffer.c_str()); - } else - remove_directory(buffer); - } - free(namelist[i]); - } - free(namelist); - rmdir(dirname.c_str()); -#endif -} - -std::string escape_filename_spaces(const std::string& filename) -{ - std::string out; - out.reserve(filename.size()); - for (auto c : filename) - { - if (c == ' ') - out += "\\ "; - else - out.push_back(c); - } - return out; -} - -int GetSize(RTLIL::Wire *wire) -{ - return wire->width; -} - -bool already_setup = false; - -void yosys_setup() -{ - if(already_setup) - return; - already_setup = true; - // if there are already IdString objects then we have a global initialization order bug - IdString empty_id; - log_assert(empty_id.index_ == 0); - IdString::get_reference(empty_id.index_); - - #ifdef WITH_PYTHON - PyImport_AppendInittab((char*)"libyosys", INIT_MODULE); - Py_Initialize(); - PyRun_SimpleString("import sys"); - #endif - - Pass::init_register(); - yosys_design = new RTLIL::Design; - yosys_celltypes.setup(); - log_push(); -} - -bool yosys_already_setup() -{ - return already_setup; -} - -bool already_shutdown = false; - -void yosys_shutdown() -{ - if(already_shutdown) - return; - already_shutdown = true; - log_pop(); - - delete yosys_design; - yosys_design = NULL; - - for (auto f : log_files) - if (f != stderr) - fclose(f); - log_errfile = NULL; - log_files.clear(); - - Pass::done_register(); - yosys_celltypes.clear(); - -#ifdef YOSYS_ENABLE_TCL - if (yosys_tcl_interp != NULL) { - Tcl_DeleteInterp(yosys_tcl_interp); - Tcl_Finalize(); - yosys_tcl_interp = NULL; - } -#endif - -#ifdef YOSYS_ENABLE_PLUGINS - for (auto &it : loaded_plugins) - dlclose(it.second); - - loaded_plugins.clear(); -#ifdef WITH_PYTHON - loaded_python_plugins.clear(); -#endif - loaded_plugin_aliases.clear(); -#endif - -#ifdef WITH_PYTHON - Py_Finalize(); -#endif - - IdString empty_id; - IdString::put_reference(empty_id.index_); -} - -RTLIL::IdString new_id(std::string file, int line, std::string func) -{ -#ifdef _WIN32 - size_t pos = file.find_last_of("/\\"); -#else - size_t pos = file.find_last_of('/'); -#endif - if (pos != std::string::npos) - file = file.substr(pos+1); - - pos = func.find_last_of(':'); - if (pos != std::string::npos) - func = func.substr(pos+1); - - return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++); -} - -RTLIL::Design *yosys_get_design() -{ - return yosys_design; -} - -const char *create_prompt(RTLIL::Design *design, int recursion_counter) -{ - static char buffer[100]; - std::string str = "\n"; - if (recursion_counter > 1) - str += stringf("(%d) ", recursion_counter); - str += "yosys"; - if (!design->selected_active_module.empty()) - str += stringf(" [%s]", RTLIL::unescape_id(design->selected_active_module).c_str()); - if (!design->selection_stack.empty() && !design->selection_stack.back().full_selection) { - if (design->selected_active_module.empty()) - str += "*"; - else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 || - design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0) - str += "*"; - } - snprintf(buffer, 100, "%s> ", str.c_str()); - return buffer; -} - -std::vector glob_filename(const std::string &filename_pattern) -{ - std::vector results; - -#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB) - results.push_back(filename_pattern); -#else - glob_t globbuf; - - int err = glob(filename_pattern.c_str(), 0, NULL, &globbuf); - - if(err == 0) { - for (size_t i = 0; i < globbuf.gl_pathc; i++) - results.push_back(globbuf.gl_pathv[i]); - globfree(&globbuf); - } else { - results.push_back(filename_pattern); - } -#endif - - return results; -} - -void rewrite_filename(std::string &filename) -{ - if (filename.substr(0, 1) == "\"" && filename.substr(GetSize(filename)-1) == "\"") - filename = filename.substr(1, GetSize(filename)-2); - if (filename.substr(0, 2) == "+/") - filename = proc_share_dirname() + filename.substr(2); -#ifndef _WIN32 - if (filename.substr(0, 2) == "~/") - filename = filename.replace(0, 1, getenv("HOME")); -#endif -} - -#ifdef YOSYS_ENABLE_TCL -static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) -{ - std::vector args; - for (int i = 1; i < argc; i++) - args.push_back(argv[i]); - - if (args.size() >= 1 && args[0] == "-import") { - for (auto &it : pass_register) { - std::string tcl_command_name = it.first; - if (tcl_command_name == "proc") - tcl_command_name = "procs"; - else if (tcl_command_name == "rename") - tcl_command_name = "renames"; - Tcl_CmdInfo info; - if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) { - log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str()); - } else { - std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str()); - Tcl_Eval(interp, tcl_script.c_str()); - } - } - return TCL_OK; - } - - if (args.size() == 1) { - Pass::call(yosys_get_design(), args[0]); - return TCL_OK; - } - - Pass::call(yosys_get_design(), args); - return TCL_OK; -} - -extern Tcl_Interp *yosys_get_tcl_interp() -{ - if (yosys_tcl_interp == NULL) { - yosys_tcl_interp = Tcl_CreateInterp(); - Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL); - } - return yosys_tcl_interp; -} - -struct TclPass : public Pass { - TclPass() : Pass("tcl", "execute a TCL script file") { } - void help() YS_OVERRIDE { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" tcl [args]\n"); - log("\n"); - log("This command executes the tcl commands in the specified file.\n"); - log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n"); - log("\n"); - log("The tcl command 'yosys -import' can be used to import all yosys\n"); - log("commands directly as tcl commands to the tcl shell. Yosys commands\n"); - log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n"); - log("in order to avoid a name collision with the built in commands.\n"); - log("\n"); - log("If any arguments are specified, these arguments are provided to the script via\n"); - log("the standard $argc and $argv variables.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *) YS_OVERRIDE { - if (args.size() < 2) - log_cmd_error("Missing script file.\n"); - - std::vector script_args; - for (auto it = args.begin() + 2; it != args.end(); ++it) - script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size())); - - Tcl_Interp *interp = yosys_get_tcl_interp(); - Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0); - Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0); - Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0); - if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK) - log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(interp)); - } -} TclPass; -#endif - -#if defined(__linux__) || defined(__CYGWIN__) -std::string proc_self_dirname() -{ - char path[PATH_MAX]; - ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path)); - if (buflen < 0) { - log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno)); - } - while (buflen > 0 && path[buflen-1] != '/') - buflen--; - return std::string(path, buflen); -} -#elif defined(__FreeBSD__) -std::string proc_self_dirname() -{ - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; - size_t buflen; - char *buffer; - std::string path; - if (sysctl(mib, 4, NULL, &buflen, NULL, 0) != 0) - log_error("sysctl failed: %s\n", strerror(errno)); - buffer = (char*)malloc(buflen); - if (buffer == NULL) - log_error("malloc failed: %s\n", strerror(errno)); - if (sysctl(mib, 4, buffer, &buflen, NULL, 0) != 0) - log_error("sysctl failed: %s\n", strerror(errno)); - while (buflen > 0 && buffer[buflen-1] != '/') - buflen--; - path.assign(buffer, buflen); - free(buffer); - return path; -} -#elif defined(__APPLE__) -std::string proc_self_dirname() -{ - char *path = NULL; - uint32_t buflen = 0; - while (_NSGetExecutablePath(path, &buflen) != 0) - path = (char *) realloc((void *) path, buflen); - while (buflen > 0 && path[buflen-1] != '/') - buflen--; - return std::string(path, buflen); -} -#elif defined(_WIN32) -std::string proc_self_dirname() -{ - int i = 0; -# ifdef __MINGW32__ - char longpath[MAX_PATH + 1]; - char shortpath[MAX_PATH + 1]; -# else - WCHAR longpath[MAX_PATH + 1]; - TCHAR shortpath[MAX_PATH + 1]; -# endif - if (!GetModuleFileName(0, longpath, MAX_PATH+1)) - log_error("GetModuleFileName() failed.\n"); - if (!GetShortPathName(longpath, shortpath, MAX_PATH+1)) - log_error("GetShortPathName() failed.\n"); - while (shortpath[i] != 0) - i++; - while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\') - shortpath[--i] = 0; - std::string path; - for (i = 0; shortpath[i]; i++) - path += char(shortpath[i]); - return path; -} -#elif defined(EMSCRIPTEN) -std::string proc_self_dirname() -{ - return "/"; -} -#else - #error "Don't know how to determine process executable base path!" -#endif - -#ifdef EMSCRIPTEN -std::string proc_share_dirname() -{ - return "/share/"; -} -#else -std::string proc_share_dirname() -{ - std::string proc_self_path = proc_self_dirname(); -# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR) - std::string proc_share_path = proc_self_path + "share\\"; - if (check_file_exists(proc_share_path, true)) - return proc_share_path; - proc_share_path = proc_self_path + "..\\share\\"; - if (check_file_exists(proc_share_path, true)) - return proc_share_path; -# else - std::string proc_share_path = proc_self_path + "share/"; - if (check_file_exists(proc_share_path, true)) - return proc_share_path; - proc_share_path = proc_self_path + "../share/yosys/"; - if (check_file_exists(proc_share_path, true)) - return proc_share_path; -# ifdef YOSYS_DATDIR - proc_share_path = YOSYS_DATDIR "/"; - if (check_file_exists(proc_share_path, true)) - return proc_share_path; -# endif -# endif - log_error("proc_share_dirname: unable to determine share/ directory!\n"); -} -#endif - -bool fgetline(FILE *f, std::string &buffer) -{ - buffer = ""; - char block[4096]; - while (1) { - if (fgets(block, 4096, f) == NULL) - return false; - buffer += block; - if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) { - while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) - buffer.resize(buffer.size()-1); - return true; - } - } -} - -static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to) -{ - int pos = 0; - std::string label; - - while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t')) - pos++; - - if (pos < GetSize(command) && command[pos] == '#') - return; - - while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') - label += command[pos++]; - - if (GetSize(label) > 1 && label.back() == ':') - { - label = label.substr(0, GetSize(label)-1); - command = command.substr(pos); - - if (label == run_from) - from_to_active = true; - else if (label == run_to || (run_from == run_to && !run_from.empty())) - from_to_active = false; - } -} - -void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design) -{ - if (design == nullptr) - design = yosys_design; - - if (command == "auto") { - if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") - command = "verilog"; - else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv") - command = "verilog -sv"; - else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".vhd") - command = "vhdl"; - else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif") - command = "blif"; - else if (filename.size() > 5 && filename.substr(filename.size()-6) == ".eblif") - command = "blif"; - else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json") - command = "json"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") - command = "ilang"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys") - command = "script"; - else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".tcl") - command = "tcl"; - else if (filename == "-") - command = "script"; - else - log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str()); - } - - if (command == "script") - { - std::string run_from, run_to; - bool from_to_active = true; - - if (from_to_label != NULL) { - size_t pos = from_to_label->find(':'); - if (pos == std::string::npos) { - run_from = *from_to_label; - run_to = *from_to_label; - } else { - run_from = from_to_label->substr(0, pos); - run_to = from_to_label->substr(pos+1); - } - from_to_active = run_from.empty(); - } - - log("\n-- Executing script file `%s' --\n", filename.c_str()); - - FILE *f = stdin; - - if (filename != "-") { - f = fopen(filename.c_str(), "r"); - yosys_input_files.insert(filename); - } - - if (f == NULL) - log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); - - FILE *backup_script_file = Frontend::current_script_file; - Frontend::current_script_file = f; - - try { - std::string command; - while (fgetline(f, command)) { - while (!command.empty() && command[command.size()-1] == '\\') { - std::string next_line; - if (!fgetline(f, next_line)) - break; - command.resize(command.size()-1); - command += next_line; - } - handle_label(command, from_to_active, run_from, run_to); - if (from_to_active) - Pass::call(design, command); - } - - if (!command.empty()) { - handle_label(command, from_to_active, run_from, run_to); - if (from_to_active) - Pass::call(design, command); - } - } - catch (...) { - Frontend::current_script_file = backup_script_file; - throw; - } - - Frontend::current_script_file = backup_script_file; - - if (filename != "-") - fclose(f); - - if (backend_command != NULL && *backend_command == "auto") - *backend_command = ""; - - return; - } - - if (filename == "-") { - log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str()); - } else { - log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str()); - } - - if (command == "tcl") - Pass::call(design, vector({command, filename})); - else - Frontend::frontend_call(design, NULL, filename, command); -} - -void run_frontend(std::string filename, std::string command, RTLIL::Design *design) -{ - run_frontend(filename, command, nullptr, nullptr, design); -} - -void run_pass(std::string command, RTLIL::Design *design) -{ - if (design == nullptr) - design = yosys_design; - - log("\n-- Running command `%s' --\n", command.c_str()); - - Pass::call(design, command); -} - -void run_backend(std::string filename, std::string command, RTLIL::Design *design) -{ - if (design == nullptr) - design = yosys_design; - - if (command == "auto") { - if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") - command = "verilog"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") - command = "ilang"; - else if (filename.size() > 4 && filename.substr(filename.size()-4) == ".aig") - command = "aiger"; - else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif") - command = "blif"; - else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".edif") - command = "edif"; - else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".json") - command = "json"; - else if (filename == "-") - command = "ilang"; - else if (filename.empty()) - return; - else - log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str()); - } - - if (filename.empty()) - filename = "-"; - - if (filename == "-") { - log("\n-- Writing to stdout using backend `%s' --\n", command.c_str()); - } else { - log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str()); - } - - Backend::backend_call(design, NULL, filename, command); -} - -#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) -static char *readline_cmd_generator(const char *text, int state) -{ - static std::map::iterator it; - static int len; - - if (!state) { - it = pass_register.begin(); - len = strlen(text); - } - - for (; it != pass_register.end(); it++) { - if (it->first.substr(0, len) == text) - return strdup((it++)->first.c_str()); - } - return NULL; -} - -static char *readline_obj_generator(const char *text, int state) -{ - static std::vector obj_names; - static size_t idx; - - if (!state) - { - idx = 0; - obj_names.clear(); - - RTLIL::Design *design = yosys_get_design(); - int len = strlen(text); - - if (design->selected_active_module.empty()) - { - for (auto &it : design->modules_) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); - } - else - if (design->modules_.count(design->selected_active_module) > 0) - { - RTLIL::Module *module = design->modules_.at(design->selected_active_module); - - for (auto &it : module->wires_) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); - - for (auto &it : module->memories) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); - - for (auto &it : module->cells_) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); - - for (auto &it : module->processes) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); - } - - std::sort(obj_names.begin(), obj_names.end()); - } - - if (idx < obj_names.size()) - return strdup(obj_names[idx++]); - - idx = 0; - obj_names.clear(); - return NULL; -} - -static char **readline_completion(const char *text, int start, int) -{ - if (start == 0) - return rl_completion_matches(text, readline_cmd_generator); - if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6)) - return rl_completion_matches(text, readline_obj_generator); - return NULL; -} -#endif - -void shell(RTLIL::Design *design) -{ - static int recursion_counter = 0; - - recursion_counter++; - log_cmd_error_throw = true; - -#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) - rl_readline_name = (char*)"yosys"; - rl_attempted_completion_function = readline_completion; - rl_basic_word_break_characters = (char*)" \t\n"; -#endif - - char *command = NULL; -#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) - while ((command = readline(create_prompt(design, recursion_counter))) != NULL) - { -#else - char command_buffer[4096]; - while (1) - { - fputs(create_prompt(design, recursion_counter), stdout); - fflush(stdout); - if ((command = fgets(command_buffer, 4096, stdin)) == NULL) - break; -#endif - if (command[strspn(command, " \t\r\n")] == 0) - continue; -#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) - add_history(command); -#endif - - char *p = command + strspn(command, " \t\r\n"); - if (!strncmp(p, "exit", 4)) { - p += 4; - p += strspn(p, " \t\r\n"); - if (*p == 0) - break; - } - - try { - log_assert(design->selection_stack.size() == 1); - Pass::call(design, command); - } catch (log_cmd_error_exception) { - while (design->selection_stack.size() > 1) - design->selection_stack.pop_back(); - log_reset_stack(); - } - } - if (command == NULL) - printf("exit\n"); - - recursion_counter--; - log_cmd_error_throw = false; -} - -struct ShellPass : public Pass { - ShellPass() : Pass("shell", "enter interactive command mode") { } - void help() YS_OVERRIDE { - log("\n"); - log(" shell\n"); - log("\n"); - log("This command enters the interactive command mode. This can be useful\n"); - log("in a script to interrupt the script at a certain point and allow for\n"); - log("interactive inspection or manual synthesis of the design at this point.\n"); - log("\n"); - log("The command prompt of the interactive shell indicates the current\n"); - log("selection (see 'help select'):\n"); - log("\n"); - log(" yosys>\n"); - log(" the entire design is selected\n"); - log("\n"); - log(" yosys*>\n"); - log(" only part of the design is selected\n"); - log("\n"); - log(" yosys [modname]>\n"); - log(" the entire module 'modname' is selected using 'select -module modname'\n"); - log("\n"); - log(" yosys [modname]*>\n"); - log(" only part of current module 'modname' is selected\n"); - log("\n"); - log("When in interactive shell, some errors (e.g. invalid command arguments)\n"); - log("do not terminate yosys but return to the command prompt.\n"); - log("\n"); - log("This command is the default action if nothing else has been specified\n"); - log("on the command line.\n"); - log("\n"); - log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - extra_args(args, 1, design, false); - shell(design); - } -} ShellPass; - -#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) -struct HistoryPass : public Pass { - HistoryPass() : Pass("history", "show last interactive commands") { } - void help() YS_OVERRIDE { - log("\n"); - log(" history\n"); - log("\n"); - log("This command prints all commands in the shell history buffer. This are\n"); - log("all commands executed in an interactive session, but not the commands\n"); - log("from executed scripts.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - extra_args(args, 1, design, false); -#ifdef YOSYS_ENABLE_READLINE - for(HIST_ENTRY **list = history_list(); *list != NULL; list++) - log("%s\n", (*list)->line); -#else - for (int i = where_history(); history_get(i); i++) - log("%s\n", history_get(i)->line); -#endif - } -} HistoryPass; -#endif - -struct ScriptCmdPass : public Pass { - ScriptCmdPass() : Pass("script", "execute commands from script file") { } - void help() YS_OVERRIDE { - log("\n"); - log(" script [:]\n"); - log("\n"); - log("This command executes the yosys commands in the specified file.\n"); - log("\n"); - log("The 2nd argument can be used to only execute the section of the\n"); - log("file between the specified labels. An empty from label is synonymous\n"); - log("for the beginning of the file and an empty to label is synonymous\n"); - log("for the end of the file.\n"); - log("\n"); - log("If only one label is specified (without ':') then only the block\n"); - log("marked with that label (until the next label) is executed.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - if (args.size() < 2) - log_cmd_error("Missing script file.\n"); - else if (args.size() == 2) - run_frontend(args[1], "script", design); - else if (args.size() == 3) - run_frontend(args[1], "script", NULL, &args[2], design); - else - extra_args(args, 2, design, false); - } -} ScriptCmdPass; - -YOSYS_NAMESPACE_END diff --git a/yosys/kernel/yosys.h b/yosys/kernel/yosys.h deleted file mode 100644 index 730efe825..000000000 --- a/yosys/kernel/yosys.h +++ /dev/null @@ -1,343 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - - -// *** NOTE TO THE READER *** -// -// Maybe you have just opened this file in the hope to learn more about the -// Yosys API. Let me congratulate you on this great decision! ;) -// -// If you want to know how the design is represented by Yosys in the memory, -// you should read "kernel/rtlil.h". -// -// If you want to know how to register a command with Yosys, you could read -// "kernel/register.h", but it would be easier to just look at a simple -// example instead. A simple one would be "passes/cmds/log.cc". -// -// This header is very boring. It just defines some general things that -// belong nowhere else and includes the interesting headers. -// -// Find more information in the "CodingReadme" file. - - -#ifndef YOSYS_H -#define YOSYS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef WITH_PYTHON -#include -#endif - -#ifndef _YOSYS_ -# error It looks like you are trying to build Yosys without the config defines set. \ - When building Yosys with a custom make system, make sure you set all the \ - defines the Yosys Makefile would set for your build configuration. -#endif - -#ifdef YOSYS_ENABLE_TCL -# include -# ifdef YOSYS_MXE_HACKS -extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); -extern Tcl_Interp *Tcl_CreateInterp(void); -extern void Tcl_DeleteInterp(Tcl_Interp *interp); -extern int Tcl_Eval(Tcl_Interp *interp, const char *script); -extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName); -extern void Tcl_Finalize(void); -extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); -extern const char *Tcl_GetStringResult(Tcl_Interp *interp); -extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length); -extern Tcl_Obj *Tcl_NewIntObj(int intValue); -extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]); -extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); -# endif -#endif - -#ifdef _WIN32 -# undef NOMINMAX -# define NOMINMAX 1 -# undef YY_NO_UNISTD_H -# define YY_NO_UNISTD_H 1 - -# include -# include -# include - -# define strtok_r strtok_s -# define strdup _strdup -# define snprintf _snprintf -# define getcwd _getcwd -# define mkdir _mkdir -# define popen _popen -# define pclose _pclose - -# ifndef __MINGW32__ -# define PATH_MAX MAX_PATH -# define isatty _isatty -# define fileno _fileno -# endif -#endif - -#ifndef PATH_MAX -# define PATH_MAX 4096 -#endif - -#define YOSYS_NAMESPACE Yosys -#define PRIVATE_NAMESPACE_BEGIN namespace { -#define PRIVATE_NAMESPACE_END } -#define YOSYS_NAMESPACE_BEGIN namespace Yosys { -#define YOSYS_NAMESPACE_END } -#define YOSYS_NAMESPACE_PREFIX Yosys:: -#define USING_YOSYS_NAMESPACE using namespace Yosys; - -#if __cplusplus >= 201103L -# define YS_OVERRIDE override -# define YS_FINAL final -#else -# define YS_OVERRIDE -# define YS_FINAL -#endif - -#if defined(__GNUC__) || defined(__clang__) -# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__)) -# define YS_NORETURN -#elif defined(_MSC_VER) -# define YS_ATTRIBUTE(...) -# define YS_NORETURN __declspec(noreturn) -#else -# define YS_ATTRIBUTE(...) -# define YS_NORETURN -#endif - -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" -#else -# include "kernel/hashlib.h" -# undef HASHLIB_H -#endif - -using std::vector; -using std::string; -using std::tuple; -using std::pair; - -using std::make_tuple; -using std::make_pair; -using std::get; -using std::min; -using std::max; - -// A primitive shared string implementation that does not -// move its .c_str() when the object is copied or moved. -struct shared_str { - std::shared_ptr content; - shared_str() { } - shared_str(string s) { content = std::shared_ptr(new string(s)); } - shared_str(const char *s) { content = std::shared_ptr(new string(s)); } - 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::hash(*content); } -}; - -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; - struct SigBit; - struct SigSpec; - struct Wire; - struct Cell; - struct Module; - struct Design; - struct Monitor; -} - -namespace AST { - struct AstNode; -} - -using RTLIL::IdString; -using RTLIL::Const; -using RTLIL::SigBit; -using RTLIL::SigSpec; -using RTLIL::Wire; -using RTLIL::Cell; -using RTLIL::Module; -using RTLIL::Design; - -namespace hashlib { - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; - template<> struct hash_ops : hash_obj_ops {}; -} - -void memhasher_on(); -void memhasher_off(); -void memhasher_do(); - -extern bool memhasher_active; -inline void memhasher() { if (memhasher_active) memhasher_do(); } - -void yosys_banner(); -int ceil_log2(int x) YS_ATTRIBUTE(const); -std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -std::string vstringf(const char *fmt, va_list ap); -int readsome(std::istream &f, char *s, int n); -std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); -std::vector split_tokens(const std::string &text, const char *sep = " \t\r\n"); -bool patmatch(const char *pattern, const char *string); -int run_command(const std::string &command, std::function process_line = std::function()); -std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX"); -std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX"); -bool check_file_exists(std::string filename, bool is_exec = false); -bool is_absolute_path(std::string filename); -void remove_directory(std::string dirname); -std::string escape_filename_spaces(const std::string& filename); - -template int GetSize(const T &obj) { return obj.size(); } -int GetSize(RTLIL::Wire *wire); - -extern int autoidx; -extern int yosys_xtrace; - -YOSYS_NAMESPACE_END - -#include "kernel/log.h" -#include "kernel/rtlil.h" -#include "kernel/register.h" - -YOSYS_NAMESPACE_BEGIN - -using RTLIL::State; -using RTLIL::SigChunk; -using RTLIL::SigSig; - -namespace hashlib { - template<> struct hash_ops : hash_ops {}; -} - -void yosys_setup(); - -#ifdef WITH_PYTHON -bool yosys_already_setup(); -#endif - -void yosys_shutdown(); - -#ifdef YOSYS_ENABLE_TCL -Tcl_Interp *yosys_get_tcl_interp(); -#endif - -extern RTLIL::Design *yosys_design; - -RTLIL::IdString new_id(std::string file, int line, std::string func); - -#define NEW_ID \ - YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__) - -#define ID(_str) \ - ([]() { static YOSYS_NAMESPACE_PREFIX RTLIL::IdString _id(_str); return _id; })() - -RTLIL::Design *yosys_get_design(); -std::string proc_self_dirname(); -std::string proc_share_dirname(); -const char *create_prompt(RTLIL::Design *design, int recursion_counter); -std::vector glob_filename(const std::string &filename_pattern); -void rewrite_filename(std::string &filename); - -void run_pass(std::string command, RTLIL::Design *design = nullptr); -void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr); -void run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr); -void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr); -void shell(RTLIL::Design *design); - -// journal of all input and output files read (for "yosys -E") -extern std::set yosys_input_files, yosys_output_files; - -// from kernel/version_*.o (cc source generated from Makefile) -extern const char *yosys_version_str; - -// from passes/cmds/design.cc -extern std::map saved_designs; -extern std::vector pushed_designs; - -// from passes/cmds/pluginc.cc -extern std::map loaded_plugins; -#ifdef WITH_PYTHON -extern std::map loaded_python_plugins; -#endif -extern std::map loaded_plugin_aliases; -void load_plugin(std::string filename, std::vector aliases); - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/libs/bigint/.gitignore b/yosys/libs/bigint/.gitignore deleted file mode 100644 index 4467edcf5..000000000 --- a/yosys/libs/bigint/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.o -sample -testsuite -testsuite.expected -testsuite.out -testsuite.err diff --git a/yosys/libs/bigint/BigInteger.cc b/yosys/libs/bigint/BigInteger.cc deleted file mode 100644 index 3b23aa1e7..000000000 --- a/yosys/libs/bigint/BigInteger.cc +++ /dev/null @@ -1,405 +0,0 @@ -#include "BigInteger.hh" - -void BigInteger::operator =(const BigInteger &x) { - // Calls like a = a have no effect - if (this == &x) - return; - // Copy sign - sign = x.sign; - // Copy the rest - mag = x.mag; -} - -BigInteger::BigInteger(const Blk *b, Index blen, Sign s) : mag(b, blen) { - switch (s) { - case zero: - if (!mag.isZero()) - throw "BigInteger::BigInteger(const Blk *, Index, Sign): Cannot use a sign of zero with a nonzero magnitude"; - sign = zero; - break; - case positive: - case negative: - // If the magnitude is zero, force the sign to zero. - sign = mag.isZero() ? zero : s; - break; - default: - /* g++ seems to be optimizing out this case on the assumption - * that the sign is a valid member of the enumeration. Oh well. */ - throw "BigInteger::BigInteger(const Blk *, Index, Sign): Invalid sign"; - } -} - -BigInteger::BigInteger(const BigUnsigned &x, Sign s) : mag(x) { - switch (s) { - case zero: - if (!mag.isZero()) - throw "BigInteger::BigInteger(const BigUnsigned &, Sign): Cannot use a sign of zero with a nonzero magnitude"; - sign = zero; - break; - case positive: - case negative: - // If the magnitude is zero, force the sign to zero. - sign = mag.isZero() ? zero : s; - break; - default: - /* g++ seems to be optimizing out this case on the assumption - * that the sign is a valid member of the enumeration. Oh well. */ - throw "BigInteger::BigInteger(const BigUnsigned &, Sign): Invalid sign"; - } -} - -/* CONSTRUCTION FROM PRIMITIVE INTEGERS - * Same idea as in BigUnsigned.cc, except that negative input results in a - * negative BigInteger instead of an exception. */ - -// Done longhand to let us use initialization. -BigInteger::BigInteger(unsigned long x) : mag(x) { sign = mag.isZero() ? zero : positive; } -BigInteger::BigInteger(unsigned int x) : mag(x) { sign = mag.isZero() ? zero : positive; } -BigInteger::BigInteger(unsigned short x) : mag(x) { sign = mag.isZero() ? zero : positive; } - -// For signed input, determine the desired magnitude and sign separately. - -namespace { - template - BigInteger::Blk magOf(X x) { - /* UX(...) cast needed to stop short(-2^15), which negates to - * itself, from sign-extending in the conversion to Blk. */ - return BigInteger::Blk(x < 0 ? UX(-x) : x); - } - template - BigInteger::Sign signOf(X x) { - return (x == 0) ? BigInteger::zero - : (x > 0) ? BigInteger::positive - : BigInteger::negative; - } -} - -BigInteger::BigInteger(long x) : sign(signOf(x)), mag(magOf(x)) {} -BigInteger::BigInteger(int x) : sign(signOf(x)), mag(magOf(x)) {} -BigInteger::BigInteger(short x) : sign(signOf(x)), mag(magOf(x)) {} - -// CONVERSION TO PRIMITIVE INTEGERS - -/* Reuse BigUnsigned's conversion to an unsigned primitive integer. - * The friend is a separate function rather than - * BigInteger::convertToUnsignedPrimitive to avoid requiring BigUnsigned to - * declare BigInteger. */ -template -inline X convertBigUnsignedToPrimitiveAccess(const BigUnsigned &a) { - return a.convertToPrimitive(); -} - -template -X BigInteger::convertToUnsignedPrimitive() const { - if (sign == negative) - throw "BigInteger::to: " - "Cannot convert a negative integer to an unsigned type"; - else - return convertBigUnsignedToPrimitiveAccess(mag); -} - -/* Similar to BigUnsigned::convertToPrimitive, but split into two cases for - * nonnegative and negative numbers. */ -template -X BigInteger::convertToSignedPrimitive() const { - if (sign == zero) - return 0; - else if (mag.getLength() == 1) { - // The single block might fit in an X. Try the conversion. - Blk b = mag.getBlock(0); - if (sign == positive) { - X x = X(b); - if (x >= 0 && Blk(x) == b) - return x; - } else { - X x = -X(b); - /* UX(...) needed to avoid rejecting conversion of - * -2^15 to a short. */ - if (x < 0 && Blk(UX(-x)) == b) - return x; - } - // Otherwise fall through. - } - throw "BigInteger::to: " - "Value is too big to fit in the requested type"; -} - -unsigned long BigInteger::toUnsignedLong () const { return convertToUnsignedPrimitive (); } -unsigned int BigInteger::toUnsignedInt () const { return convertToUnsignedPrimitive (); } -unsigned short BigInteger::toUnsignedShort() const { return convertToUnsignedPrimitive (); } -long BigInteger::toLong () const { return convertToSignedPrimitive (); } -int BigInteger::toInt () const { return convertToSignedPrimitive (); } -short BigInteger::toShort () const { return convertToSignedPrimitive (); } - -// COMPARISON -BigInteger::CmpRes BigInteger::compareTo(const BigInteger &x) const { - // A greater sign implies a greater number - if (sign < x.sign) - return less; - else if (sign > x.sign) - return greater; - else switch (sign) { - // If the signs are the same... - case zero: - return equal; // Two zeros are equal - case positive: - // Compare the magnitudes - return mag.compareTo(x.mag); - case negative: - // Compare the magnitudes, but return the opposite result - return CmpRes(-mag.compareTo(x.mag)); - default: - throw "BigInteger internal error"; - } -} - -/* COPY-LESS OPERATIONS - * These do some messing around to determine the sign of the result, - * then call one of BigUnsigned's copy-less operations. */ - -// See remarks about aliased calls in BigUnsigned.cc . -#define DTRT_ALIASED(cond, op) \ - if (cond) { \ - BigInteger tmpThis; \ - tmpThis.op; \ - *this = tmpThis; \ - return; \ - } - -void BigInteger::add(const BigInteger &a, const BigInteger &b) { - DTRT_ALIASED(this == &a || this == &b, add(a, b)); - // If one argument is zero, copy the other. - if (a.sign == zero) - operator =(b); - else if (b.sign == zero) - operator =(a); - // If the arguments have the same sign, take the - // common sign and add their magnitudes. - else if (a.sign == b.sign) { - sign = a.sign; - mag.add(a.mag, b.mag); - } else { - // Otherwise, their magnitudes must be compared. - switch (a.mag.compareTo(b.mag)) { - case equal: - // If their magnitudes are the same, copy zero. - mag = 0; - sign = zero; - break; - // Otherwise, take the sign of the greater, and subtract - // the lesser magnitude from the greater magnitude. - case greater: - sign = a.sign; - mag.subtract(a.mag, b.mag); - break; - case less: - sign = b.sign; - mag.subtract(b.mag, a.mag); - break; - } - } -} - -void BigInteger::subtract(const BigInteger &a, const BigInteger &b) { - // Notice that this routine is identical to BigInteger::add, - // if one replaces b.sign by its opposite. - DTRT_ALIASED(this == &a || this == &b, subtract(a, b)); - // If a is zero, copy b and flip its sign. If b is zero, copy a. - if (a.sign == zero) { - mag = b.mag; - // Take the negative of _b_'s, sign, not ours. - // Bug pointed out by Sam Larkin on 2005.03.30. - sign = Sign(-b.sign); - } else if (b.sign == zero) - operator =(a); - // If their signs differ, take a.sign and add the magnitudes. - else if (a.sign != b.sign) { - sign = a.sign; - mag.add(a.mag, b.mag); - } else { - // Otherwise, their magnitudes must be compared. - switch (a.mag.compareTo(b.mag)) { - // If their magnitudes are the same, copy zero. - case equal: - mag = 0; - sign = zero; - break; - // If a's magnitude is greater, take a.sign and - // subtract a from b. - case greater: - sign = a.sign; - mag.subtract(a.mag, b.mag); - break; - // If b's magnitude is greater, take the opposite - // of b.sign and subtract b from a. - case less: - sign = Sign(-b.sign); - mag.subtract(b.mag, a.mag); - break; - } - } -} - -void BigInteger::multiply(const BigInteger &a, const BigInteger &b) { - DTRT_ALIASED(this == &a || this == &b, multiply(a, b)); - // If one object is zero, copy zero and return. - if (a.sign == zero || b.sign == zero) { - sign = zero; - mag = 0; - return; - } - // If the signs of the arguments are the same, the result - // is positive, otherwise it is negative. - sign = (a.sign == b.sign) ? positive : negative; - // Multiply the magnitudes. - mag.multiply(a.mag, b.mag); -} - -/* - * DIVISION WITH REMAINDER - * Please read the comments before the definition of - * `BigUnsigned::divideWithRemainder' in `BigUnsigned.cc' for lots of - * information you should know before reading this function. - * - * Following Knuth, I decree that x / y is to be - * 0 if y==0 and floor(real-number x / y) if y!=0. - * Then x % y shall be x - y*(integer x / y). - * - * Note that x = y * (x / y) + (x % y) always holds. - * In addition, (x % y) is from 0 to y - 1 if y > 0, - * and from -(|y| - 1) to 0 if y < 0. (x % y) = x if y = 0. - * - * Examples: (q = a / b, r = a % b) - * a b q r - * === === === === - * 4 3 1 1 - * -4 3 -2 2 - * 4 -3 -2 -2 - * -4 -3 1 -1 - */ -void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) { - // Defend against aliased calls; - // same idea as in BigUnsigned::divideWithRemainder . - if (this == &q) - throw "BigInteger::divideWithRemainder: Cannot write quotient and remainder into the same variable"; - if (this == &b || &q == &b) { - BigInteger tmpB(b); - divideWithRemainder(tmpB, q); - return; - } - - // Division by zero gives quotient 0 and remainder *this - if (b.sign == zero) { - q.mag = 0; - q.sign = zero; - return; - } - // 0 / b gives quotient 0 and remainder 0 - if (sign == zero) { - q.mag = 0; - q.sign = zero; - return; - } - - // Here *this != 0, b != 0. - - // Do the operands have the same sign? - if (sign == b.sign) { - // Yes: easy case. Quotient is zero or positive. - q.sign = positive; - } else { - // No: harder case. Quotient is negative. - q.sign = negative; - // Decrease the magnitude of the dividend by one. - mag--; - /* - * We tinker with the dividend before and with the - * quotient and remainder after so that the result - * comes out right. To see why it works, consider the following - * list of examples, where A is the magnitude-decreased - * a, Q and R are the results of BigUnsigned division - * with remainder on A and |b|, and q and r are the - * final results we want: - * - * a A b Q R q r - * -3 -2 3 0 2 -1 0 - * -4 -3 3 1 0 -2 2 - * -5 -4 3 1 1 -2 1 - * -6 -5 3 1 2 -2 0 - * - * It appears that we need a total of 3 corrections: - * Decrease the magnitude of a to get A. Increase the - * magnitude of Q to get q (and make it negative). - * Find r = (b - 1) - R and give it the desired sign. - */ - } - - // Divide the magnitudes. - mag.divideWithRemainder(b.mag, q.mag); - - if (sign != b.sign) { - // More for the harder case (as described): - // Increase the magnitude of the quotient by one. - q.mag++; - // Modify the remainder. - mag.subtract(b.mag, mag); - mag--; - } - - // Sign of the remainder is always the sign of the divisor b. - sign = b.sign; - - // Set signs to zero as necessary. (Thanks David Allen!) - if (mag.isZero()) - sign = zero; - if (q.mag.isZero()) - q.sign = zero; - - // WHEW!!! -} - -// Negation -void BigInteger::negate(const BigInteger &a) { - DTRT_ALIASED(this == &a, negate(a)); - // Copy a's magnitude - mag = a.mag; - // Copy the opposite of a.sign - sign = Sign(-a.sign); -} - -// INCREMENT/DECREMENT OPERATORS - -// Prefix increment -void BigInteger::operator ++() { - if (sign == negative) { - mag--; - if (mag == 0) - sign = zero; - } else { - mag++; - sign = positive; // if not already - } -} - -// Postfix increment: same as prefix -void BigInteger::operator ++(int) { - operator ++(); -} - -// Prefix decrement -void BigInteger::operator --() { - if (sign == positive) { - mag--; - if (mag == 0) - sign = zero; - } else { - mag++; - sign = negative; - } -} - -// Postfix decrement: same as prefix -void BigInteger::operator --(int) { - operator --(); -} - diff --git a/yosys/libs/bigint/BigInteger.hh b/yosys/libs/bigint/BigInteger.hh deleted file mode 100644 index cf6e91056..000000000 --- a/yosys/libs/bigint/BigInteger.hh +++ /dev/null @@ -1,215 +0,0 @@ -#ifndef BIGINTEGER_H -#define BIGINTEGER_H - -#include "BigUnsigned.hh" - -/* A BigInteger object represents a signed integer of size limited only by - * available memory. BigUnsigneds support most mathematical operators and can - * be converted to and from most primitive integer types. - * - * A BigInteger is just an aggregate of a BigUnsigned and a sign. (It is no - * longer derived from BigUnsigned because that led to harmful implicit - * conversions.) */ -class BigInteger { - -public: - typedef BigUnsigned::Blk Blk; - typedef BigUnsigned::Index Index; - typedef BigUnsigned::CmpRes CmpRes; - static const CmpRes - less = BigUnsigned::less , - equal = BigUnsigned::equal , - greater = BigUnsigned::greater; - // Enumeration for the sign of a BigInteger. - enum Sign { negative = -1, zero = 0, positive = 1 }; - -protected: - Sign sign; - BigUnsigned mag; - -public: - // Constructs zero. - BigInteger() : sign(zero), mag() {} - - // Copy constructor - BigInteger(const BigInteger &x) : sign(x.sign), mag(x.mag) {}; - - // Assignment operator - void operator=(const BigInteger &x); - - // Constructor that copies from a given array of blocks with a sign. - BigInteger(const Blk *b, Index blen, Sign s); - - // Nonnegative constructor that copies from a given array of blocks. - BigInteger(const Blk *b, Index blen) : mag(b, blen) { - sign = mag.isZero() ? zero : positive; - } - - // Constructor from a BigUnsigned and a sign - BigInteger(const BigUnsigned &x, Sign s); - - // Nonnegative constructor from a BigUnsigned - BigInteger(const BigUnsigned &x) : mag(x) { - sign = mag.isZero() ? zero : positive; - } - - // Constructors from primitive integer types - BigInteger(unsigned long x); - BigInteger( long x); - BigInteger(unsigned int x); - BigInteger( int x); - BigInteger(unsigned short x); - BigInteger( short x); - - /* Converters to primitive integer types - * The implicit conversion operators caused trouble, so these are now - * named. */ - unsigned long toUnsignedLong () const; - long toLong () const; - unsigned int toUnsignedInt () const; - int toInt () const; - unsigned short toUnsignedShort() const; - short toShort () const; -protected: - // Helper - template X convertToUnsignedPrimitive() const; - template X convertToSignedPrimitive() const; -public: - - // ACCESSORS - Sign getSign() const { return sign; } - /* The client can't do any harm by holding a read-only reference to the - * magnitude. */ - const BigUnsigned &getMagnitude() const { return mag; } - - // Some accessors that go through to the magnitude - Index getLength() const { return mag.getLength(); } - Index getCapacity() const { return mag.getCapacity(); } - Blk getBlock(Index i) const { return mag.getBlock(i); } - bool isZero() const { return sign == zero; } // A bit special - - // COMPARISONS - - // Compares this to x like Perl's <=> - CmpRes compareTo(const BigInteger &x) const; - - // Ordinary comparison operators - bool operator ==(const BigInteger &x) const { - return sign == x.sign && mag == x.mag; - } - bool operator !=(const BigInteger &x) const { return !operator ==(x); }; - bool operator < (const BigInteger &x) const { return compareTo(x) == less ; } - bool operator <=(const BigInteger &x) const { return compareTo(x) != greater; } - bool operator >=(const BigInteger &x) const { return compareTo(x) != less ; } - bool operator > (const BigInteger &x) const { return compareTo(x) == greater; } - - // OPERATORS -- See the discussion in BigUnsigned.hh. - void add (const BigInteger &a, const BigInteger &b); - void subtract(const BigInteger &a, const BigInteger &b); - void multiply(const BigInteger &a, const BigInteger &b); - /* See the comment on BigUnsigned::divideWithRemainder. Semantics - * differ from those of primitive integers when negatives and/or zeros - * are involved. */ - void divideWithRemainder(const BigInteger &b, BigInteger &q); - void negate(const BigInteger &a); - - /* Bitwise operators are not provided for BigIntegers. Use - * getMagnitude to get the magnitude and operate on that instead. */ - - BigInteger operator +(const BigInteger &x) const; - BigInteger operator -(const BigInteger &x) const; - BigInteger operator *(const BigInteger &x) const; - BigInteger operator /(const BigInteger &x) const; - BigInteger operator %(const BigInteger &x) const; - BigInteger operator -() const; - - void operator +=(const BigInteger &x); - void operator -=(const BigInteger &x); - void operator *=(const BigInteger &x); - void operator /=(const BigInteger &x); - void operator %=(const BigInteger &x); - void flipSign(); - - // INCREMENT/DECREMENT OPERATORS - void operator ++( ); - void operator ++(int); - void operator --( ); - void operator --(int); -}; - -// NORMAL OPERATORS -/* These create an object to hold the result and invoke - * the appropriate put-here operation on it, passing - * this and x. The new object is then returned. */ -inline BigInteger BigInteger::operator +(const BigInteger &x) const { - BigInteger ans; - ans.add(*this, x); - return ans; -} -inline BigInteger BigInteger::operator -(const BigInteger &x) const { - BigInteger ans; - ans.subtract(*this, x); - return ans; -} -inline BigInteger BigInteger::operator *(const BigInteger &x) const { - BigInteger ans; - ans.multiply(*this, x); - return ans; -} -inline BigInteger BigInteger::operator /(const BigInteger &x) const { - if (x.isZero()) throw "BigInteger::operator /: division by zero"; - BigInteger q, r; - r = *this; - r.divideWithRemainder(x, q); - return q; -} -inline BigInteger BigInteger::operator %(const BigInteger &x) const { - if (x.isZero()) throw "BigInteger::operator %: division by zero"; - BigInteger q, r; - r = *this; - r.divideWithRemainder(x, q); - return r; -} -inline BigInteger BigInteger::operator -() const { - BigInteger ans; - ans.negate(*this); - return ans; -} - -/* - * ASSIGNMENT OPERATORS - * - * Now the responsibility for making a temporary copy if necessary - * belongs to the put-here operations. See Assignment Operators in - * BigUnsigned.hh. - */ -inline void BigInteger::operator +=(const BigInteger &x) { - add(*this, x); -} -inline void BigInteger::operator -=(const BigInteger &x) { - subtract(*this, x); -} -inline void BigInteger::operator *=(const BigInteger &x) { - multiply(*this, x); -} -inline void BigInteger::operator /=(const BigInteger &x) { - if (x.isZero()) throw "BigInteger::operator /=: division by zero"; - /* The following technique is slightly faster than copying *this first - * when x is large. */ - BigInteger q; - divideWithRemainder(x, q); - // *this contains the remainder, but we overwrite it with the quotient. - *this = q; -} -inline void BigInteger::operator %=(const BigInteger &x) { - if (x.isZero()) throw "BigInteger::operator %=: division by zero"; - BigInteger q; - // Mods *this by x. Don't care about quotient left in q. - divideWithRemainder(x, q); -} -// This one is trivial -inline void BigInteger::flipSign() { - sign = Sign(-sign); -} - -#endif diff --git a/yosys/libs/bigint/BigIntegerAlgorithms.cc b/yosys/libs/bigint/BigIntegerAlgorithms.cc deleted file mode 100644 index 7edebda76..000000000 --- a/yosys/libs/bigint/BigIntegerAlgorithms.cc +++ /dev/null @@ -1,70 +0,0 @@ -#include "BigIntegerAlgorithms.hh" - -BigUnsigned gcd(BigUnsigned a, BigUnsigned b) { - BigUnsigned trash; - // Neat in-place alternating technique. - for (;;) { - if (b.isZero()) - return a; - a.divideWithRemainder(b, trash); - if (a.isZero()) - return b; - b.divideWithRemainder(a, trash); - } -} - -void extendedEuclidean(BigInteger m, BigInteger n, - BigInteger &g, BigInteger &r, BigInteger &s) { - if (&g == &r || &g == &s || &r == &s) - throw "BigInteger extendedEuclidean: Outputs are aliased"; - BigInteger r1(1), s1(0), r2(0), s2(1), q; - /* Invariants: - * r1*m(orig) + s1*n(orig) == m(current) - * r2*m(orig) + s2*n(orig) == n(current) */ - for (;;) { - if (n.isZero()) { - r = r1; s = s1; g = m; - return; - } - // Subtract q times the second invariant from the first invariant. - m.divideWithRemainder(n, q); - r1 -= q*r2; s1 -= q*s2; - - if (m.isZero()) { - r = r2; s = s2; g = n; - return; - } - // Subtract q times the first invariant from the second invariant. - n.divideWithRemainder(m, q); - r2 -= q*r1; s2 -= q*s1; - } -} - -BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n) { - BigInteger g, r, s; - extendedEuclidean(x, n, g, r, s); - if (g == 1) - // r*x + s*n == 1, so r*x === 1 (mod n), so r is the answer. - return (r % n).getMagnitude(); // (r % n) will be nonnegative - else - throw "BigInteger modinv: x and n have a common factor"; -} - -BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent, - const BigUnsigned &modulus) { - BigUnsigned ans = 1, base2 = (base % modulus).getMagnitude(); - BigUnsigned::Index i = exponent.bitLength(); - // For each bit of the exponent, most to least significant... - while (i > 0) { - i--; - // Square. - ans *= ans; - ans %= modulus; - // And multiply if the bit is a 1. - if (exponent.getBit(i)) { - ans *= base2; - ans %= modulus; - } - } - return ans; -} diff --git a/yosys/libs/bigint/BigIntegerAlgorithms.hh b/yosys/libs/bigint/BigIntegerAlgorithms.hh deleted file mode 100644 index b1dd94322..000000000 --- a/yosys/libs/bigint/BigIntegerAlgorithms.hh +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef BIGINTEGERALGORITHMS_H -#define BIGINTEGERALGORITHMS_H - -#include "BigInteger.hh" - -/* Some mathematical algorithms for big integers. - * This code is new and, as such, experimental. */ - -// Returns the greatest common divisor of a and b. -BigUnsigned gcd(BigUnsigned a, BigUnsigned b); - -/* Extended Euclidean algorithm. - * Given m and n, finds gcd g and numbers r, s such that r*m + s*n == g. */ -void extendedEuclidean(BigInteger m, BigInteger n, - BigInteger &g, BigInteger &r, BigInteger &s); - -/* Returns the multiplicative inverse of x modulo n, or throws an exception if - * they have a common factor. */ -BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n); - -// Returns (base ^ exponent) % modulus. -BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent, - const BigUnsigned &modulus); - -#endif diff --git a/yosys/libs/bigint/BigIntegerLibrary.hh b/yosys/libs/bigint/BigIntegerLibrary.hh deleted file mode 100644 index 2a0ebee6a..000000000 --- a/yosys/libs/bigint/BigIntegerLibrary.hh +++ /dev/null @@ -1,8 +0,0 @@ -// This header file includes all of the library header files. - -#include "NumberlikeArray.hh" -#include "BigUnsigned.hh" -#include "BigInteger.hh" -#include "BigIntegerAlgorithms.hh" -#include "BigUnsignedInABase.hh" -#include "BigIntegerUtils.hh" diff --git a/yosys/libs/bigint/BigIntegerUtils.cc b/yosys/libs/bigint/BigIntegerUtils.cc deleted file mode 100644 index 44073af65..000000000 --- a/yosys/libs/bigint/BigIntegerUtils.cc +++ /dev/null @@ -1,50 +0,0 @@ -#include "BigIntegerUtils.hh" -#include "BigUnsignedInABase.hh" - -std::string bigUnsignedToString(const BigUnsigned &x) { - return std::string(BigUnsignedInABase(x, 10)); -} - -std::string bigIntegerToString(const BigInteger &x) { - return (x.getSign() == BigInteger::negative) - ? (std::string("-") + bigUnsignedToString(x.getMagnitude())) - : (bigUnsignedToString(x.getMagnitude())); -} - -BigUnsigned stringToBigUnsigned(const std::string &s) { - return BigUnsigned(BigUnsignedInABase(s, 10)); -} - -BigInteger stringToBigInteger(const std::string &s) { - // Recognize a sign followed by a BigUnsigned. - return (s[0] == '-') ? BigInteger(stringToBigUnsigned(s.substr(1, s.length() - 1)), BigInteger::negative) - : (s[0] == '+') ? BigInteger(stringToBigUnsigned(s.substr(1, s.length() - 1))) - : BigInteger(stringToBigUnsigned(s)); -} - -std::ostream &operator <<(std::ostream &os, const BigUnsigned &x) { - BigUnsignedInABase::Base base; - long osFlags = os.flags(); - if (osFlags & os.dec) - base = 10; - else if (osFlags & os.hex) { - base = 16; - if (osFlags & os.showbase) - os << "0x"; - } else if (osFlags & os.oct) { - base = 8; - if (osFlags & os.showbase) - os << '0'; - } else - throw "std::ostream << BigUnsigned: Could not determine the desired base from output-stream flags"; - std::string s = std::string(BigUnsignedInABase(x, base)); - os << s; - return os; -} - -std::ostream &operator <<(std::ostream &os, const BigInteger &x) { - if (x.getSign() == BigInteger::negative) - os << '-'; - os << x.getMagnitude(); - return os; -} diff --git a/yosys/libs/bigint/BigIntegerUtils.hh b/yosys/libs/bigint/BigIntegerUtils.hh deleted file mode 100644 index c815b5d7c..000000000 --- a/yosys/libs/bigint/BigIntegerUtils.hh +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef BIGINTEGERUTILS_H -#define BIGINTEGERUTILS_H - -#include "BigInteger.hh" -#include -#include - -/* This file provides: - * - Convenient std::string <-> BigUnsigned/BigInteger conversion routines - * - std::ostream << operators for BigUnsigned/BigInteger */ - -// std::string conversion routines. Base 10 only. -std::string bigUnsignedToString(const BigUnsigned &x); -std::string bigIntegerToString(const BigInteger &x); -BigUnsigned stringToBigUnsigned(const std::string &s); -BigInteger stringToBigInteger(const std::string &s); - -// Creates a BigInteger from data such as `char's; read below for details. -template -BigInteger dataToBigInteger(const T* data, BigInteger::Index length, BigInteger::Sign sign); - -// Outputs x to os, obeying the flags `dec', `hex', `bin', and `showbase'. -std::ostream &operator <<(std::ostream &os, const BigUnsigned &x); - -// Outputs x to os, obeying the flags `dec', `hex', `bin', and `showbase'. -// My somewhat arbitrary policy: a negative sign comes before a base indicator (like -0xFF). -std::ostream &operator <<(std::ostream &os, const BigInteger &x); - -// BEGIN TEMPLATE DEFINITIONS. - -/* - * Converts binary data to a BigInteger. - * Pass an array `data', its length, and the desired sign. - * - * Elements of `data' may be of any type `T' that has the following - * two properties (this includes almost all integral types): - * - * (1) `sizeof(T)' correctly gives the amount of binary data in one - * value of `T' and is a factor of `sizeof(Blk)'. - * - * (2) When a value of `T' is casted to a `Blk', the low bytes of - * the result contain the desired binary data. - */ -template -BigInteger dataToBigInteger(const T* data, BigInteger::Index length, BigInteger::Sign sign) { - // really ceiling(numBytes / sizeof(BigInteger::Blk)) - unsigned int pieceSizeInBits = 8 * sizeof(T); - unsigned int piecesPerBlock = sizeof(BigInteger::Blk) / sizeof(T); - unsigned int numBlocks = (length + piecesPerBlock - 1) / piecesPerBlock; - - // Allocate our block array - BigInteger::Blk *blocks = new BigInteger::Blk[numBlocks]; - - BigInteger::Index blockNum, pieceNum, pieceNumHere; - - // Convert - for (blockNum = 0, pieceNum = 0; blockNum < numBlocks; blockNum++) { - BigInteger::Blk curBlock = 0; - for (pieceNumHere = 0; pieceNumHere < piecesPerBlock && pieceNum < length; - pieceNumHere++, pieceNum++) - curBlock |= (BigInteger::Blk(data[pieceNum]) << (pieceSizeInBits * pieceNumHere)); - blocks[blockNum] = curBlock; - } - - // Create the BigInteger. - BigInteger x(blocks, numBlocks, sign); - - delete [] blocks; - return x; -} - -#endif diff --git a/yosys/libs/bigint/BigUnsigned.cc b/yosys/libs/bigint/BigUnsigned.cc deleted file mode 100644 index d7f9889cc..000000000 --- a/yosys/libs/bigint/BigUnsigned.cc +++ /dev/null @@ -1,697 +0,0 @@ -#include "BigUnsigned.hh" - -// Memory management definitions have moved to the bottom of NumberlikeArray.hh. - -// The templates used by these constructors and converters are at the bottom of -// BigUnsigned.hh. - -BigUnsigned::BigUnsigned(unsigned long x) { initFromPrimitive (x); } -BigUnsigned::BigUnsigned(unsigned int x) { initFromPrimitive (x); } -BigUnsigned::BigUnsigned(unsigned short x) { initFromPrimitive (x); } -BigUnsigned::BigUnsigned( long x) { initFromSignedPrimitive(x); } -BigUnsigned::BigUnsigned( int x) { initFromSignedPrimitive(x); } -BigUnsigned::BigUnsigned( short x) { initFromSignedPrimitive(x); } - -unsigned long BigUnsigned::toUnsignedLong () const { return convertToPrimitive (); } -unsigned int BigUnsigned::toUnsignedInt () const { return convertToPrimitive (); } -unsigned short BigUnsigned::toUnsignedShort() const { return convertToPrimitive (); } -long BigUnsigned::toLong () const { return convertToSignedPrimitive< long >(); } -int BigUnsigned::toInt () const { return convertToSignedPrimitive< int >(); } -short BigUnsigned::toShort () const { return convertToSignedPrimitive< short>(); } - -// BIT/BLOCK ACCESSORS - -void BigUnsigned::setBlock(Index i, Blk newBlock) { - if (newBlock == 0) { - if (i < len) { - blk[i] = 0; - zapLeadingZeros(); - } - // If i >= len, no effect. - } else { - if (i >= len) { - // The nonzero block extends the number. - allocateAndCopy(i+1); - // Zero any added blocks that we aren't setting. - for (Index j = len; j < i; j++) - blk[j] = 0; - len = i+1; - } - blk[i] = newBlock; - } -} - -/* Evidently the compiler wants BigUnsigned:: on the return type because, at - * that point, it hasn't yet parsed the BigUnsigned:: on the name to get the - * proper scope. */ -BigUnsigned::Index BigUnsigned::bitLength() const { - if (isZero()) - return 0; - else { - Blk leftmostBlock = getBlock(len - 1); - Index leftmostBlockLen = 0; - while (leftmostBlock != 0) { - leftmostBlock >>= 1; - leftmostBlockLen++; - } - return leftmostBlockLen + (len - 1) * N; - } -} - -void BigUnsigned::setBit(Index bi, bool newBit) { - Index blockI = bi / N; - Blk block = getBlock(blockI), mask = Blk(1) << (bi % N); - block = newBit ? (block | mask) : (block & ~mask); - setBlock(blockI, block); -} - -// COMPARISON -BigUnsigned::CmpRes BigUnsigned::compareTo(const BigUnsigned &x) const { - // A bigger length implies a bigger number. - if (len < x.len) - return less; - else if (len > x.len) - return greater; - else { - // Compare blocks one by one from left to right. - Index i = len; - while (i > 0) { - i--; - if (blk[i] == x.blk[i]) - continue; - else if (blk[i] > x.blk[i]) - return greater; - else - return less; - } - // If no blocks differed, the numbers are equal. - return equal; - } -} - -// COPY-LESS OPERATIONS - -/* - * On most calls to copy-less operations, it's safe to read the inputs little by - * little and write the outputs little by little. However, if one of the - * inputs is coming from the same variable into which the output is to be - * stored (an "aliased" call), we risk overwriting the input before we read it. - * In this case, we first compute the result into a temporary BigUnsigned - * variable and then copy it into the requested output variable *this. - * Each put-here operation uses the DTRT_ALIASED macro (Do The Right Thing on - * aliased calls) to generate code for this check. - * - * I adopted this approach on 2007.02.13 (see Assignment Operators in - * BigUnsigned.hh). Before then, put-here operations rejected aliased calls - * with an exception. I think doing the right thing is better. - * - * Some of the put-here operations can probably handle aliased calls safely - * without the extra copy because (for example) they process blocks strictly - * right-to-left. At some point I might determine which ones don't need the - * copy, but my reasoning would need to be verified very carefully. For now - * I'll leave in the copy. - */ -#define DTRT_ALIASED(cond, op) \ - if (cond) { \ - BigUnsigned tmpThis; \ - tmpThis.op; \ - *this = tmpThis; \ - return; \ - } - - - -void BigUnsigned::add(const BigUnsigned &a, const BigUnsigned &b) { - DTRT_ALIASED(this == &a || this == &b, add(a, b)); - // If one argument is zero, copy the other. - if (a.len == 0) { - operator =(b); - return; - } else if (b.len == 0) { - operator =(a); - return; - } - // Some variables... - // Carries in and out of an addition stage - bool carryIn, carryOut; - Blk temp; - Index i; - // a2 points to the longer input, b2 points to the shorter - const BigUnsigned *a2, *b2; - if (a.len >= b.len) { - a2 = &a; - b2 = &b; - } else { - a2 = &b; - b2 = &a; - } - // Set prelimiary length and make room in this BigUnsigned - len = a2->len + 1; - allocate(len); - // For each block index that is present in both inputs... - for (i = 0, carryIn = false; i < b2->len; i++) { - // Add input blocks - temp = a2->blk[i] + b2->blk[i]; - // If a rollover occurred, the result is less than either input. - // This test is used many times in the BigUnsigned code. - carryOut = (temp < a2->blk[i]); - // If a carry was input, handle it - if (carryIn) { - temp++; - carryOut |= (temp == 0); - } - blk[i] = temp; // Save the addition result - carryIn = carryOut; // Pass the carry along - } - // If there is a carry left over, increase blocks until - // one does not roll over. - for (; i < a2->len && carryIn; i++) { - temp = a2->blk[i] + 1; - carryIn = (temp == 0); - blk[i] = temp; - } - // If the carry was resolved but the larger number - // still has blocks, copy them over. - for (; i < a2->len; i++) - blk[i] = a2->blk[i]; - // Set the extra block if there's still a carry, decrease length otherwise - if (carryIn) - blk[i] = 1; - else - len--; -} - -void BigUnsigned::subtract(const BigUnsigned &a, const BigUnsigned &b) { - DTRT_ALIASED(this == &a || this == &b, subtract(a, b)); - if (b.len == 0) { - // If b is zero, copy a. - operator =(a); - return; - } else if (a.len < b.len) - // If a is shorter than b, the result is negative. - throw "BigUnsigned::subtract: " - "Negative result in unsigned calculation"; - // Some variables... - bool borrowIn, borrowOut; - Blk temp; - Index i; - // Set preliminary length and make room - len = a.len; - allocate(len); - // For each block index that is present in both inputs... - for (i = 0, borrowIn = false; i < b.len; i++) { - temp = a.blk[i] - b.blk[i]; - // If a reverse rollover occurred, - // the result is greater than the block from a. - borrowOut = (temp > a.blk[i]); - // Handle an incoming borrow - if (borrowIn) { - borrowOut |= (temp == 0); - temp--; - } - blk[i] = temp; // Save the subtraction result - borrowIn = borrowOut; // Pass the borrow along - } - // If there is a borrow left over, decrease blocks until - // one does not reverse rollover. - for (; i < a.len && borrowIn; i++) { - borrowIn = (a.blk[i] == 0); - blk[i] = a.blk[i] - 1; - } - /* If there's still a borrow, the result is negative. - * Throw an exception, but zero out this object so as to leave it in a - * predictable state. */ - if (borrowIn) { - len = 0; - throw "BigUnsigned::subtract: Negative result in unsigned calculation"; - } else - // Copy over the rest of the blocks - for (; i < a.len; i++) - blk[i] = a.blk[i]; - // Zap leading zeros - zapLeadingZeros(); -} - -/* - * About the multiplication and division algorithms: - * - * I searched unsucessfully for fast C++ built-in operations like the `b_0' - * and `c_0' Knuth describes in Section 4.3.1 of ``The Art of Computer - * Programming'' (replace `place' by `Blk'): - * - * ``b_0[:] multiplication of a one-place integer by another one-place - * integer, giving a two-place answer; - * - * ``c_0[:] division of a two-place integer by a one-place integer, - * provided that the quotient is a one-place integer, and yielding - * also a one-place remainder.'' - * - * I also missed his note that ``[b]y adjusting the word size, if - * necessary, nearly all computers will have these three operations - * available'', so I gave up on trying to use algorithms similar to his. - * A future version of the library might include such algorithms; I - * would welcome contributions from others for this. - * - * I eventually decided to use bit-shifting algorithms. To multiply `a' - * and `b', we zero out the result. Then, for each `1' bit in `a', we - * shift `b' left the appropriate amount and add it to the result. - * Similarly, to divide `a' by `b', we shift `b' left varying amounts, - * repeatedly trying to subtract it from `a'. When we succeed, we note - * the fact by setting a bit in the quotient. While these algorithms - * have the same O(n^2) time complexity as Knuth's, the ``constant factor'' - * is likely to be larger. - * - * Because I used these algorithms, which require single-block addition - * and subtraction rather than single-block multiplication and division, - * the innermost loops of all four routines are very similar. Study one - * of them and all will become clear. - */ - -/* - * This is a little inline function used by both the multiplication - * routine and the division routine. - * - * `getShiftedBlock' returns the `x'th block of `num << y'. - * `y' may be anything from 0 to N - 1, and `x' may be anything from - * 0 to `num.len'. - * - * Two things contribute to this block: - * - * (1) The `N - y' low bits of `num.blk[x]', shifted `y' bits left. - * - * (2) The `y' high bits of `num.blk[x-1]', shifted `N - y' bits right. - * - * But we must be careful if `x == 0' or `x == num.len', in - * which case we should use 0 instead of (2) or (1), respectively. - * - * If `y == 0', then (2) contributes 0, as it should. However, - * in some computer environments, for a reason I cannot understand, - * `a >> b' means `a >> (b % N)'. This means `num.blk[x-1] >> (N - y)' - * will return `num.blk[x-1]' instead of the desired 0 when `y == 0'; - * the test `y == 0' handles this case specially. - */ -inline BigUnsigned::Blk getShiftedBlock(const BigUnsigned &num, - BigUnsigned::Index x, unsigned int y) { - BigUnsigned::Blk part1 = (x == 0 || y == 0) ? 0 : (num.blk[x - 1] >> (BigUnsigned::N - y)); - BigUnsigned::Blk part2 = (x == num.len) ? 0 : (num.blk[x] << y); - return part1 | part2; -} - -void BigUnsigned::multiply(const BigUnsigned &a, const BigUnsigned &b) { - DTRT_ALIASED(this == &a || this == &b, multiply(a, b)); - // If either a or b is zero, set to zero. - if (a.len == 0 || b.len == 0) { - len = 0; - return; - } - /* - * Overall method: - * - * Set this = 0. - * For each 1-bit of `a' (say the `i2'th bit of block `i'): - * Add `b << (i blocks and i2 bits)' to *this. - */ - // Variables for the calculation - Index i, j, k; - unsigned int i2; - Blk temp; - bool carryIn, carryOut; - // Set preliminary length and make room - len = a.len + b.len; - allocate(len); - // Zero out this object - for (i = 0; i < len; i++) - blk[i] = 0; - // For each block of the first number... - for (i = 0; i < a.len; i++) { - // For each 1-bit of that block... - for (i2 = 0; i2 < N; i2++) { - if ((a.blk[i] & (Blk(1) << i2)) == 0) - continue; - /* - * Add b to this, shifted left i blocks and i2 bits. - * j is the index in b, and k = i + j is the index in this. - * - * `getShiftedBlock', a short inline function defined above, - * is now used for the bit handling. It replaces the more - * complex `bHigh' code, in which each run of the loop dealt - * immediately with the low bits and saved the high bits to - * be picked up next time. The last run of the loop used to - * leave leftover high bits, which were handled separately. - * Instead, this loop runs an additional time with j == b.len. - * These changes were made on 2005.01.11. - */ - for (j = 0, k = i, carryIn = false; j <= b.len; j++, k++) { - /* - * The body of this loop is very similar to the body of the first loop - * in `add', except that this loop does a `+=' instead of a `+'. - */ - temp = blk[k] + getShiftedBlock(b, j, i2); - carryOut = (temp < blk[k]); - if (carryIn) { - temp++; - carryOut |= (temp == 0); - } - blk[k] = temp; - carryIn = carryOut; - } - // No more extra iteration to deal with `bHigh'. - // Roll-over a carry as necessary. - for (; carryIn; k++) { - blk[k]++; - carryIn = (blk[k] == 0); - } - } - } - // Zap possible leading zero - if (blk[len - 1] == 0) - len--; -} - -/* - * DIVISION WITH REMAINDER - * This monstrous function mods *this by the given divisor b while storing the - * quotient in the given object q; at the end, *this contains the remainder. - * The seemingly bizarre pattern of inputs and outputs was chosen so that the - * function copies as little as possible (since it is implemented by repeated - * subtraction of multiples of b from *this). - * - * "modWithQuotient" might be a better name for this function, but I would - * rather not change the name now. - */ -void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) { - /* Defending against aliased calls is more complex than usual because we - * are writing to both *this and q. - * - * It would be silly to try to write quotient and remainder to the - * same variable. Rule that out right away. */ - if (this == &q) - throw "BigUnsigned::divideWithRemainder: Cannot write quotient and remainder into the same variable"; - /* Now *this and q are separate, so the only concern is that b might be - * aliased to one of them. If so, use a temporary copy of b. */ - if (this == &b || &q == &b) { - BigUnsigned tmpB(b); - divideWithRemainder(tmpB, q); - return; - } - - /* - * Knuth's definition of mod (which this function uses) is somewhat - * different from the C++ definition of % in case of division by 0. - * - * We let a / 0 == 0 (it doesn't matter much) and a % 0 == a, no - * exceptions thrown. This allows us to preserve both Knuth's demand - * that a mod 0 == a and the useful property that - * (a / b) * b + (a % b) == a. - */ - if (b.len == 0) { - q.len = 0; - return; - } - - /* - * If *this.len < b.len, then *this < b, and we can be sure that b doesn't go into - * *this at all. The quotient is 0 and *this is already the remainder (so leave it alone). - */ - if (len < b.len) { - q.len = 0; - return; - } - - // At this point we know (*this).len >= b.len > 0. (Whew!) - - /* - * Overall method: - * - * For each appropriate i and i2, decreasing: - * Subtract (b << (i blocks and i2 bits)) from *this, storing the - * result in subtractBuf. - * If the subtraction succeeds with a nonnegative result: - * Turn on bit i2 of block i of the quotient q. - * Copy subtractBuf back into *this. - * Otherwise bit i2 of block i remains off, and *this is unchanged. - * - * Eventually q will contain the entire quotient, and *this will - * be left with the remainder. - * - * subtractBuf[x] corresponds to blk[x], not blk[x+i], since 2005.01.11. - * But on a single iteration, we don't touch the i lowest blocks of blk - * (and don't use those of subtractBuf) because these blocks are - * unaffected by the subtraction: we are subtracting - * (b << (i blocks and i2 bits)), which ends in at least `i' zero - * blocks. */ - // Variables for the calculation - Index i, j, k; - unsigned int i2; - Blk temp; - bool borrowIn, borrowOut; - - /* - * Make sure we have an extra zero block just past the value. - * - * When we attempt a subtraction, we might shift `b' so - * its first block begins a few bits left of the dividend, - * and then we'll try to compare these extra bits with - * a nonexistent block to the left of the dividend. The - * extra zero block ensures sensible behavior; we need - * an extra block in `subtractBuf' for exactly the same reason. - */ - Index origLen = len; // Save real length. - /* To avoid an out-of-bounds access in case of reallocation, allocate - * first and then increment the logical length. */ - allocateAndCopy(len + 1); - len++; - blk[origLen] = 0; // Zero the added block. - - // subtractBuf holds part of the result of a subtraction; see above. - Blk *subtractBuf = new Blk[len]; - - // Set preliminary length for quotient and make room - q.len = origLen - b.len + 1; - q.allocate(q.len); - // Zero out the quotient - for (i = 0; i < q.len; i++) - q.blk[i] = 0; - - // For each possible left-shift of b in blocks... - i = q.len; - while (i > 0) { - i--; - // For each possible left-shift of b in bits... - // (Remember, N is the number of bits in a Blk.) - q.blk[i] = 0; - i2 = N; - while (i2 > 0) { - i2--; - /* - * Subtract b, shifted left i blocks and i2 bits, from *this, - * and store the answer in subtractBuf. In the for loop, `k == i + j'. - * - * Compare this to the middle section of `multiply'. They - * are in many ways analogous. See especially the discussion - * of `getShiftedBlock'. - */ - for (j = 0, k = i, borrowIn = false; j <= b.len; j++, k++) { - temp = blk[k] - getShiftedBlock(b, j, i2); - borrowOut = (temp > blk[k]); - if (borrowIn) { - borrowOut |= (temp == 0); - temp--; - } - // Since 2005.01.11, indices of `subtractBuf' directly match those of `blk', so use `k'. - subtractBuf[k] = temp; - borrowIn = borrowOut; - } - // No more extra iteration to deal with `bHigh'. - // Roll-over a borrow as necessary. - for (; k < origLen && borrowIn; k++) { - borrowIn = (blk[k] == 0); - subtractBuf[k] = blk[k] - 1; - } - /* - * If the subtraction was performed successfully (!borrowIn), - * set bit i2 in block i of the quotient. - * - * Then, copy the portion of subtractBuf filled by the subtraction - * back to *this. This portion starts with block i and ends-- - * where? Not necessarily at block `i + b.len'! Well, we - * increased k every time we saved a block into subtractBuf, so - * the region of subtractBuf we copy is just [i, k). - */ - if (!borrowIn) { - q.blk[i] |= (Blk(1) << i2); - while (k > i) { - k--; - blk[k] = subtractBuf[k]; - } - } - } - } - // Zap possible leading zero in quotient - if (q.blk[q.len - 1] == 0) - q.len--; - // Zap any/all leading zeros in remainder - zapLeadingZeros(); - // Deallocate subtractBuf. - // (Thanks to Brad Spencer for noticing my accidental omission of this!) - delete [] subtractBuf; -} - -/* BITWISE OPERATORS - * These are straightforward blockwise operations except that they differ in - * the output length and the necessity of zapLeadingZeros. */ - -void BigUnsigned::bitAnd(const BigUnsigned &a, const BigUnsigned &b) { - DTRT_ALIASED(this == &a || this == &b, bitAnd(a, b)); - // The bitwise & can't be longer than either operand. - len = (a.len >= b.len) ? b.len : a.len; - allocate(len); - Index i; - for (i = 0; i < len; i++) - blk[i] = a.blk[i] & b.blk[i]; - zapLeadingZeros(); -} - -void BigUnsigned::bitOr(const BigUnsigned &a, const BigUnsigned &b) { - DTRT_ALIASED(this == &a || this == &b, bitOr(a, b)); - Index i; - const BigUnsigned *a2, *b2; - if (a.len >= b.len) { - a2 = &a; - b2 = &b; - } else { - a2 = &b; - b2 = &a; - } - allocate(a2->len); - for (i = 0; i < b2->len; i++) - blk[i] = a2->blk[i] | b2->blk[i]; - for (; i < a2->len; i++) - blk[i] = a2->blk[i]; - len = a2->len; - // Doesn't need zapLeadingZeros. -} - -void BigUnsigned::bitXor(const BigUnsigned &a, const BigUnsigned &b) { - DTRT_ALIASED(this == &a || this == &b, bitXor(a, b)); - Index i; - const BigUnsigned *a2, *b2; - if (a.len >= b.len) { - a2 = &a; - b2 = &b; - } else { - a2 = &b; - b2 = &a; - } - allocate(a2->len); - for (i = 0; i < b2->len; i++) - blk[i] = a2->blk[i] ^ b2->blk[i]; - for (; i < a2->len; i++) - blk[i] = a2->blk[i]; - len = a2->len; - zapLeadingZeros(); -} - -void BigUnsigned::bitShiftLeft(const BigUnsigned &a, int b) { - DTRT_ALIASED(this == &a, bitShiftLeft(a, b)); - if (b < 0) { - if (b << 1 == 0) - throw "BigUnsigned::bitShiftLeft: " - "Pathological shift amount not implemented"; - else { - bitShiftRight(a, -b); - return; - } - } - Index shiftBlocks = b / N; - unsigned int shiftBits = b % N; - // + 1: room for high bits nudged left into another block - len = a.len + shiftBlocks + 1; - allocate(len); - Index i, j; - for (i = 0; i < shiftBlocks; i++) - blk[i] = 0; - for (j = 0, i = shiftBlocks; j <= a.len; j++, i++) - blk[i] = getShiftedBlock(a, j, shiftBits); - // Zap possible leading zero - if (blk[len - 1] == 0) - len--; -} - -void BigUnsigned::bitShiftRight(const BigUnsigned &a, int b) { - DTRT_ALIASED(this == &a, bitShiftRight(a, b)); - if (b < 0) { - if (b << 1 == 0) - throw "BigUnsigned::bitShiftRight: " - "Pathological shift amount not implemented"; - else { - bitShiftLeft(a, -b); - return; - } - } - // This calculation is wacky, but expressing the shift as a left bit shift - // within each block lets us use getShiftedBlock. - Index rightShiftBlocks = (b + N - 1) / N; - unsigned int leftShiftBits = N * rightShiftBlocks - b; - // Now (N * rightShiftBlocks - leftShiftBits) == b - // and 0 <= leftShiftBits < N. - if (rightShiftBlocks >= a.len + 1) { - // All of a is guaranteed to be shifted off, even considering the left - // bit shift. - len = 0; - return; - } - // Now we're allocating a positive amount. - // + 1: room for high bits nudged left into another block - len = a.len + 1 - rightShiftBlocks; - allocate(len); - Index i, j; - for (j = rightShiftBlocks, i = 0; j <= a.len; j++, i++) - blk[i] = getShiftedBlock(a, j, leftShiftBits); - // Zap possible leading zero - if (blk[len - 1] == 0) - len--; -} - -// INCREMENT/DECREMENT OPERATORS - -// Prefix increment -void BigUnsigned::operator ++() { - Index i; - bool carry = true; - for (i = 0; i < len && carry; i++) { - blk[i]++; - carry = (blk[i] == 0); - } - if (carry) { - // Allocate and then increase length, as in divideWithRemainder - allocateAndCopy(len + 1); - len++; - blk[i] = 1; - } -} - -// Postfix increment: same as prefix -void BigUnsigned::operator ++(int) { - operator ++(); -} - -// Prefix decrement -void BigUnsigned::operator --() { - if (len == 0) - throw "BigUnsigned::operator --(): Cannot decrement an unsigned zero"; - Index i; - bool borrow = true; - for (i = 0; borrow; i++) { - borrow = (blk[i] == 0); - blk[i]--; - } - // Zap possible leading zero (there can only be one) - if (blk[len - 1] == 0) - len--; -} - -// Postfix decrement: same as prefix -void BigUnsigned::operator --(int) { - operator --(); -} diff --git a/yosys/libs/bigint/BigUnsigned.hh b/yosys/libs/bigint/BigUnsigned.hh deleted file mode 100644 index 9228753c8..000000000 --- a/yosys/libs/bigint/BigUnsigned.hh +++ /dev/null @@ -1,418 +0,0 @@ -#ifndef BIGUNSIGNED_H -#define BIGUNSIGNED_H - -#include "NumberlikeArray.hh" - -/* A BigUnsigned object represents a nonnegative integer of size limited only by - * available memory. BigUnsigneds support most mathematical operators and can - * be converted to and from most primitive integer types. - * - * The number is stored as a NumberlikeArray of unsigned longs as if it were - * written in base 256^sizeof(unsigned long). The least significant block is - * first, and the length is such that the most significant block is nonzero. */ -class BigUnsigned : protected NumberlikeArray { - -public: - // Enumeration for the result of a comparison. - enum CmpRes { less = -1, equal = 0, greater = 1 }; - - // BigUnsigneds are built with a Blk type of unsigned long. - typedef unsigned long Blk; - - typedef NumberlikeArray::Index Index; - using NumberlikeArray::N; - -protected: - // Creates a BigUnsigned with a capacity; for internal use. - BigUnsigned(int, Index c) : NumberlikeArray(0, c) {} - - // Decreases len to eliminate any leading zero blocks. - void zapLeadingZeros() { - while (len > 0 && blk[len - 1] == 0) - len--; - } - -public: - // Constructs zero. - BigUnsigned() : NumberlikeArray() {} - - // Copy constructor - BigUnsigned(const BigUnsigned &x) : NumberlikeArray(x) {} - - // Assignment operator - void operator=(const BigUnsigned &x) { - NumberlikeArray::operator =(x); - } - - // Constructor that copies from a given array of blocks. - BigUnsigned(const Blk *b, Index blen) : NumberlikeArray(b, blen) { - // Eliminate any leading zeros we may have been passed. - zapLeadingZeros(); - } - - // Destructor. NumberlikeArray does the delete for us. - ~BigUnsigned() {} - - // Constructors from primitive integer types - BigUnsigned(unsigned long x); - BigUnsigned( long x); - BigUnsigned(unsigned int x); - BigUnsigned( int x); - BigUnsigned(unsigned short x); - BigUnsigned( short x); -protected: - // Helpers - template void initFromPrimitive (X x); - template void initFromSignedPrimitive(X x); -public: - - /* Converters to primitive integer types - * The implicit conversion operators caused trouble, so these are now - * named. */ - unsigned long toUnsignedLong () const; - long toLong () const; - unsigned int toUnsignedInt () const; - int toInt () const; - unsigned short toUnsignedShort() const; - short toShort () const; -protected: - // Helpers - template X convertToSignedPrimitive() const; - template X convertToPrimitive () const; -public: - - // BIT/BLOCK ACCESSORS - - // Expose these from NumberlikeArray directly. - using NumberlikeArray::getCapacity; - using NumberlikeArray::getLength; - - /* Returns the requested block, or 0 if it is beyond the length (as if - * the number had 0s infinitely to the left). */ - Blk getBlock(Index i) const { return i >= len ? 0 : blk[i]; } - /* Sets the requested block. The number grows or shrinks as necessary. */ - void setBlock(Index i, Blk newBlock); - - // The number is zero if and only if the canonical length is zero. - bool isZero() const { return NumberlikeArray::isEmpty(); } - - /* Returns the length of the number in bits, i.e., zero if the number - * is zero and otherwise one more than the largest value of bi for - * which getBit(bi) returns true. */ - Index bitLength() const; - /* Get the state of bit bi, which has value 2^bi. Bits beyond the - * number's length are considered to be 0. */ - bool getBit(Index bi) const { - return (getBlock(bi / N) & (Blk(1) << (bi % N))) != 0; - } - /* Sets the state of bit bi to newBit. The number grows or shrinks as - * necessary. */ - void setBit(Index bi, bool newBit); - - // COMPARISONS - - // Compares this to x like Perl's <=> - CmpRes compareTo(const BigUnsigned &x) const; - - // Ordinary comparison operators - bool operator ==(const BigUnsigned &x) const { - return NumberlikeArray::operator ==(x); - } - bool operator !=(const BigUnsigned &x) const { - return NumberlikeArray::operator !=(x); - } - bool operator < (const BigUnsigned &x) const { return compareTo(x) == less ; } - bool operator <=(const BigUnsigned &x) const { return compareTo(x) != greater; } - bool operator >=(const BigUnsigned &x) const { return compareTo(x) != less ; } - bool operator > (const BigUnsigned &x) const { return compareTo(x) == greater; } - - /* - * BigUnsigned and BigInteger both provide three kinds of operators. - * Here ``big-integer'' refers to BigInteger or BigUnsigned. - * - * (1) Overloaded ``return-by-value'' operators: - * +, -, *, /, %, unary -, &, |, ^, <<, >>. - * Big-integer code using these operators looks identical to code using - * the primitive integer types. These operators take one or two - * big-integer inputs and return a big-integer result, which can then - * be assigned to a BigInteger variable or used in an expression. - * Example: - * BigInteger a(1), b = 1; - * BigInteger c = a + b; - * - * (2) Overloaded assignment operators: - * +=, -=, *=, /=, %=, flipSign, &=, |=, ^=, <<=, >>=, ++, --. - * Again, these are used on big integers just like on ints. They take - * one writable big integer that both provides an operand and receives a - * result. Most also take a second read-only operand. - * Example: - * BigInteger a(1), b(1); - * a += b; - * - * (3) Copy-less operations: `add', `subtract', etc. - * These named methods take operands as arguments and store the result - * in the receiver (*this), avoiding unnecessary copies and allocations. - * `divideWithRemainder' is special: it both takes the dividend from and - * stores the remainder into the receiver, and it takes a separate - * object in which to store the quotient. NOTE: If you are wondering - * why these don't return a value, you probably mean to use the - * overloaded return-by-value operators instead. - * - * Examples: - * BigInteger a(43), b(7), c, d; - * - * c = a + b; // Now c == 50. - * c.add(a, b); // Same effect but without the two copies. - * - * c.divideWithRemainder(b, d); - * // 50 / 7; now d == 7 (quotient) and c == 1 (remainder). - * - * // ``Aliased'' calls now do the right thing using a temporary - * // copy, but see note on `divideWithRemainder'. - * a.add(a, b); - */ - - // COPY-LESS OPERATIONS - - // These 8: Arguments are read-only operands, result is saved in *this. - void add(const BigUnsigned &a, const BigUnsigned &b); - void subtract(const BigUnsigned &a, const BigUnsigned &b); - void multiply(const BigUnsigned &a, const BigUnsigned &b); - void bitAnd(const BigUnsigned &a, const BigUnsigned &b); - void bitOr(const BigUnsigned &a, const BigUnsigned &b); - void bitXor(const BigUnsigned &a, const BigUnsigned &b); - /* Negative shift amounts translate to opposite-direction shifts, - * except for -2^(8*sizeof(int)-1) which is unimplemented. */ - void bitShiftLeft(const BigUnsigned &a, int b); - void bitShiftRight(const BigUnsigned &a, int b); - - /* `a.divideWithRemainder(b, q)' is like `q = a / b, a %= b'. - * / and % use semantics similar to Knuth's, which differ from the - * primitive integer semantics under division by zero. See the - * implementation in BigUnsigned.cc for details. - * `a.divideWithRemainder(b, a)' throws an exception: it doesn't make - * sense to write quotient and remainder into the same variable. */ - void divideWithRemainder(const BigUnsigned &b, BigUnsigned &q); - - /* `divide' and `modulo' are no longer offered. Use - * `divideWithRemainder' instead. */ - - // OVERLOADED RETURN-BY-VALUE OPERATORS - BigUnsigned operator +(const BigUnsigned &x) const; - BigUnsigned operator -(const BigUnsigned &x) const; - BigUnsigned operator *(const BigUnsigned &x) const; - BigUnsigned operator /(const BigUnsigned &x) const; - BigUnsigned operator %(const BigUnsigned &x) const; - /* OK, maybe unary minus could succeed in one case, but it really - * shouldn't be used, so it isn't provided. */ - BigUnsigned operator &(const BigUnsigned &x) const; - BigUnsigned operator |(const BigUnsigned &x) const; - BigUnsigned operator ^(const BigUnsigned &x) const; - BigUnsigned operator <<(int b) const; - BigUnsigned operator >>(int b) const; - - // OVERLOADED ASSIGNMENT OPERATORS - void operator +=(const BigUnsigned &x); - void operator -=(const BigUnsigned &x); - void operator *=(const BigUnsigned &x); - void operator /=(const BigUnsigned &x); - void operator %=(const BigUnsigned &x); - void operator &=(const BigUnsigned &x); - void operator |=(const BigUnsigned &x); - void operator ^=(const BigUnsigned &x); - void operator <<=(int b); - void operator >>=(int b); - - /* INCREMENT/DECREMENT OPERATORS - * To discourage messy coding, these do not return *this, so prefix - * and postfix behave the same. */ - void operator ++( ); - void operator ++(int); - void operator --( ); - void operator --(int); - - // Helper function that needs access to BigUnsigned internals - friend Blk getShiftedBlock(const BigUnsigned &num, Index x, - unsigned int y); - - // See BigInteger.cc. - template - friend X convertBigUnsignedToPrimitiveAccess(const BigUnsigned &a); -}; - -/* Implementing the return-by-value and assignment operators in terms of the - * copy-less operations. The copy-less operations are responsible for making - * any necessary temporary copies to work around aliasing. */ - -inline BigUnsigned BigUnsigned::operator +(const BigUnsigned &x) const { - BigUnsigned ans; - ans.add(*this, x); - return ans; -} -inline BigUnsigned BigUnsigned::operator -(const BigUnsigned &x) const { - BigUnsigned ans; - ans.subtract(*this, x); - return ans; -} -inline BigUnsigned BigUnsigned::operator *(const BigUnsigned &x) const { - BigUnsigned ans; - ans.multiply(*this, x); - return ans; -} -inline BigUnsigned BigUnsigned::operator /(const BigUnsigned &x) const { - if (x.isZero()) throw "BigUnsigned::operator /: division by zero"; - BigUnsigned q, r; - r = *this; - r.divideWithRemainder(x, q); - return q; -} -inline BigUnsigned BigUnsigned::operator %(const BigUnsigned &x) const { - if (x.isZero()) throw "BigUnsigned::operator %: division by zero"; - BigUnsigned q, r; - r = *this; - r.divideWithRemainder(x, q); - return r; -} -inline BigUnsigned BigUnsigned::operator &(const BigUnsigned &x) const { - BigUnsigned ans; - ans.bitAnd(*this, x); - return ans; -} -inline BigUnsigned BigUnsigned::operator |(const BigUnsigned &x) const { - BigUnsigned ans; - ans.bitOr(*this, x); - return ans; -} -inline BigUnsigned BigUnsigned::operator ^(const BigUnsigned &x) const { - BigUnsigned ans; - ans.bitXor(*this, x); - return ans; -} -inline BigUnsigned BigUnsigned::operator <<(int b) const { - BigUnsigned ans; - ans.bitShiftLeft(*this, b); - return ans; -} -inline BigUnsigned BigUnsigned::operator >>(int b) const { - BigUnsigned ans; - ans.bitShiftRight(*this, b); - return ans; -} - -inline void BigUnsigned::operator +=(const BigUnsigned &x) { - add(*this, x); -} -inline void BigUnsigned::operator -=(const BigUnsigned &x) { - subtract(*this, x); -} -inline void BigUnsigned::operator *=(const BigUnsigned &x) { - multiply(*this, x); -} -inline void BigUnsigned::operator /=(const BigUnsigned &x) { - if (x.isZero()) throw "BigUnsigned::operator /=: division by zero"; - /* The following technique is slightly faster than copying *this first - * when x is large. */ - BigUnsigned q; - divideWithRemainder(x, q); - // *this contains the remainder, but we overwrite it with the quotient. - *this = q; -} -inline void BigUnsigned::operator %=(const BigUnsigned &x) { - if (x.isZero()) throw "BigUnsigned::operator %=: division by zero"; - BigUnsigned q; - // Mods *this by x. Don't care about quotient left in q. - divideWithRemainder(x, q); -} -inline void BigUnsigned::operator &=(const BigUnsigned &x) { - bitAnd(*this, x); -} -inline void BigUnsigned::operator |=(const BigUnsigned &x) { - bitOr(*this, x); -} -inline void BigUnsigned::operator ^=(const BigUnsigned &x) { - bitXor(*this, x); -} -inline void BigUnsigned::operator <<=(int b) { - bitShiftLeft(*this, b); -} -inline void BigUnsigned::operator >>=(int b) { - bitShiftRight(*this, b); -} - -/* Templates for conversions of BigUnsigned to and from primitive integers. - * BigInteger.cc needs to instantiate convertToPrimitive, and the uses in - * BigUnsigned.cc didn't do the trick; I think g++ inlined convertToPrimitive - * instead of generating linkable instantiations. So for consistency, I put - * all the templates here. */ - -// CONSTRUCTION FROM PRIMITIVE INTEGERS - -/* Initialize this BigUnsigned from the given primitive integer. The same - * pattern works for all primitive integer types, so I put it into a template to - * reduce code duplication. (Don't worry: this is protected and we instantiate - * it only with primitive integer types.) Type X could be signed, but x is - * known to be nonnegative. */ -template -void BigUnsigned::initFromPrimitive(X x) { - if (x == 0) - ; // NumberlikeArray already initialized us to zero. - else { - // Create a single block. blk is NULL; no need to delete it. - cap = 1; - blk = new Blk[1]; - len = 1; - blk[0] = Blk(x); - } -} - -/* Ditto, but first check that x is nonnegative. I could have put the check in - * initFromPrimitive and let the compiler optimize it out for unsigned-type - * instantiations, but I wanted to avoid the warning stupidly issued by g++ for - * a condition that is constant in *any* instantiation, even if not in all. */ -template -void BigUnsigned::initFromSignedPrimitive(X x) { - if (x < 0) - throw "BigUnsigned constructor: " - "Cannot construct a BigUnsigned from a negative number"; - else - initFromPrimitive(x); -} - -// CONVERSION TO PRIMITIVE INTEGERS - -/* Template with the same idea as initFromPrimitive. This might be slightly - * slower than the previous version with the masks, but it's much shorter and - * clearer, which is the library's stated goal. */ -template -X BigUnsigned::convertToPrimitive() const { - if (len == 0) - // The number is zero; return zero. - return 0; - else if (len == 1) { - // The single block might fit in an X. Try the conversion. - X x = X(blk[0]); - // Make sure the result accurately represents the block. - if (Blk(x) == blk[0]) - // Successful conversion. - return x; - // Otherwise fall through. - } - throw "BigUnsigned::to: " - "Value is too big to fit in the requested type"; -} - -/* Wrap the above in an x >= 0 test to make sure we got a nonnegative result, - * not a negative one that happened to convert back into the correct nonnegative - * one. (E.g., catch incorrect conversion of 2^31 to the long -2^31.) Again, - * separated to avoid a g++ warning. */ -template -X BigUnsigned::convertToSignedPrimitive() const { - X x = convertToPrimitive(); - if (x >= 0) - return x; - else - throw "BigUnsigned::to(Primitive): " - "Value is too big to fit in the requested type"; -} - -#endif diff --git a/yosys/libs/bigint/BigUnsignedInABase.cc b/yosys/libs/bigint/BigUnsignedInABase.cc deleted file mode 100644 index 999faaf2d..000000000 --- a/yosys/libs/bigint/BigUnsignedInABase.cc +++ /dev/null @@ -1,125 +0,0 @@ -#include "BigUnsignedInABase.hh" - -BigUnsignedInABase::BigUnsignedInABase(const Digit *d, Index l, Base base) - : NumberlikeArray(d, l), base(base) { - // Check the base - if (base < 2) - throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): The base must be at least 2"; - - // Validate the digits. - for (Index i = 0; i < l; i++) - if (blk[i] >= base) - throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): A digit is too large for the specified base"; - - // Eliminate any leading zeros we may have been passed. - zapLeadingZeros(); -} - -namespace { - unsigned int bitLen(unsigned int x) { - unsigned int len = 0; - while (x > 0) { - x >>= 1; - len++; - } - return len; - } - unsigned int ceilingDiv(unsigned int a, unsigned int b) { - return (a + b - 1) / b; - } -} - -BigUnsignedInABase::BigUnsignedInABase(const BigUnsigned &x, Base base) { - // Check the base - if (base < 2) - throw "BigUnsignedInABase(BigUnsigned, Base): The base must be at least 2"; - this->base = base; - - // Get an upper bound on how much space we need - int maxBitLenOfX = x.getLength() * BigUnsigned::N; - int minBitsPerDigit = bitLen(base) - 1; - int maxDigitLenOfX = ceilingDiv(maxBitLenOfX, minBitsPerDigit); - len = maxDigitLenOfX; // Another change to comply with `staying in bounds'. - allocate(len); // Get the space - - BigUnsigned x2(x), buBase(base); - Index digitNum = 0; - - while (!x2.isZero()) { - // Get last digit. This is like `lastDigit = x2 % buBase, x2 /= buBase'. - BigUnsigned lastDigit(x2); - lastDigit.divideWithRemainder(buBase, x2); - // Save the digit. - blk[digitNum] = lastDigit.toUnsignedShort(); - // Move on. We can't run out of room: we figured it out above. - digitNum++; - } - - // Save the actual length. - len = digitNum; -} - -BigUnsignedInABase::operator BigUnsigned() const { - BigUnsigned ans(0), buBase(base), temp; - Index digitNum = len; - while (digitNum > 0) { - digitNum--; - temp.multiply(ans, buBase); - ans.add(temp, BigUnsigned(blk[digitNum])); - } - return ans; -} - -BigUnsignedInABase::BigUnsignedInABase(const std::string &s, Base base) { - // Check the base. - if (base > 36) - throw "BigUnsignedInABase(std::string, Base): The default string conversion routines use the symbol set 0-9, A-Z and therefore support only up to base 36. You tried a conversion with a base over 36; write your own string conversion routine."; - // Save the base. - // This pattern is seldom seen in C++, but the analogous ``this.'' is common in Java. - this->base = base; - - // `s.length()' is a `size_t', while `len' is a `NumberlikeArray::Index', - // also known as an `unsigned int'. Some compilers warn without this cast. - len = Index(s.length()); - allocate(len); - - Index digitNum, symbolNumInString; - for (digitNum = 0; digitNum < len; digitNum++) { - symbolNumInString = len - 1 - digitNum; - char theSymbol = s[symbolNumInString]; - if (theSymbol >= '0' && theSymbol <= '9') - blk[digitNum] = theSymbol - '0'; - else if (theSymbol >= 'A' && theSymbol <= 'Z') - blk[digitNum] = theSymbol - 'A' + 10; - else if (theSymbol >= 'a' && theSymbol <= 'z') - blk[digitNum] = theSymbol - 'a' + 10; - else - throw "BigUnsignedInABase(std::string, Base): Bad symbol in input. Only 0-9, A-Z, a-z are accepted."; - - if (blk[digitNum] >= base) - throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): A digit is too large for the specified base"; - } - zapLeadingZeros(); -} - -BigUnsignedInABase::operator std::string() const { - if (base > 36) - throw "BigUnsignedInABase ==> std::string: The default string conversion routines use the symbol set 0-9, A-Z and therefore support only up to base 36. You tried a conversion with a base over 36; write your own string conversion routine."; - if (len == 0) - return std::string("0"); - // Some compilers don't have push_back, so use a char * buffer instead. - char *s = new char[len + 1]; - s[len] = '\0'; - Index digitNum, symbolNumInString; - for (symbolNumInString = 0; symbolNumInString < len; symbolNumInString++) { - digitNum = len - 1 - symbolNumInString; - Digit theDigit = blk[digitNum]; - if (theDigit < 10) - s[symbolNumInString] = char('0' + theDigit); - else - s[symbolNumInString] = char('A' + theDigit - 10); - } - std::string s2(s); - delete [] s; - return s2; -} diff --git a/yosys/libs/bigint/BigUnsignedInABase.hh b/yosys/libs/bigint/BigUnsignedInABase.hh deleted file mode 100644 index 0ea89c6ef..000000000 --- a/yosys/libs/bigint/BigUnsignedInABase.hh +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef BIGUNSIGNEDINABASE_H -#define BIGUNSIGNEDINABASE_H - -#include "NumberlikeArray.hh" -#include "BigUnsigned.hh" -#include - -/* - * A BigUnsignedInABase object represents a nonnegative integer of size limited - * only by available memory, represented in a user-specified base that can fit - * in an `unsigned short' (most can, and this saves memory). - * - * BigUnsignedInABase is intended as an intermediary class with little - * functionality of its own. BigUnsignedInABase objects can be constructed - * from, and converted to, BigUnsigneds (requiring multiplication, mods, etc.) - * and `std::string's (by switching digit values for appropriate characters). - * - * BigUnsignedInABase is similar to BigUnsigned. Note the following: - * - * (1) They represent the number in exactly the same way, except that - * BigUnsignedInABase uses ``digits'' (or Digit) where BigUnsigned uses - * ``blocks'' (or Blk). - * - * (2) Both use the management features of NumberlikeArray. (In fact, my desire - * to add a BigUnsignedInABase class without duplicating a lot of code led me to - * introduce NumberlikeArray.) - * - * (3) The only arithmetic operation supported by BigUnsignedInABase is an - * equality test. Use BigUnsigned for arithmetic. - */ - -class BigUnsignedInABase : protected NumberlikeArray { - -public: - // The digits of a BigUnsignedInABase are unsigned shorts. - typedef unsigned short Digit; - // That's also the type of a base. - typedef Digit Base; - -protected: - // The base in which this BigUnsignedInABase is expressed - Base base; - - // Creates a BigUnsignedInABase with a capacity; for internal use. - BigUnsignedInABase(int, Index c) : NumberlikeArray(0, c) {} - - // Decreases len to eliminate any leading zero digits. - void zapLeadingZeros() { - while (len > 0 && blk[len - 1] == 0) - len--; - } - -public: - // Constructs zero in base 2. - BigUnsignedInABase() : NumberlikeArray(), base(2) {} - - // Copy constructor - BigUnsignedInABase(const BigUnsignedInABase &x) : NumberlikeArray(x), base(x.base) {} - - // Assignment operator - void operator =(const BigUnsignedInABase &x) { - NumberlikeArray::operator =(x); - base = x.base; - } - - // Constructor that copies from a given array of digits. - BigUnsignedInABase(const Digit *d, Index l, Base base); - - // Destructor. NumberlikeArray does the delete for us. - ~BigUnsignedInABase() {} - - // LINKS TO BIGUNSIGNED - BigUnsignedInABase(const BigUnsigned &x, Base base); - operator BigUnsigned() const; - - /* LINKS TO STRINGS - * - * These use the symbols ``0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'' to - * represent digits of 0 through 35. When parsing strings, lowercase is - * also accepted. - * - * All string representations are big-endian (big-place-value digits - * first). (Computer scientists have adopted zero-based counting; why - * can't they tolerate little-endian numbers?) - * - * No string representation has a ``base indicator'' like ``0x''. - * - * An exception is made for zero: it is converted to ``0'' and not the - * empty string. - * - * If you want different conventions, write your own routines to go - * between BigUnsignedInABase and strings. It's not hard. - */ - operator std::string() const; - BigUnsignedInABase(const std::string &s, Base base); - -public: - - // ACCESSORS - Base getBase() const { return base; } - - // Expose these from NumberlikeArray directly. - using NumberlikeArray::getCapacity; - using NumberlikeArray::getLength; - - /* Returns the requested digit, or 0 if it is beyond the length (as if - * the number had 0s infinitely to the left). */ - Digit getDigit(Index i) const { return i >= len ? 0 : blk[i]; } - - // The number is zero if and only if the canonical length is zero. - bool isZero() const { return NumberlikeArray::isEmpty(); } - - /* Equality test. For the purposes of this test, two BigUnsignedInABase - * values must have the same base to be equal. */ - bool operator ==(const BigUnsignedInABase &x) const { - return base == x.base && NumberlikeArray::operator ==(x); - } - bool operator !=(const BigUnsignedInABase &x) const { return !operator ==(x); } - -}; - -#endif diff --git a/yosys/libs/bigint/ChangeLog b/yosys/libs/bigint/ChangeLog deleted file mode 100644 index ac6927c40..000000000 --- a/yosys/libs/bigint/ChangeLog +++ /dev/null @@ -1,146 +0,0 @@ - Change Log - -These entries tell you what was added, fixed, or improved in each version as -compared to the previous one. In case you haven't noticed, a version number -roughly corresponds to the release date of that version in `YYYY.MM.DD[.N]' -format, where `.N' goes `.2', `.3', etc. if there are multiple versions on the -same day. The topmost version listed is the one you have. - -2010.04.30 ----------- -- Strengthen the advice about build/IDE configuration in the README. - -2009.05.03 ----------- -- BigUnsigned::{get,set}Bit: Change two remaining `1 <<' to `Blk(1) <<' to work - on systems where sizeof(unsigned int) != sizeof(Blk). Bug reported by Brad - Spencer. -- dataToBigInteger: Change a `delete' to `delete []' to avoid leaking memory. - Bug reported by Nicolás Carrasco. - -2009.03.26 ----------- -- BigUnsignedInABase(std::string) Reject digits too big for the base. - Bug reported by Niakam Kazemi. - -2008.07.20 ----------- -Dennis Yew pointed out serious problems with ambiguities and unwanted -conversions when mixing BigInteger/BigUnsigned and primitive integers. To fix -these, I removed the implicit conversions from BigInteger/BigUnsigned to -primitive integers and from BigInteger to BigUnsigned. Removing the -BigInteger-to-BigUnsigned conversion required changing BigInteger to have a -BigUnsigned field instead of inheriting from it; this was a complex task but -ultimately gave a saner design. At the same time, I went through the entire -codebase, making the formatting and comments prettier and reworking anything I -thought was unclear. I also added a testsuite (currently for 32-bit systems -only); it doesn't yet cover the entire library but should help to ensure that -things work the way they should. - -A number of changes from version 2007.07.07 break compatibility with existing -code that uses the library, but updating that code should be pretty easy: -- BigInteger can no longer be implicitly converted to BigUnsigned. Use - getMagnitude() instead. -- BigUnsigned and BigInteger can no longer be implicitly converted to primitive - integers. Use the toInt() family of functions instead. -- The easy* functions have been renamed to more mature names: - bigUnsignedToString, bigIntegerToString, stringToBigUnsigned, - stringToBigInteger, dataToBigInteger. -- BigInteger no longer supports bitwise operations. Get the magnitude with - getMagnitude() and operate on that instead. -- The old {BigUnsigned,BigInteger}::{divide,modulo} copy-less options have been - removed. Use divideWithRemainder instead. -- Added a base argument to BigUnsignedInABase's digit-array constructor. I - ope no one used that constructor in its broken state anyway. - -Other notable changes: -- Added BigUnsigned functions setBlock, bitLength, getBit, setBit. -- The bit-shifting operations now support negative shift amounts, which shift in - the other direction. -- Added some big-integer algorithms in BigIntegerAlgorithms.hh: gcd, - extendedEuclidean, modinv, modexp. - -2007.07.07 ----------- -Update the "Running the sample program produces this output:" comment in -sample.cc for the bitwise operators. - -2007.06.14 ----------- -- Implement << and >> for BigUnsigned in response to email from Marco Schulze. -- Fix name: DOTR_ALIASED -> DTRT_ALIASED. -- Demonstrate all bitwise operators (&, |, ^, <<, >>) in sample.cc. - -2007.02.16 ----------- -Boris Dessy pointed out that the library threw an exception on "a *= a", so I changed all the put-here operations to handle aliased calls correctly using a temporary copy instead of throwing exceptions. - -2006.08.14 ----------- -In BigUnsigned::bitXor, change allocate(b2->len) to allocate(a2->len): we should allocate enough space for the longer number, not the shorter one! Thanks to Sriram Sankararaman for pointing this out. - -2006.05.03 ----------- -I ran the sample program using valgrind and discovered a `delete s' that should be `delete [] s' and a `len++' before an `allocateAndCopy(len)' that should have been after an `allocateAndCopy(len + 1)'. I fixed both. Yay for valgrind! - -2006.05.01 ----------- -I fixed incorrect results reported by Mohand Mezmaz and related memory corruption on platforms where Blk is bigger than int. I replaced (1 << x) with (Blk(1) << x) in two places in BigUnsigned.cc. - -2006.04.24 ----------- -Two bug fixes: BigUnsigned "++x" no longer segfaults when x grows in length, and BigUnsigned == and != are now redeclared so as to be usable. I redid the Makefile: I removed the *.tag mechanism and hard-coded the library's header dependencies, I added comments, and I made the Makefile more useful for building one's own programs instead of just the sample. - -2006.02.26 ----------- -A few tweaks in preparation for a group to distribute the library. The project Web site has moved; I updated the references. I fixed a typo and added a missing function in NumberlikeArray.hh. I'm using Eclipse now, so you get Eclipse project files. - -2005.03.30 ----------- -Sam Larkin found a bug in `BigInteger::subtract'; I fixed it. - -2005.01.18 ----------- -I fixed some problems with `easyDataToBI'. Due to some multiply declared variables, this function would not compile. However, it is a template function, so the compiler parses it and doesn't compile the parsed representation until something uses the function; this is how I missed the problems. I also removed debugging output from this function. - -2005.01.17 ----------- -A fix to some out-of-bounds accesses reported by Milan Tomic (see the comment under `BigUnsigned::divideWithRemainder'). `BigUnsigned::multiply' and `BigUnsigned::divideWithRemainder' implementations neatened up a bit with the help of a function `getShiftedBlock'. I (finally!) introduced a constant `BigUnsigned::N', the number of bits in a `BigUnsigned::Blk', which varies depending on machine word size. In both code and comments, it replaces the much clunkier `8*sizeof(Blk)'. Numerous other small changes. There's a new conversion routine `easyDataToBI' that will convert almost any format of binary data to a `BigInteger'. - -I have inserted a significant number of new comments. Most explain unobvious aspects of the code. - -2005.01.06 ----------- -Some changes to the way zero-length arrays are handled by `NumberlikeArray', which fixed a memory leak reported by Milan Tomic. - -2004.12.24.2 ------------- -I tied down a couple of loose ends involving division/modulo. I added an explanation of put-here vs. overloaded operators in the sample program; this has confused too many people. Miscellaneous other improvements. - -I believe that, at this point, the Big Integer Library makes no assumptions about the word size of the machine it is using. `BigUnsigned::Blk' is always an `unsigned long', whatever that may be, and its size is computed with `sizeof' when necessary. However, just in case, I would be interested to have someone test the library on a non-32-bit machine to see if it works. - -2004.12.24 ----------- -This is a _major_ upgrade to the library. Among the things that have changed: - -I wrote the original version of the library, particularly the four ``classical algorithms'' in `BigUnsigned.cc', using array indexing. Then I rewrote it to use pointers because I thought that would be faster. But recently, I revisited the code in `BigUnsigned.cc' and found that I could not begin to understand what it was doing. - -I have decided that the drawbacks of pointers, increased coding difficulty and reduced code readability, far outweigh their speed benefits. Plus, any modern optimizing compiler should produce fast code either way. Therefore, I rewrote the library to use array indexing again. (Thank goodness for regular-expression find-and-replace. It saved me a lot of time.) - -The put-here operations `divide' and `modulo' of each of `BigUnsigned' and `BigInteger' have been supplanted by a single operation `divideWithRemainder'. Read the profuse comments for more information on its exact behavior. - -There is a new class `BigUnsignedInABase' that is like `BigUnsigned' but uses a user-specified, small base instead of `256 ^ sizeof(unsigned long)'. Much of the code common to the two has been factored out into `NumberlikeArray'. - -`BigUnsignedInABase' facilitates conversion between `BigUnsigned's and digit-by-digit string representations using `std::string'. Convenience routines to do this conversion are in `BigIntegerUtils.hh'. `iostream' compatibility has been improved. - -I would like to thank Chris Morbitzer for the e-mail message that catalyzed this major upgrade. He wanted a way to convert a string to a BigInteger. One thing just led to another, roughly in reverse order from how they are listed here. - -2004.1216 ---------- -Brad Spencer pointed out a memory leak in `BigUnsigned::divide'. It is fixed in the December 16, 2004 version. - -2004.1205 ---------- -After months of inactivity, I fixed a bug in the `BigInteger' division routine; thanks to David Allen for reporting the bug. I also added simple routines for decimal output to `std::ostream's, and there is a demo that prints out powers of 3. - -~~~~ diff --git a/yosys/libs/bigint/Makefile b/yosys/libs/bigint/Makefile deleted file mode 100644 index 3018e98e6..000000000 --- a/yosys/libs/bigint/Makefile +++ /dev/null @@ -1,73 +0,0 @@ -# Mention default target. -all: - -# Implicit rule to compile C++ files. Modify to your taste. -%.o: %.cc - g++ -c -O2 -Wall -Wextra -pedantic $< - -# Components of the library. -library-objects = \ - BigUnsigned.o \ - BigInteger.o \ - BigIntegerAlgorithms.o \ - BigUnsignedInABase.o \ - BigIntegerUtils.o \ - -library-headers = \ - NumberlikeArray.hh \ - BigUnsigned.hh \ - BigInteger.hh \ - BigIntegerAlgorithms.hh \ - BigUnsignedInABase.hh \ - BigIntegerLibrary.hh \ - -# To ``make the library'', make all its objects using the implicit rule. -library: $(library-objects) - -# Conservatively assume that all the objects depend on all the headers. -$(library-objects): $(library-headers) - -# TESTSUITE (NOTE: Currently expects a 32-bit system) -# Compiling the testsuite. -testsuite.o: $(library-headers) -testsuite: testsuite.o $(library-objects) - g++ $^ -o $@ -# Extract the expected output from the testsuite source. -testsuite.expected: testsuite.cc - nl -ba -p -s: $< | sed -nre 's,^ +([0-9]+):.*//([^ ]),Line \1: \2,p' >$@ -# Run the testsuite. -.PHONY: test -test: testsuite testsuite.expected - ./run-testsuite -testsuite-cleanfiles = \ - testsuite.o testsuite testsuite.expected \ - testsuite.out testsuite.err - -# The rules below build a program that uses the library. They are preset to -# build ``sample'' from ``sample.cc''. You can change the name(s) of the -# source file(s) and program file to build your own program, or you can write -# your own Makefile. - -# Components of the program. -program = sample -program-objects = sample.o - -# Conservatively assume all the program source files depend on all the library -# headers. You can change this if it is not the case. -$(program-objects) : $(library-headers) - -# How to link the program. The implicit rule covers individual objects. -$(program) : $(program-objects) $(library-objects) - g++ $^ -o $@ - -# Delete all generated files we know about. -clean : - rm -f $(library-objects) $(testsuite-cleanfiles) $(program-objects) $(program) - -# I removed the *.tag dependency tracking system because it had few advantages -# over manually entering all the dependencies. If there were a portable, -# reliable dependency tracking system, I'd use it, but I know of no such; -# cons and depcomp are almost good enough. - -# Come back and define default target. -all : library $(program) diff --git a/yosys/libs/bigint/NumberlikeArray.hh b/yosys/libs/bigint/NumberlikeArray.hh deleted file mode 100644 index 53c8e5be8..000000000 --- a/yosys/libs/bigint/NumberlikeArray.hh +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef NUMBERLIKEARRAY_H -#define NUMBERLIKEARRAY_H - -// Make sure we have NULL. -#ifndef NULL -#define NULL 0 -#endif - -/* A NumberlikeArray object holds a heap-allocated array of Blk with a - * length and a capacity and provides basic memory management features. - * BigUnsigned and BigUnsignedInABase both subclass it. - * - * NumberlikeArray provides no information hiding. Subclasses should use - * nonpublic inheritance and manually expose members as desired using - * declarations like this: - * - * public: - * NumberlikeArray< the-type-argument >::getLength; - */ -template -class NumberlikeArray { -public: - - // Type for the index of a block in the array - typedef unsigned int Index; - // The number of bits in a block, defined below. - static const unsigned int N; - - // The current allocated capacity of this NumberlikeArray (in blocks) - Index cap; - // The actual length of the value stored in this NumberlikeArray (in blocks) - Index len; - // Heap-allocated array of the blocks (can be NULL if len == 0) - Blk *blk; - - // Constructs a ``zero'' NumberlikeArray with the given capacity. - NumberlikeArray(Index c) : cap(c), len(0) { - blk = (cap > 0) ? (new Blk[cap]) : NULL; - } - - /* Constructs a zero NumberlikeArray without allocating a backing array. - * A subclass that doesn't know the needed capacity at initialization - * time can use this constructor and then overwrite blk without first - * deleting it. */ - NumberlikeArray() : cap(0), len(0) { - blk = NULL; - } - - // Destructor. Note that `delete NULL' is a no-op. - ~NumberlikeArray() { - delete [] blk; - } - - /* Ensures that the array has at least the requested capacity; may - * destroy the contents. */ - void allocate(Index c); - - /* Ensures that the array has at least the requested capacity; does not - * destroy the contents. */ - void allocateAndCopy(Index c); - - // Copy constructor - NumberlikeArray(const NumberlikeArray &x); - - // Assignment operator - void operator=(const NumberlikeArray &x); - - // Constructor that copies from a given array of blocks - NumberlikeArray(const Blk *b, Index blen); - - // ACCESSORS - Index getCapacity() const { return cap; } - Index getLength() const { return len; } - Blk getBlock(Index i) const { return blk[i]; } - bool isEmpty() const { return len == 0; } - - /* Equality comparison: checks if both objects have the same length and - * equal (==) array elements to that length. Subclasses may wish to - * override. */ - bool operator ==(const NumberlikeArray &x) const; - - bool operator !=(const NumberlikeArray &x) const { - return !operator ==(x); - } -}; - -/* BEGIN TEMPLATE DEFINITIONS. They are present here so that source files that - * include this header file can generate the necessary real definitions. */ - -template -const unsigned int NumberlikeArray::N = 8 * sizeof(Blk); - -template -void NumberlikeArray::allocate(Index c) { - // If the requested capacity is more than the current capacity... - if (c > cap) { - // Delete the old number array - delete [] blk; - // Allocate the new array - cap = c; - blk = new Blk[cap]; - } -} - -template -void NumberlikeArray::allocateAndCopy(Index c) { - // If the requested capacity is more than the current capacity... - if (c > cap) { - Blk *oldBlk = blk; - // Allocate the new number array - cap = c; - blk = new Blk[cap]; - // Copy number blocks - Index i; - for (i = 0; i < len; i++) - blk[i] = oldBlk[i]; - // Delete the old array - delete [] oldBlk; - } -} - -template -NumberlikeArray::NumberlikeArray(const NumberlikeArray &x) - : len(x.len) { - // Create array - cap = len; - blk = new Blk[cap]; - // Copy blocks - Index i; - for (i = 0; i < len; i++) - blk[i] = x.blk[i]; -} - -template -void NumberlikeArray::operator=(const NumberlikeArray &x) { - /* Calls like a = a have no effect; catch them before the aliasing - * causes a problem */ - if (this == &x) - return; - // Copy length - len = x.len; - // Expand array if necessary - allocate(len); - // Copy number blocks - Index i; - for (i = 0; i < len; i++) - blk[i] = x.blk[i]; -} - -template -NumberlikeArray::NumberlikeArray(const Blk *b, Index blen) - : cap(blen), len(blen) { - // Create array - blk = new Blk[cap]; - // Copy blocks - Index i; - for (i = 0; i < len; i++) - blk[i] = b[i]; -} - -template -bool NumberlikeArray::operator ==(const NumberlikeArray &x) const { - if (len != x.len) - // Definitely unequal. - return false; - else { - // Compare corresponding blocks one by one. - Index i; - for (i = 0; i < len; i++) - if (blk[i] != x.blk[i]) - return false; - // No blocks differed, so the objects are equal. - return true; - } -} - -#endif diff --git a/yosys/libs/bigint/README b/yosys/libs/bigint/README deleted file mode 100644 index e1842381e..000000000 --- a/yosys/libs/bigint/README +++ /dev/null @@ -1,81 +0,0 @@ - -Note by Clifford Wolf: -This version of bigint was downloaded at 2012-08-29 from -https://mattmccutchen.net/bigint/bigint-2010.04.30.tar.bz2 - -Some minor changes were made to the source code (e.g. "using" -was added to access declarations to prohibit compiler warnings). - - -============================================================================== - - C++ Big Integer Library - (see ChangeLog for version) - - http://mattmccutchen.net/bigint/ - - Written and maintained by Matt McCutchen - -You can use this library in a C++ program to do arithmetic on integers of size -limited only by your computer's memory. The library provides BigUnsigned and -BigInteger classes that represent nonnegative integers and signed integers, -respectively. Most of the C++ arithmetic operators are overloaded for these -classes, so big-integer calculations are as easy as: - - #include "BigIntegerLibrary.hh" - - BigInteger a = 65536; - cout << (a * a * a * a * a * a * a * a); - - (prints 340282366920938463463374607431768211456) - -The code in `sample.cc' demonstrates the most important features of the library. -To get started quickly, read the code and explanations in that file and run it. -If you want more detail or a feature not shown in `sample.cc', consult the -consult the actual header and source files, which are thoroughly commented. - -This library emphasizes ease of use and clarity of implementation over speed; -some users will prefer GMP (http://swox.com/gmp/), which is faster. The code is -intended to be reasonably portable across computers and modern C++ compilers; in -particular, it uses whatever word size the computer provides (32-bit, 64-bit, or -otherwise). - -Compiling programs that use the library ---------------------------------------- -The library consists of a folder full of C++ header files (`.hh') and source -files (`.cc'). Your own programs should `#include' the necessary header files -and link with the source files. A makefile that builds the sample program -(`sample.cc') is included; you can adapt it to replace the sample with your own -program. - -Alternatively, you can use your own build system or IDE. In that case, you must -put the library header files where the compiler will find them and arrange to -have your program linked with the library source files; otherwise, you will get -errors about missing header files or "undefined references". To learn how to do -this, consult the documentation for the build system or IDE; don't bother asking -me. Adding all the library files to your project will work in many IDEs but may -not be the most desirable approach. - -Resources ---------- -The library's Web site (above) provides links to released versions, the current -development version, and a mailing list for release announcements, questions, -bug reports, and other discussion of the library. I would be delighted to hear -from you if you like this library and/or find a good use for it. - -Bugs and enhancements ---------------------- -The library has been tested by me and others but is by no means bug-free. If -you find a bug, please report it, whether it comes in the form of compiling -trouble, a mathematically inaccurate result, or a memory-management blooper -(since I use Java, these are altogether too common in my C++). I generally fix -all reported bugs. You are also welcome to request enhancements, but I am -unlikely to do substantial amounts of work on enhancements at this point. - -Legal ------ -I, Matt McCutchen, the sole author of the original Big Integer Library, waive my -copyright to it, placing it in the public domain. The library comes with -absolutely no warranty. - -~~~~ diff --git a/yosys/libs/bigint/run-testsuite b/yosys/libs/bigint/run-testsuite deleted file mode 100755 index ff7372916..000000000 --- a/yosys/libs/bigint/run-testsuite +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -bad= - -# If you encounter the following problem with Valgrind like I did: -# https://bugzilla.redhat.com/show_bug.cgi?id=455644 -# you can pass the environment variable NO_VALGRIND=1 to run the testsuite -# without it. -if [ "$NO_VALGRIND" ]; then - cmd=(./testsuite) -else - cmd=(valgrind --error-exitcode=1 --leak-check=full ./testsuite) -fi - -set -o pipefail -# Stdout goes directly to testsuite.out; stderr goes down the pipe. -if ! "${cmd[@]}" 2>&1 >testsuite.out | tee testsuite.err; then - echo >&2 'Memory errors!' - bad=1 -fi - -if grep 'LEAK SUMMARY' testsuite.err >/dev/null; then - echo >&2 'Memory leaks!' - bad=1 -fi - -if ! diff -u testsuite.expected testsuite.out; then - echo >&2 'Output is incorrect!' - bad=1 -fi - -if [ $bad ]; then - echo >&2 'Test suite failed!' - exit 1 -else - echo 'Test suite passed.' -fi diff --git a/yosys/libs/bigint/sample.cc b/yosys/libs/bigint/sample.cc deleted file mode 100644 index 62b41df32..000000000 --- a/yosys/libs/bigint/sample.cc +++ /dev/null @@ -1,125 +0,0 @@ -// Sample program demonstrating the use of the Big Integer Library. - -// Standard libraries -#include -#include - -// `BigIntegerLibrary.hh' includes all of the library headers. -#include "BigIntegerLibrary.hh" - -int main() { - /* The library throws `const char *' error messages when things go - * wrong. It's a good idea to catch them using a `try' block like this - * one. Your C++ compiler might need a command-line option to compile - * code that uses exceptions. */ - try { - BigInteger a; // a is 0 - int b = 535; - - /* Any primitive integer can be converted implicitly to a - * BigInteger. */ - a = b; - - /* The reverse conversion requires a method call (implicit - * conversions were previously supported but caused trouble). - * If a were too big for an int, the library would throw an - * exception. */ - b = a.toInt(); - - BigInteger c(a); // Copy a BigInteger. - - // The int literal is converted to a BigInteger. - BigInteger d(-314159265); - - /* This won't compile (at least on 32-bit machines) because the - * number is too big to be a primitive integer literal, and - * there's no such thing as a BigInteger literal. */ - //BigInteger e(3141592653589793238462643383279); - - // Instead you can convert the number from a string. - std::string s("3141592653589793238462643383279"); - BigInteger f = stringToBigInteger(s); - - // You can convert the other way too. - std::string s2 = bigIntegerToString(f); - - // f is implicitly stringified and sent to std::cout. - std::cout << f << std::endl; - - /* Let's do some math! The library overloads most of the - * mathematical operators (including assignment operators) to - * work on BigIntegers. There are also ``copy-less'' - * operations; see `BigUnsigned.hh' for details. */ - - // Arithmetic operators - BigInteger g(314159), h(265); - std::cout << (g + h) << '\n' - << (g - h) << '\n' - << (g * h) << '\n' - << (g / h) << '\n' - << (g % h) << std::endl; - - // Bitwise operators - BigUnsigned i(0xFF0000FF), j(0x0000FFFF); - // The library's << operator recognizes base flags. - std::cout.flags(std::ios::hex | std::ios::showbase); - std::cout << (i & j) << '\n' - << (i | j) << '\n' - << (i ^ j) << '\n' - // Shift distances are ordinary unsigned ints. - << (j << 21) << '\n' - << (j >> 10) << '\n'; - std::cout.flags(std::ios::dec); - - // Let's do some heavy lifting and calculate powers of 314. - int maxPower = 10; - BigUnsigned x(1), big314(314); - for (int power = 0; power <= maxPower; power++) { - std::cout << "314^" << power << " = " << x << std::endl; - x *= big314; // A BigInteger assignment operator - } - - // Some big-integer algorithms (albeit on small integers). - std::cout << gcd(BigUnsigned(60), 72) << '\n' - << modinv(BigUnsigned(7), 11) << '\n' - << modexp(BigUnsigned(314), 159, 2653) << std::endl; - - // Add your own code here to experiment with the library. - } catch(char const* err) { - std::cout << "The library threw an exception:\n" - << err << std::endl; - } - - return 0; -} - -/* -The original sample program produces this output: - -3141592653589793238462643383279 -314424 -313894 -83252135 -1185 -134 -0xFF -0xFF00FFFF -0xFF00FF00 -0x1FFFE00000 -0x3F -314^0 = 1 -314^1 = 314 -314^2 = 98596 -314^3 = 30959144 -314^4 = 9721171216 -314^5 = 3052447761824 -314^6 = 958468597212736 -314^7 = 300959139524799104 -314^8 = 94501169810786918656 -314^9 = 29673367320587092457984 -314^10 = 9317437338664347031806976 -12 -8 -1931 - -*/ diff --git a/yosys/libs/bigint/testsuite.cc b/yosys/libs/bigint/testsuite.cc deleted file mode 100644 index 7cb9768e6..000000000 --- a/yosys/libs/bigint/testsuite.cc +++ /dev/null @@ -1,326 +0,0 @@ -/* Test suite for the library. First, it ``tests'' that all the constructs it - * uses compile successfully. Then, its output to stdout is compared to the - * expected output automatically extracted from slash-slash comments below. - * - * NOTE: For now, the test suite expects a 32-bit system. On others, some tests - * may fail, and it may be ineffective at catching bugs. TODO: Remedy this. */ - -#include "BigIntegerLibrary.hh" - -#include -#include -using namespace std; - -// Evaluate expr and print the result or "error" as appropriate. -#define TEST(expr) do {\ - cout << "Line " << __LINE__ << ": ";\ - try {\ - cout << (expr);\ - } catch (const char *err) {\ - cout << "error";\ - }\ - cout << endl;\ -} while (0) - -const BigUnsigned &check(const BigUnsigned &x) { - unsigned int l = x.getLength(); - if (l != 0 && x.getBlock(l-1) == 0) - cout << "check: Unzapped number!" << endl; - if (l > x.getCapacity()) - cout << "check: Capacity inconsistent with length!" << endl; - return x; -} - -const BigInteger &check(const BigInteger &x) { - if (x.getSign() == 0 && !x.getMagnitude().isZero()) - cout << "check: Sign should not be zero!" << endl; - if (x.getSign() != 0 && x.getMagnitude().isZero()) - cout << "check: Sign should be zero!" << endl; - check(x.getMagnitude()); - return x; -} - -short pathologicalShort = ~((unsigned short)(~0) >> 1); -int pathologicalInt = ~((unsigned int)(~0) >> 1); -long pathologicalLong = ~((unsigned long)(~0) >> 1); - -int main() { - -try { - -BigUnsigned z(0), one(1), ten(10); -TEST(z); //0 -TEST(1); //1 -TEST(10); //10 - -// TODO: Comprehensively test the general and special cases of each function. - -// === Default constructors === - -TEST(check(BigUnsigned())); //0 -TEST(check(BigInteger())); //0 - -// === Block-array constructors === - -BigUnsigned::Blk myBlocks[3]; -myBlocks[0] = 3; -myBlocks[1] = 4; -myBlocks[2] = 0; -BigUnsigned bu(myBlocks, 3); -TEST(check(bu)); //17179869187 -TEST(check(BigInteger(myBlocks, 3))); //17179869187 -TEST(check(BigInteger(bu ))); //17179869187 - -// For nonzero magnitude, reject zero and invalid signs. -TEST(check(BigInteger(myBlocks, 3, BigInteger::positive))); //17179869187 -TEST(check(BigInteger(myBlocks, 3, BigInteger::negative))); //-17179869187 -TEST(check(BigInteger(myBlocks, 3, BigInteger::zero ))); //error -TEST(check(BigInteger(bu, BigInteger::positive))); //17179869187 -TEST(check(BigInteger(bu, BigInteger::negative))); //-17179869187 -TEST(check(BigInteger(bu, BigInteger::zero ))); //error - -// For zero magnitude, force the sign to zero without error. -BigUnsigned::Blk myZeroBlocks[1]; -myZeroBlocks[0] = 0; -TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::positive))); //0 -TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::negative))); //0 -TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::zero ))); //0 - -// === BigUnsigned conversion limits === - -TEST(BigUnsigned(0).toUnsignedLong()); //0 -TEST(BigUnsigned(4294967295U).toUnsignedLong()); //4294967295 -TEST(stringToBigUnsigned("4294967296").toUnsignedLong()); //error - -TEST(BigUnsigned(0).toLong()); //0 -TEST(BigUnsigned(2147483647).toLong()); //2147483647 -TEST(BigUnsigned(2147483648U).toLong()); //error - -// int is the same as long on a 32-bit system -TEST(BigUnsigned(0).toUnsignedInt()); //0 -TEST(BigUnsigned(4294967295U).toUnsignedInt()); //4294967295 -TEST(stringToBigUnsigned("4294967296").toUnsignedInt()); //error - -TEST(BigUnsigned(0).toInt()); //0 -TEST(BigUnsigned(2147483647).toInt()); //2147483647 -TEST(BigUnsigned(2147483648U).toInt()); //error - -TEST(BigUnsigned(0).toUnsignedShort()); //0 -TEST(BigUnsigned(65535).toUnsignedShort()); //65535 -TEST(BigUnsigned(65536).toUnsignedShort()); //error - -TEST(BigUnsigned(0).toShort()); //0 -TEST(BigUnsigned(32767).toShort()); //32767 -TEST(BigUnsigned(32768).toShort()); //error - -// === BigInteger conversion limits === - -TEST(BigInteger(-1).toUnsignedLong()); //error -TEST(BigInteger(0).toUnsignedLong()); //0 -TEST(BigInteger(4294967295U).toUnsignedLong()); //4294967295 -TEST(stringToBigInteger("4294967296").toUnsignedLong()); //error - -TEST(stringToBigInteger("-2147483649").toLong()); //error -TEST(stringToBigInteger("-2147483648").toLong()); //-2147483648 -TEST(BigInteger(-2147483647).toLong()); //-2147483647 -TEST(BigInteger(0).toLong()); //0 -TEST(BigInteger(2147483647).toLong()); //2147483647 -TEST(BigInteger(2147483648U).toLong()); //error - -// int is the same as long on a 32-bit system -TEST(BigInteger(-1).toUnsignedInt()); //error -TEST(BigInteger(0).toUnsignedInt()); //0 -TEST(BigInteger(4294967295U).toUnsignedInt()); //4294967295 -TEST(stringToBigInteger("4294967296").toUnsignedInt()); //error - -TEST(stringToBigInteger("-2147483649").toInt()); //error -TEST(stringToBigInteger("-2147483648").toInt()); //-2147483648 -TEST(BigInteger(-2147483647).toInt()); //-2147483647 -TEST(BigInteger(0).toInt()); //0 -TEST(BigInteger(2147483647).toInt()); //2147483647 -TEST(BigInteger(2147483648U).toInt()); //error - -TEST(BigInteger(-1).toUnsignedShort()); //error -TEST(BigInteger(0).toUnsignedShort()); //0 -TEST(BigInteger(65535).toUnsignedShort()); //65535 -TEST(BigInteger(65536).toUnsignedShort()); //error - -TEST(BigInteger(-32769).toShort()); //error -TEST(BigInteger(-32768).toShort()); //-32768 -TEST(BigInteger(-32767).toShort()); //-32767 -TEST(BigInteger(0).toShort()); //0 -TEST(BigInteger(32767).toShort()); //32767 -TEST(BigInteger(32768).toShort()); //error - -// === Negative BigUnsigneds === - -// ...during construction -TEST(BigUnsigned(short(-1))); //error -TEST(BigUnsigned(pathologicalShort)); //error -TEST(BigUnsigned(-1)); //error -TEST(BigUnsigned(pathologicalInt)); //error -TEST(BigUnsigned(long(-1))); //error -TEST(BigUnsigned(pathologicalLong)); //error - -// ...during subtraction -TEST(BigUnsigned(5) - BigUnsigned(6)); //error -TEST(stringToBigUnsigned("314159265358979323") - stringToBigUnsigned("314159265358979324")); //error -TEST(check(BigUnsigned(5) - BigUnsigned(5))); //0 -TEST(check(stringToBigUnsigned("314159265358979323") - stringToBigUnsigned("314159265358979323"))); //0 -TEST(check(stringToBigUnsigned("4294967296") - BigUnsigned(1))); //4294967295 - -// === BigUnsigned addition === - -TEST(check(BigUnsigned(0) + 0)); //0 -TEST(check(BigUnsigned(0) + 1)); //1 -// Ordinary carry -TEST(check(stringToBigUnsigned("8589934591" /* 2^33 - 1*/) - + stringToBigUnsigned("4294967298" /* 2^32 + 2 */))); //12884901889 -// Creation of a new block -TEST(check(BigUnsigned(0xFFFFFFFFU) + 1)); //4294967296 - -// === BigUnsigned subtraction === - -TEST(check(BigUnsigned(1) - 0)); //1 -TEST(check(BigUnsigned(1) - 1)); //0 -TEST(check(BigUnsigned(2) - 1)); //1 -// Ordinary borrow -TEST(check(stringToBigUnsigned("12884901889") - - stringToBigUnsigned("4294967298"))); //8589934591 -// Borrow that removes a block -TEST(check(stringToBigUnsigned("4294967296") - 1)); //4294967295 - -// === BigUnsigned multiplication and division === - -BigUnsigned a = check(BigUnsigned(314159265) * 358979323); -TEST(a); //112776680263877595 -TEST(a / 123); //916883579381118 -TEST(a % 123); //81 - -TEST(BigUnsigned(5) / 0); //error - -// === Block accessors === - -BigUnsigned b; -TEST(b); //0 -TEST(b.getBlock(0)); //0 -b.setBlock(1, 314); -// Did b grow properly? And did we zero intermediate blocks? -TEST(check(b)); //1348619730944 -TEST(b.getLength()); //2 -TEST(b.getBlock(0)); //0 -TEST(b.getBlock(1)); //314 -// Did b shrink properly? -b.setBlock(1, 0); -TEST(check(b)); //0 - -BigUnsigned bb(314); -bb.setBlock(1, 159); -// Make sure we used allocateAndCopy, not allocate -TEST(bb.getBlock(0)); //314 -TEST(bb.getBlock(1)); //159 -// Blocks beyond the number should be zero regardless of whether they are -// within the capacity. -bb.add(1, 2); -TEST(bb.getBlock(0)); //3 -TEST(bb.getBlock(1)); //0 -TEST(bb.getBlock(2)); //0 -TEST(bb.getBlock(314159)); //0 - -// === Bit accessors === - -TEST(BigUnsigned(0).bitLength()); //0 -TEST(BigUnsigned(1).bitLength()); //1 -TEST(BigUnsigned(4095).bitLength()); //12 -TEST(BigUnsigned(4096).bitLength()); //13 -// 5 billion is between 2^32 (about 4 billion) and 2^33 (about 8 billion). -TEST(stringToBigUnsigned("5000000000").bitLength()); //33 - -// 25 is binary 11001. -BigUnsigned bbb(25); -TEST(bbb.getBit(4)); //1 -TEST(bbb.getBit(3)); //1 -TEST(bbb.getBit(2)); //0 -TEST(bbb.getBit(1)); //0 -TEST(bbb.getBit(0)); //1 -TEST(bbb.bitLength()); //5 -// Effectively add 2^32. -bbb.setBit(32, true); -TEST(bbb); //4294967321 -bbb.setBit(31, true); -bbb.setBit(32, false); -TEST(check(bbb)); //2147483673 - -// === Combining BigUnsigned, BigInteger, and primitive integers === - -BigUnsigned p1 = BigUnsigned(3) * 5; -TEST(p1); //15 -/* In this case, we would like g++ to implicitly promote the BigUnsigned to a - * BigInteger, but it seems to prefer converting the -5 to a BigUnsigned, which - * causes an error. If I take out constructors for BigUnsigned from signed - * primitive integers, the BigUnsigned(3) becomes ambiguous, and if I take out - * all the constructors but BigUnsigned(unsigned long), g++ uses that - * constructor and gets a wrong (positive) answer. Thus, I think we'll just - * have to live with this cast. */ -BigInteger p2 = BigInteger(BigUnsigned(3)) * -5; -TEST(p2); //-15 - -// === Test some previous bugs === - -{ - /* Test that BigInteger division sets the sign to zero. - * Bug reported by David Allen. */ - BigInteger num(3), denom(5), quotient; - num.divideWithRemainder(denom, quotient); - check(quotient); - num = 5; - num.divideWithRemainder(denom, quotient); - check(num); -} - -{ - /* Test that BigInteger subtraction sets the sign properly. - * Bug reported by Samuel Larkin. */ - BigInteger zero(0), three(3), ans; - ans = zero - three; - TEST(check(ans).getSign()); //-1 -} - -{ - /* Test that BigInteger multiplication shifts bits properly on systems - * where long is bigger than int. (Obviously, this would only catch the - * bug when run on such a system.) - * Bug reported by Mohand Mezmaz. */ - BigInteger f=4; f*=3; - TEST(check(f)); //12 -} - -{ - /* Test that bitwise XOR allocates the larger length. - * Bug reported by Sriram Sankararaman. */ - BigUnsigned a(0), b(3), ans; - ans = a ^ b; - TEST(ans); //3 -} - -{ - /* Test that an aliased multiplication works. - * Bug reported by Boris Dessy. */ - BigInteger num(5); - num *= num; - TEST(check(num)); //25 -} - -{ - /* Test that BigUnsignedInABase(std::string) constructor rejects digits - * too big for the specified base. - * Bug reported by Niakam Kazemi. */ - TEST(BigUnsignedInABase("f", 10)); //error -} - -} catch (const char *err) { - cout << "UNCAUGHT ERROR: " << err << endl; -} - -return 0; -} diff --git a/yosys/libs/ezsat/.gitignore b/yosys/libs/ezsat/.gitignore deleted file mode 100644 index e079bd096..000000000 --- a/yosys/libs/ezsat/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -demo_bit -demo_cmp -demo_vec -puzzle3d -testbench diff --git a/yosys/libs/ezsat/Makefile b/yosys/libs/ezsat/Makefile deleted file mode 100644 index b1f864160..000000000 --- a/yosys/libs/ezsat/Makefile +++ /dev/null @@ -1,30 +0,0 @@ - -CC = clang -CXX = clang -CXXFLAGS = -MD -Wall -Wextra -ggdb -CXXFLAGS += -std=c++11 -O0 -LDLIBS = ../minisat/Options.cc ../minisat/SimpSolver.cc ../minisat/Solver.cc ../minisat/System.cc -lm -lstdc++ - - -all: demo_vec demo_bit demo_cmp testbench puzzle3d - -demo_vec: demo_vec.o ezsat.o ezminisat.o -demo_bit: demo_bit.o ezsat.o ezminisat.o -demo_cmp: demo_cmp.o ezsat.o ezminisat.o -testbench: testbench.o ezsat.o ezminisat.o -puzzle3d: puzzle3d.o ezsat.o ezminisat.o - -test: all - ./testbench - ./demo_bit - ./demo_vec - # ./demo_cmp - # ./puzzle3d - -clean: - rm -f demo_bit demo_vec demo_cmp testbench puzzle3d *.o *.d - -.PHONY: all test clean - --include *.d - diff --git a/yosys/libs/ezsat/README b/yosys/libs/ezsat/README deleted file mode 100644 index c6745e6cf..000000000 --- a/yosys/libs/ezsat/README +++ /dev/null @@ -1,29 +0,0 @@ - - ************************************************************************** - * * - * The ezSAT C++11 library * - * * - * A simple frontend to SAT solvers with bindings to MiniSAT. * - * by Clifford Wolf * - * * - ************************************************************************** - -============ -Introduction -============ - -This library acts as a frontend to SAT solvers and a helper for generating -CNF for sat solvers. It comes with bindings for MiniSAT (http://minisat.se/). - -Have a look at demo_bit.cc and demo_vec.cc for examples of how to set up -a SAT problem using ezSAT. Have a look at puzzle3d.cc for a more complex -(real-world) example of using ezSAT. - - -C++11 Warning -------------- - -This project is written in C++11. Use appropriate compiler switches to compile -it. Tested with clang version 3.0 and option -std=c++11. Also tested with gcc -version 4.6.3 and option -std=c++0x. - diff --git a/yosys/libs/ezsat/demo_bit.cc b/yosys/libs/ezsat/demo_bit.cc deleted file mode 100644 index c7b11246c..000000000 --- a/yosys/libs/ezsat/demo_bit.cc +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "ezminisat.h" -#include - -void print_results(bool satisfiable, const std::vector &modelValues) -{ - if (!satisfiable) { - printf("not satisfiable.\n\n"); - } else { - printf("satisfiable:"); - for (auto val : modelValues) - printf(" %d", val ? 1 : 0); - printf("\n\n"); - } -} - -int main() -{ - ezMiniSAT sat; - - // 3 input AOI-Gate - // 'pos_active' encodes the condition under which the pullup path of the gate is active - // 'neg_active' encodes the condition under which the pulldown path of the gate is active - // 'impossible' encodes the condition that both or none of the above paths is active - int pos_active = sat.AND(sat.NOT("A"), sat.OR(sat.NOT("B"), sat.NOT("C"))); - int neg_active = sat.OR("A", sat.AND("B", "C")); - int impossible = sat.IFF(pos_active, neg_active); - - std::vector modelVars; - std::vector modelValues; - bool satisfiable; - - modelVars.push_back(sat.VAR("A")); - modelVars.push_back(sat.VAR("B")); - modelVars.push_back(sat.VAR("C")); - - printf("\n"); - - printf("pos_active: %s\n", sat.to_string(pos_active).c_str()); - satisfiable = sat.solve(modelVars, modelValues, pos_active); - print_results(satisfiable, modelValues); - - printf("neg_active: %s\n", sat.to_string(neg_active).c_str()); - satisfiable = sat.solve(modelVars, modelValues, neg_active); - print_results(satisfiable, modelValues); - - printf("impossible: %s\n", sat.to_string(impossible).c_str()); - satisfiable = sat.solve(modelVars, modelValues, impossible); - print_results(satisfiable, modelValues); - - return 0; -} - diff --git a/yosys/libs/ezsat/demo_cmp.cc b/yosys/libs/ezsat/demo_cmp.cc deleted file mode 100644 index 8d7ceb2b4..000000000 --- a/yosys/libs/ezsat/demo_cmp.cc +++ /dev/null @@ -1,146 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "ezminisat.h" -#include - -#define INIT_X 123456789 -#define INIT_Y 362436069 -#define INIT_Z 521288629 -#define INIT_W 88675123 - -uint32_t xorshift128() { - static uint32_t x = INIT_X; - static uint32_t y = INIT_Y; - static uint32_t z = INIT_Z; - static uint32_t w = INIT_W; - uint32_t t = x ^ (x << 11); - x = y; y = z; z = w; - w ^= (w >> 19) ^ t ^ (t >> 8); - return w; -} - -void test_cmp(uint32_t a, uint32_t b) -{ - ezMiniSAT sat; - - printf("A = %10u (%10d)\n", a, int32_t(a)); - printf("B = %10u (%10d)\n", b, int32_t(b)); - printf("\n"); - - std::vector va = sat.vec_var("a", 32); - std::vector vb = sat.vec_var("b", 32); - - sat.vec_set_unsigned(va, a); - sat.vec_set_unsigned(vb, b); - -#define MONITOR_VARS \ - X(carry) X(overflow) X(sign) X(zero) \ - X(lt_signed) X(le_signed) X(ge_signed) X(gt_signed) \ - X(lt_unsigned) X(le_unsigned) X(ge_unsigned) X(gt_unsigned) - -#define X(_n) int _n; bool _n ## _master; - MONITOR_VARS -#undef X - - carry_master = ((uint64_t(a) - uint64_t(b)) >> 32) & 1; - overflow_master = (int32_t(a) - int32_t(b)) != (int64_t(int32_t(a)) - int64_t(int32_t(b))); - sign_master = ((a - b) >> 31) & 1; - zero_master = a == b; - - sat.vec_cmp(va, vb, carry, overflow, sign, zero); - - lt_signed_master = int32_t(a) < int32_t(b); - le_signed_master = int32_t(a) <= int32_t(b); - ge_signed_master = int32_t(a) >= int32_t(b); - gt_signed_master = int32_t(a) > int32_t(b); - - lt_unsigned_master = a < b; - le_unsigned_master = a <= b; - ge_unsigned_master = a >= b; - gt_unsigned_master = a > b; - - lt_signed = sat.vec_lt_signed(va, vb); - le_signed = sat.vec_le_signed(va, vb); - ge_signed = sat.vec_ge_signed(va, vb); - gt_signed = sat.vec_gt_signed(va, vb); - - lt_unsigned = sat.vec_lt_unsigned(va, vb); - le_unsigned = sat.vec_le_unsigned(va, vb); - ge_unsigned = sat.vec_ge_unsigned(va, vb); - gt_unsigned = sat.vec_gt_unsigned(va, vb); - - std::vector modelExpressions; - std::vector modelValues, modelMaster; - std::vector modelNames; - -#define X(_n) modelExpressions.push_back(_n); modelNames.push_back(#_n); modelMaster.push_back(_n ## _master); - MONITOR_VARS -#undef X - - std::vector add_ab = sat.vec_add(va, vb); - std::vector sub_ab = sat.vec_sub(va, vb); - std::vector sub_ba = sat.vec_sub(vb, va); - - sat.vec_append(modelExpressions, add_ab); - sat.vec_append(modelExpressions, sub_ab); - sat.vec_append(modelExpressions, sub_ba); - - if (!sat.solve(modelExpressions, modelValues)) { - fprintf(stderr, "SAT solver failed to find a model!\n"); - abort(); - } - - bool found_error = false; - - for (size_t i = 0; i < modelMaster.size(); i++) { - if (modelMaster.at(i) != int(modelValues.at(i))) - found_error = true; - printf("%-20s %d%s\n", modelNames.at(i).c_str(), int(modelValues.at(i)), - modelMaster.at(i) != modelValues.at(i) ? " !!!" : ""); - } - printf("\n"); - - uint32_t add_ab_value = sat.vec_model_get_unsigned(modelExpressions, modelValues, add_ab); - uint32_t sub_ab_value = sat.vec_model_get_unsigned(modelExpressions, modelValues, sub_ab); - uint32_t sub_ba_value = sat.vec_model_get_unsigned(modelExpressions, modelValues, sub_ba); - - printf("%-20s %10u %10u%s\n", "result(a+b)", add_ab_value, a+b, add_ab_value != a+b ? " !!!" : ""); - printf("%-20s %10u %10u%s\n", "result(a-b)", sub_ab_value, a-b, sub_ab_value != a-b ? " !!!" : ""); - printf("%-20s %10u %10u%s\n", "result(b-a)", sub_ba_value, b-a, sub_ba_value != b-a ? " !!!" : ""); - printf("\n"); - - if (found_error || add_ab_value != a+b || sub_ab_value != a-b || sub_ba_value != b-a) - abort(); -} - -int main() -{ - printf("\n"); - for (int i = 0; i < 1024; i++) { - printf("************** %d **************\n\n", i); - uint32_t a = xorshift128(); - uint32_t b = xorshift128(); - if (xorshift128() % 16 == 0) - a = b; - test_cmp(a, b); - } - return 0; -} - diff --git a/yosys/libs/ezsat/demo_vec.cc b/yosys/libs/ezsat/demo_vec.cc deleted file mode 100644 index eb8d75997..000000000 --- a/yosys/libs/ezsat/demo_vec.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "ezminisat.h" -#include - -#define INIT_X 123456789 -#define INIT_Y 362436069 -#define INIT_Z 521288629 -#define INIT_W 88675123 - -uint32_t xorshift128() { - static uint32_t x = INIT_X; - static uint32_t y = INIT_Y; - static uint32_t z = INIT_Z; - static uint32_t w = INIT_W; - uint32_t t = x ^ (x << 11); - x = y; y = z; z = w; - w ^= (w >> 19) ^ t ^ (t >> 8); - return w; -} - -void xorshift128_sat(ezSAT &sat, std::vector &x, std::vector &y, std::vector &z, std::vector &w) -{ - std::vector t = sat.vec_xor(x, sat.vec_shl(x, 11)); - x = y; y = z; z = w; - w = sat.vec_xor(sat.vec_xor(w, sat.vec_shr(w, 19)), sat.vec_xor(t, sat.vec_shr(t, 8))); -} - -void find_xorshift128_init_state(uint32_t &x, uint32_t &y, uint32_t &z, uint32_t &w, uint32_t w1, uint32_t w2, uint32_t w3, uint32_t w4) -{ - ezMiniSAT sat; - - std::vector vx = sat.vec_var("x", 32); - std::vector vy = sat.vec_var("y", 32); - std::vector vz = sat.vec_var("z", 32); - std::vector vw = sat.vec_var("w", 32); - - xorshift128_sat(sat, vx, vy, vz, vw); - sat.vec_set_unsigned(vw, w1); - - xorshift128_sat(sat, vx, vy, vz, vw); - sat.vec_set_unsigned(vw, w2); - - xorshift128_sat(sat, vx, vy, vz, vw); - sat.vec_set_unsigned(vw, w3); - - xorshift128_sat(sat, vx, vy, vz, vw); - sat.vec_set_unsigned(vw, w4); - - std::vector modelExpressions; - std::vector modelValues; - - sat.vec_append(modelExpressions, sat.vec_var("x", 32)); - sat.vec_append(modelExpressions, sat.vec_var("y", 32)); - sat.vec_append(modelExpressions, sat.vec_var("z", 32)); - sat.vec_append(modelExpressions, sat.vec_var("w", 32)); - - // sat.printDIMACS(stdout); - - if (!sat.solve(modelExpressions, modelValues)) { - fprintf(stderr, "SAT solver failed to find a model!\n"); - abort(); - } - - x = sat.vec_model_get_unsigned(modelExpressions, modelValues, sat.vec_var("x", 32)); - y = sat.vec_model_get_unsigned(modelExpressions, modelValues, sat.vec_var("y", 32)); - z = sat.vec_model_get_unsigned(modelExpressions, modelValues, sat.vec_var("z", 32)); - w = sat.vec_model_get_unsigned(modelExpressions, modelValues, sat.vec_var("w", 32)); -} - -int main() -{ - uint32_t w1 = xorshift128(); - uint32_t w2 = xorshift128(); - uint32_t w3 = xorshift128(); - uint32_t w4 = xorshift128(); - uint32_t x, y, z, w; - - printf("\n"); - - find_xorshift128_init_state(x, y, z, w, w1, w2, w3, w4); - - printf("x = %9u (%s)\n", (unsigned int)x, x == INIT_X ? "ok" : "ERROR"); - printf("y = %9u (%s)\n", (unsigned int)y, y == INIT_Y ? "ok" : "ERROR"); - printf("z = %9u (%s)\n", (unsigned int)z, z == INIT_Z ? "ok" : "ERROR"); - printf("w = %9u (%s)\n", (unsigned int)w, w == INIT_W ? "ok" : "ERROR"); - - if (x != INIT_X || y != INIT_Y || z != INIT_Z || w != INIT_W) - abort(); - - printf("\n"); - - return 0; -} - diff --git a/yosys/libs/ezsat/ezminisat.cc b/yosys/libs/ezsat/ezminisat.cc deleted file mode 100644 index 4be5fd493..000000000 --- a/yosys/libs/ezsat/ezminisat.cc +++ /dev/null @@ -1,247 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// needed for MiniSAT headers (see Minisat Makefile) -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif - -#include "ezminisat.h" - -#include -#include -#include -#include - -#ifndef _WIN32 -# include -#endif - -#include "../minisat/Solver.h" -#include "../minisat/SimpSolver.h" - -ezMiniSAT::ezMiniSAT() : minisatSolver(NULL) -{ - minisatSolver = NULL; - foundContradiction = false; - - freeze(CONST_TRUE); - freeze(CONST_FALSE); -} - -ezMiniSAT::~ezMiniSAT() -{ - if (minisatSolver != NULL) - delete minisatSolver; -} - -void ezMiniSAT::clear() -{ - if (minisatSolver != NULL) { - delete minisatSolver; - minisatSolver = NULL; - } - foundContradiction = false; - minisatVars.clear(); -#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL - cnfFrozenVars.clear(); -#endif - ezSAT::clear(); -} - -#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL -void ezMiniSAT::freeze(int id) -{ - if (!mode_non_incremental()) - cnfFrozenVars.insert(bind(id)); -} - -bool ezMiniSAT::eliminated(int idx) -{ - idx = idx < 0 ? -idx : idx; - if (minisatSolver != NULL && idx > 0 && idx <= int(minisatVars.size())) - return minisatSolver->isEliminated(minisatVars.at(idx-1)); - return false; -} -#endif - -#ifndef _WIN32 -ezMiniSAT *ezMiniSAT::alarmHandlerThis = NULL; -clock_t ezMiniSAT::alarmHandlerTimeout = 0; - -void ezMiniSAT::alarmHandler(int) -{ - if (clock() > alarmHandlerTimeout) { - alarmHandlerThis->minisatSolver->interrupt(); - alarmHandlerTimeout = 0; - } else - alarm(1); -} -#endif - -bool ezMiniSAT::solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) -{ - preSolverCallback(); - - solverTimoutStatus = false; - - if (0) { -contradiction: - delete minisatSolver; - minisatSolver = NULL; - minisatVars.clear(); - foundContradiction = true; - return false; - } - - if (foundContradiction) { - consumeCnf(); - return false; - } - - std::vector extraClauses, modelIdx; - - for (auto id : assumptions) - extraClauses.push_back(bind(id)); - for (auto id : modelExpressions) - modelIdx.push_back(bind(id)); - - if (minisatSolver == NULL) { - minisatSolver = new Solver; - minisatSolver->verbosity = EZMINISAT_VERBOSITY; - } - -#if EZMINISAT_INCREMENTAL - std::vector> cnf; - consumeCnf(cnf); -#else - const std::vector> &cnf = this->cnf(); -#endif - - while (int(minisatVars.size()) < numCnfVariables()) - minisatVars.push_back(minisatSolver->newVar()); - -#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL - for (auto idx : cnfFrozenVars) - minisatSolver->setFrozen(minisatVars.at(idx > 0 ? idx-1 : -idx-1), true); - cnfFrozenVars.clear(); -#endif - - for (auto &clause : cnf) { - Minisat::vec ps; - for (auto idx : clause) { - if (idx > 0) - ps.push(Minisat::mkLit(minisatVars.at(idx-1))); - else - ps.push(Minisat::mkLit(minisatVars.at(-idx-1), true)); -#if EZMINISAT_SIMPSOLVER - if (minisatSolver->isEliminated(minisatVars.at(idx > 0 ? idx-1 : -idx-1))) { - fprintf(stderr, "Assert in %s:%d failed! Missing call to ezsat->freeze(): %s (lit=%d)\n", - __FILE__, __LINE__, cnfLiteralInfo(idx).c_str(), idx); - abort(); - } -#endif - } - if (!minisatSolver->addClause(ps)) - goto contradiction; - } - - if (cnf.size() > 0 && !minisatSolver->simplify()) - goto contradiction; - - Minisat::vec assumps; - - for (auto idx : extraClauses) { - if (idx > 0) - assumps.push(Minisat::mkLit(minisatVars.at(idx-1))); - else - assumps.push(Minisat::mkLit(minisatVars.at(-idx-1), true)); -#if EZMINISAT_SIMPSOLVER - if (minisatSolver->isEliminated(minisatVars.at(idx > 0 ? idx-1 : -idx-1))) { - fprintf(stderr, "Assert in %s:%d failed! Missing call to ezsat->freeze(): %s\n", __FILE__, __LINE__, cnfLiteralInfo(idx).c_str()); - abort(); - } -#endif - } - -#ifndef _WIN32 - struct sigaction sig_action; - struct sigaction old_sig_action; - int old_alarm_timeout = 0; - - if (solverTimeout > 0) { - sig_action.sa_handler = alarmHandler; - sigemptyset(&sig_action.sa_mask); - sig_action.sa_flags = SA_RESTART; - alarmHandlerThis = this; - alarmHandlerTimeout = clock() + solverTimeout*CLOCKS_PER_SEC; - old_alarm_timeout = alarm(0); - sigaction(SIGALRM, &sig_action, &old_sig_action); - alarm(1); - } -#endif - - bool foundSolution = minisatSolver->solve(assumps); - -#ifndef _WIN32 - if (solverTimeout > 0) { - if (alarmHandlerTimeout == 0) - solverTimoutStatus = true; - alarm(0); - sigaction(SIGALRM, &old_sig_action, NULL); - alarm(old_alarm_timeout); - } -#endif - - if (!foundSolution) { -#if !EZMINISAT_INCREMENTAL - delete minisatSolver; - minisatSolver = NULL; - minisatVars.clear(); -#endif - return false; - } - - modelValues.clear(); - modelValues.resize(modelIdx.size()); - - for (size_t i = 0; i < modelIdx.size(); i++) - { - int idx = modelIdx[i]; - bool refvalue = true; - - if (idx < 0) - idx = -idx, refvalue = false; - - using namespace Minisat; - lbool value = minisatSolver->modelValue(minisatVars.at(idx-1)); - modelValues[i] = (value == Minisat::lbool(refvalue)); - } - -#if !EZMINISAT_INCREMENTAL - delete minisatSolver; - minisatSolver = NULL; - minisatVars.clear(); -#endif - return true; -} - diff --git a/yosys/libs/ezsat/ezminisat.h b/yosys/libs/ezsat/ezminisat.h deleted file mode 100644 index 3a34c13c8..000000000 --- a/yosys/libs/ezsat/ezminisat.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef EZMINISAT_H -#define EZMINISAT_H - -#define EZMINISAT_SIMPSOLVER 1 -#define EZMINISAT_VERBOSITY 0 -#define EZMINISAT_INCREMENTAL 1 - -#include "ezsat.h" -#include - -// minisat is using limit macros and format macros in their headers that -// can be the source of some troubles when used from c++11. therefore we -// don't force ezSAT users to use minisat headers.. -namespace Minisat { - class Solver; - class SimpSolver; -} - -class ezMiniSAT : public ezSAT -{ -private: -#if EZMINISAT_SIMPSOLVER - typedef Minisat::SimpSolver Solver; -#else - typedef Minisat::Solver Solver; -#endif - Solver *minisatSolver; - std::vector minisatVars; - bool foundContradiction; - -#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL - std::set cnfFrozenVars; -#endif - -#ifndef _WIN32 - static ezMiniSAT *alarmHandlerThis; - static clock_t alarmHandlerTimeout; - static void alarmHandler(int); -#endif - -public: - ezMiniSAT(); - virtual ~ezMiniSAT(); - virtual void clear(); -#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL - virtual void freeze(int id); - virtual bool eliminated(int idx); -#endif - virtual bool solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions); -}; - -#endif diff --git a/yosys/libs/ezsat/ezsat.cc b/yosys/libs/ezsat/ezsat.cc deleted file mode 100644 index 177bcd8a3..000000000 --- a/yosys/libs/ezsat/ezsat.cc +++ /dev/null @@ -1,1449 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "ezsat.h" - -#include -#include -#include -#include - -#include - -const int ezSAT::CONST_TRUE = 1; -const int ezSAT::CONST_FALSE = 2; - -static std::string my_int_to_string(int i) -{ -#ifdef __MINGW32__ - char buffer[64]; - snprintf(buffer, 64, "%d", i); - return buffer; -#else - return std::to_string(i); -#endif -} - -ezSAT::ezSAT() -{ - statehash = 5381; - - flag_keep_cnf = false; - flag_non_incremental = false; - - non_incremental_solve_used_up = false; - - cnfConsumed = false; - cnfVariableCount = 0; - cnfClausesCount = 0; - - solverTimeout = 0; - solverTimoutStatus = false; - - literal("CONST_TRUE"); - literal("CONST_FALSE"); - - assert(literal("CONST_TRUE") == CONST_TRUE); - assert(literal("CONST_FALSE") == CONST_FALSE); -} - -ezSAT::~ezSAT() -{ -} - -void ezSAT::addhash(unsigned int h) -{ - statehash = ((statehash << 5) + statehash) ^ h; -} - -int ezSAT::value(bool val) -{ - return val ? CONST_TRUE : CONST_FALSE; -} - -int ezSAT::literal() -{ - literals.push_back(std::string()); - return literals.size(); -} - -int ezSAT::literal(const std::string &name) -{ - if (literalsCache.count(name) == 0) { - literals.push_back(name); - literalsCache[name] = literals.size(); - } - return literalsCache.at(name); -} - -int ezSAT::frozen_literal() -{ - int id = literal(); - freeze(id); - return id; -} - -int ezSAT::frozen_literal(const std::string &name) -{ - int id = literal(name); - freeze(id); - return id; -} - -int ezSAT::expression(OpId op, int a, int b, int c, int d, int e, int f) -{ - std::vector args(6); - args[0] = a, args[1] = b, args[2] = c; - args[3] = d, args[4] = e, args[5] = f; - return expression(op, args); -} - -int ezSAT::expression(OpId op, const std::vector &args) -{ - std::vector myArgs; - myArgs.reserve(args.size()); - bool xorRemovedOddTrues = false; - - addhash(__LINE__); - addhash(op); - - for (auto arg : args) - { - addhash(__LINE__); - addhash(arg); - - if (arg == 0) - continue; - if (op == OpAnd && arg == CONST_TRUE) - continue; - if ((op == OpOr || op == OpXor) && arg == CONST_FALSE) - continue; - if (op == OpXor && arg == CONST_TRUE) { - xorRemovedOddTrues = !xorRemovedOddTrues; - continue; - } - myArgs.push_back(arg); - } - - if (myArgs.size() > 0 && (op == OpAnd || op == OpOr || op == OpXor || op == OpIFF)) { - std::sort(myArgs.begin(), myArgs.end()); - int j = 0; - for (int i = 1; i < int(myArgs.size()); i++) - if (j < 0 || myArgs[j] != myArgs[i]) - myArgs[++j] = myArgs[i]; - else if (op == OpXor) - j--; - myArgs.resize(j+1); - } - - switch (op) - { - case OpNot: - assert(myArgs.size() == 1); - if (myArgs[0] == CONST_TRUE) - return CONST_FALSE; - if (myArgs[0] == CONST_FALSE) - return CONST_TRUE; - break; - - case OpAnd: - if (myArgs.size() == 0) - return CONST_TRUE; - if (myArgs.size() == 1) - return myArgs[0]; - break; - - case OpOr: - if (myArgs.size() == 0) - return CONST_FALSE; - if (myArgs.size() == 1) - return myArgs[0]; - break; - - case OpXor: - if (myArgs.size() == 0) - return xorRemovedOddTrues ? CONST_TRUE : CONST_FALSE; - if (myArgs.size() == 1) - return xorRemovedOddTrues ? NOT(myArgs[0]) : myArgs[0]; - break; - - case OpIFF: - assert(myArgs.size() >= 1); - if (myArgs.size() == 1) - return CONST_TRUE; - // FIXME: Add proper const folding - break; - - case OpITE: - assert(myArgs.size() == 3); - if (myArgs[0] == CONST_TRUE) - return myArgs[1]; - if (myArgs[0] == CONST_FALSE) - return myArgs[2]; - break; - - default: - abort(); - } - - std::pair> myExpr(op, myArgs); - int id = 0; - - if (expressionsCache.count(myExpr) > 0) { - id = expressionsCache.at(myExpr); - } else { - id = -(int(expressions.size()) + 1); - expressionsCache[myExpr] = id; - expressions.push_back(myExpr); - } - - if (xorRemovedOddTrues) - id = NOT(id); - - addhash(__LINE__); - addhash(id); - - return id; -} - -void ezSAT::lookup_literal(int id, std::string &name) const -{ - assert(0 < id && id <= int(literals.size())); - name = literals[id - 1]; -} - -const std::string &ezSAT::lookup_literal(int id) const -{ - assert(0 < id && id <= int(literals.size())); - return literals[id - 1]; -} - -void ezSAT::lookup_expression(int id, OpId &op, std::vector &args) const -{ - assert(0 < -id && -id <= int(expressions.size())); - op = expressions[-id - 1].first; - args = expressions[-id - 1].second; -} - -const std::vector &ezSAT::lookup_expression(int id, OpId &op) const -{ - assert(0 < -id && -id <= int(expressions.size())); - op = expressions[-id - 1].first; - return expressions[-id - 1].second; -} - -int ezSAT::parse_string(const std::string &) -{ - abort(); -} - -std::string ezSAT::to_string(int id) const -{ - std::string text; - - if (id > 0) - { - lookup_literal(id, text); - } - else - { - OpId op; - std::vector args; - lookup_expression(id, op, args); - - switch (op) - { - case OpNot: - text = "not("; - break; - - case OpAnd: - text = "and("; - break; - - case OpOr: - text = "or("; - break; - - case OpXor: - text = "xor("; - break; - - case OpIFF: - text = "iff("; - break; - - case OpITE: - text = "ite("; - break; - - default: - abort(); - } - - for (int i = 0; i < int(args.size()); i++) { - if (i > 0) - text += ", "; - text += to_string(args[i]); - } - - text += ")"; - } - - return text; -} - -int ezSAT::eval(int id, const std::vector &values) const -{ - if (id > 0) { - if (id <= int(values.size()) && (values[id-1] == CONST_TRUE || values[id-1] == CONST_FALSE || values[id-1] == 0)) - return values[id-1]; - return 0; - } - - OpId op; - const std::vector &args = lookup_expression(id, op); - int a, b; - - switch (op) - { - case OpNot: - assert(args.size() == 1); - a = eval(args[0], values); - if (a == CONST_TRUE) - return CONST_FALSE; - if (a == CONST_FALSE) - return CONST_TRUE; - return 0; - case OpAnd: - a = CONST_TRUE; - for (auto arg : args) { - b = eval(arg, values); - if (b != CONST_TRUE && b != CONST_FALSE) - a = 0; - if (b == CONST_FALSE) - return CONST_FALSE; - } - return a; - case OpOr: - a = CONST_FALSE; - for (auto arg : args) { - b = eval(arg, values); - if (b != CONST_TRUE && b != CONST_FALSE) - a = 0; - if (b == CONST_TRUE) - return CONST_TRUE; - } - return a; - case OpXor: - a = CONST_FALSE; - for (auto arg : args) { - b = eval(arg, values); - if (b != CONST_TRUE && b != CONST_FALSE) - return 0; - if (b == CONST_TRUE) - a = a == CONST_TRUE ? CONST_FALSE : CONST_TRUE; - } - return a; - case OpIFF: - assert(args.size() > 0); - a = eval(args[0], values); - for (auto arg : args) { - b = eval(arg, values); - if (b != CONST_TRUE && b != CONST_FALSE) - return 0; - if (b != a) - return CONST_FALSE; - } - return CONST_TRUE; - case OpITE: - assert(args.size() == 3); - a = eval(args[0], values); - if (a == CONST_TRUE) - return eval(args[1], values); - if (a == CONST_FALSE) - return eval(args[2], values); - return 0; - default: - abort(); - } -} - -void ezSAT::clear() -{ - cnfConsumed = false; - cnfVariableCount = 0; - cnfClausesCount = 0; - cnfLiteralVariables.clear(); - cnfExpressionVariables.clear(); - cnfClauses.clear(); -} - -void ezSAT::freeze(int) -{ -} - -bool ezSAT::eliminated(int) -{ - return false; -} - -void ezSAT::assume(int id) -{ - addhash(__LINE__); - addhash(id); - - if (id < 0) - { - assert(0 < -id && -id <= int(expressions.size())); - cnfExpressionVariables.resize(expressions.size()); - - if (cnfExpressionVariables[-id-1] == 0) - { - OpId op; - std::vector args; - lookup_expression(id, op, args); - - if (op == OpNot) { - int idx = bind(args[0]); - cnfClauses.push_back(std::vector(1, -idx)); - cnfClausesCount++; - return; - } - if (op == OpOr) { - std::vector clause; - for (int arg : args) - clause.push_back(bind(arg)); - cnfClauses.push_back(clause); - cnfClausesCount++; - return; - } - if (op == OpAnd) { - for (int arg : args) { - cnfClauses.push_back(std::vector(1, bind(arg))); - cnfClausesCount++; - } - return; - } - } - } - - int idx = bind(id); - cnfClauses.push_back(std::vector(1, idx)); - cnfClausesCount++; -} - -void ezSAT::add_clause(const std::vector &args) -{ - addhash(__LINE__); - for (auto arg : args) - addhash(arg); - - cnfClauses.push_back(args); - cnfClausesCount++; -} - -void ezSAT::add_clause(const std::vector &args, bool argsPolarity, int a, int b, int c) -{ - std::vector clause; - for (auto arg : args) - clause.push_back(argsPolarity ? +arg : -arg); - if (a != 0) - clause.push_back(a); - if (b != 0) - clause.push_back(b); - if (c != 0) - clause.push_back(c); - add_clause(clause); -} - -void ezSAT::add_clause(int a, int b, int c) -{ - std::vector clause; - if (a != 0) - clause.push_back(a); - if (b != 0) - clause.push_back(b); - if (c != 0) - clause.push_back(c); - add_clause(clause); -} - -int ezSAT::bind_cnf_not(const std::vector &args) -{ - assert(args.size() == 1); - return -args[0]; -} - -int ezSAT::bind_cnf_and(const std::vector &args) -{ - assert(args.size() >= 2); - - int idx = ++cnfVariableCount; - add_clause(args, false, idx); - - for (auto arg : args) - add_clause(-idx, arg); - - return idx; -} - -int ezSAT::bind_cnf_or(const std::vector &args) -{ - assert(args.size() >= 2); - - int idx = ++cnfVariableCount; - add_clause(args, true, -idx); - - for (auto arg : args) - add_clause(idx, -arg); - - return idx; -} - -int ezSAT::bound(int id) const -{ - if (id > 0 && id <= int(cnfLiteralVariables.size())) - return cnfLiteralVariables[id-1]; - if (-id > 0 && -id <= int(cnfExpressionVariables.size())) - return cnfExpressionVariables[-id-1]; - return 0; -} - -std::string ezSAT::cnfLiteralInfo(int idx) const -{ - for (int i = 0; i < int(cnfLiteralVariables.size()); i++) { - if (cnfLiteralVariables[i] == idx) - return to_string(i+1); - if (cnfLiteralVariables[i] == -idx) - return "NOT " + to_string(i+1); - } - for (int i = 0; i < int(cnfExpressionVariables.size()); i++) { - if (cnfExpressionVariables[i] == idx) - return to_string(-i-1); - if (cnfExpressionVariables[i] == -idx) - return "NOT " + to_string(-i-1); - } - return ""; -} - -int ezSAT::bind(int id, bool auto_freeze) -{ - addhash(__LINE__); - addhash(id); - addhash(auto_freeze); - - if (id >= 0) { - assert(0 < id && id <= int(literals.size())); - cnfLiteralVariables.resize(literals.size()); - if (eliminated(cnfLiteralVariables[id-1])) { - fprintf(stderr, "ezSAT: Missing freeze on literal `%s'.\n", to_string(id).c_str()); - abort(); - } - if (cnfLiteralVariables[id-1] == 0) { - cnfLiteralVariables[id-1] = ++cnfVariableCount; - if (id == CONST_TRUE) - add_clause(+cnfLiteralVariables[id-1]); - if (id == CONST_FALSE) - add_clause(-cnfLiteralVariables[id-1]); - } - return cnfLiteralVariables[id-1]; - } - - assert(0 < -id && -id <= int(expressions.size())); - cnfExpressionVariables.resize(expressions.size()); - - if (eliminated(cnfExpressionVariables[-id-1])) - { - cnfExpressionVariables[-id-1] = 0; - - // this will recursively call bind(id). within the recursion - // the cnf is pre-set to 0. an idx is allocated there, then it - // is frozen, then it returns here with the new idx already set. - if (auto_freeze) - freeze(id); - } - - if (cnfExpressionVariables[-id-1] == 0) - { - OpId op; - std::vector args; - lookup_expression(id, op, args); - int idx = 0; - - if (op == OpXor) { - while (args.size() > 1) { - std::vector newArgs; - for (int i = 0; i < int(args.size()); i += 2) - if (i+1 == int(args.size())) { - newArgs.push_back(args[i]); - } else { - int sub1 = AND(args[i], NOT(args[i+1])); - int sub2 = AND(NOT(args[i]), args[i+1]); - newArgs.push_back(OR(sub1, sub2)); - } - args.swap(newArgs); - } - idx = bind(args.at(0), false); - goto assign_idx; - } - - if (op == OpIFF) { - std::vector invArgs; - for (auto arg : args) - invArgs.push_back(NOT(arg)); - int sub1 = expression(OpAnd, args); - int sub2 = expression(OpAnd, invArgs); - idx = bind(OR(sub1, sub2), false); - goto assign_idx; - } - - if (op == OpITE) { - int sub1 = AND(args[0], args[1]); - int sub2 = AND(NOT(args[0]), args[2]); - idx = bind(OR(sub1, sub2), false); - goto assign_idx; - } - - for (int i = 0; i < int(args.size()); i++) - args[i] = bind(args[i], false); - - switch (op) - { - case OpNot: idx = bind_cnf_not(args); break; - case OpAnd: idx = bind_cnf_and(args); break; - case OpOr: idx = bind_cnf_or(args); break; - default: abort(); - } - - assign_idx: - assert(idx != 0); - cnfExpressionVariables[-id-1] = idx; - } - - return cnfExpressionVariables[-id-1]; -} - -void ezSAT::consumeCnf() -{ - if (mode_keep_cnf()) - cnfClausesBackup.insert(cnfClausesBackup.end(), cnfClauses.begin(), cnfClauses.end()); - else - cnfConsumed = true; - cnfClauses.clear(); -} - -void ezSAT::consumeCnf(std::vector> &cnf) -{ - if (mode_keep_cnf()) - cnfClausesBackup.insert(cnfClausesBackup.end(), cnfClauses.begin(), cnfClauses.end()); - else - cnfConsumed = true; - cnf.swap(cnfClauses); - cnfClauses.clear(); -} - -void ezSAT::getFullCnf(std::vector> &full_cnf) const -{ - assert(full_cnf.empty()); - full_cnf.insert(full_cnf.end(), cnfClausesBackup.begin(), cnfClausesBackup.end()); - full_cnf.insert(full_cnf.end(), cnfClauses.begin(), cnfClauses.end()); -} - -void ezSAT::preSolverCallback() -{ - assert(!non_incremental_solve_used_up); - if (mode_non_incremental()) - non_incremental_solve_used_up = true; -} - -bool ezSAT::solver(const std::vector&, std::vector&, const std::vector&) -{ - preSolverCallback(); - fprintf(stderr, "************************************************************************\n"); - fprintf(stderr, "ERROR: You are trying to use the solve() method of the ezSAT base class!\n"); - fprintf(stderr, "Use a dervied class like ezMiniSAT instead.\n"); - fprintf(stderr, "************************************************************************\n"); - abort(); -} - -std::vector ezSAT::vec_const(const std::vector &bits) -{ - std::vector vec; - for (auto bit : bits) - vec.push_back(bit ? CONST_TRUE : CONST_FALSE); - return vec; -} - -std::vector ezSAT::vec_const_signed(int64_t value, int numBits) -{ - std::vector vec; - for (int i = 0; i < numBits; i++) - vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE); - return vec; -} - -std::vector ezSAT::vec_const_unsigned(uint64_t value, int numBits) -{ - std::vector vec; - for (int i = 0; i < numBits; i++) - vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE); - return vec; -} - -std::vector ezSAT::vec_var(int numBits) -{ - std::vector vec; - for (int i = 0; i < numBits; i++) - vec.push_back(literal()); - return vec; -} - -std::vector ezSAT::vec_var(std::string name, int numBits) -{ - std::vector vec; - for (int i = 0; i < numBits; i++) { - vec.push_back(VAR(name + my_int_to_string(i))); - } - return vec; -} - -std::vector ezSAT::vec_cast(const std::vector &vec1, int toBits, bool signExtend) -{ - std::vector vec; - for (int i = 0; i < toBits; i++) - if (i >= int(vec1.size())) - vec.push_back(signExtend ? vec1.back() : CONST_FALSE); - else - vec.push_back(vec1[i]); - return vec; -} - -std::vector ezSAT::vec_not(const std::vector &vec1) -{ - std::vector vec; - for (auto bit : vec1) - vec.push_back(NOT(bit)); - return vec; -} - -std::vector ezSAT::vec_and(const std::vector &vec1, const std::vector &vec2) -{ - assert(vec1.size() == vec2.size()); - std::vector vec(vec1.size()); - for (int i = 0; i < int(vec1.size()); i++) - vec[i] = AND(vec1[i], vec2[i]); - return vec; -} - -std::vector ezSAT::vec_or(const std::vector &vec1, const std::vector &vec2) -{ - assert(vec1.size() == vec2.size()); - std::vector vec(vec1.size()); - for (int i = 0; i < int(vec1.size()); i++) - vec[i] = OR(vec1[i], vec2[i]); - return vec; -} - -std::vector ezSAT::vec_xor(const std::vector &vec1, const std::vector &vec2) -{ - assert(vec1.size() == vec2.size()); - std::vector vec(vec1.size()); - for (int i = 0; i < int(vec1.size()); i++) - vec[i] = XOR(vec1[i], vec2[i]); - return vec; -} - -std::vector ezSAT::vec_iff(const std::vector &vec1, const std::vector &vec2) -{ - assert(vec1.size() == vec2.size()); - std::vector vec(vec1.size()); - for (int i = 0; i < int(vec1.size()); i++) - vec[i] = IFF(vec1[i], vec2[i]); - return vec; -} - -std::vector ezSAT::vec_ite(const std::vector &vec1, const std::vector &vec2, const std::vector &vec3) -{ - assert(vec1.size() == vec2.size() && vec2.size() == vec3.size()); - std::vector vec(vec1.size()); - for (int i = 0; i < int(vec1.size()); i++) - vec[i] = ITE(vec1[i], vec2[i], vec3[i]); - return vec; -} - - -std::vector ezSAT::vec_ite(int sel, const std::vector &vec1, const std::vector &vec2) -{ - assert(vec1.size() == vec2.size()); - std::vector vec(vec1.size()); - for (int i = 0; i < int(vec1.size()); i++) - vec[i] = ITE(sel, vec1[i], vec2[i]); - return vec; -} - -// 'y' is the MSB (carry) and x the LSB (sum) output -static void fulladder(ezSAT *that, int a, int b, int c, int &y, int &x) -{ - int tmp = that->XOR(a, b); - int new_x = that->XOR(tmp, c); - int new_y = that->OR(that->AND(a, b), that->AND(c, tmp)); -#if 0 - printf("FULLADD> a=%s, b=%s, c=%s, carry=%s, sum=%s\n", that->to_string(a).c_str(), that->to_string(b).c_str(), - that->to_string(c).c_str(), that->to_string(new_y).c_str(), that->to_string(new_x).c_str()); -#endif - x = new_x, y = new_y; -} - -// 'y' is the MSB (carry) and x the LSB (sum) output -static void halfadder(ezSAT *that, int a, int b, int &y, int &x) -{ - int new_x = that->XOR(a, b); - int new_y = that->AND(a, b); -#if 0 - printf("HALFADD> a=%s, b=%s, carry=%s, sum=%s\n", that->to_string(a).c_str(), that->to_string(b).c_str(), - that->to_string(new_y).c_str(), that->to_string(new_x).c_str()); -#endif - x = new_x, y = new_y; -} - -std::vector ezSAT::vec_count(const std::vector &vec, int numBits, bool clip) -{ - std::vector sum = vec_const_unsigned(0, numBits); - std::vector carry_vector; - - for (auto bit : vec) { - int carry = bit; - for (int i = 0; i < numBits; i++) - halfadder(this, carry, sum[i], carry, sum[i]); - carry_vector.push_back(carry); - } - - if (clip) { - int overflow = vec_reduce_or(carry_vector); - sum = vec_ite(overflow, vec_const_unsigned(~0, numBits), sum); - } - -#if 0 - printf("COUNT> vec=["); - for (int i = int(vec.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec[i]).c_str(), i ? ", " : ""); - printf("], result=["); - for (int i = int(sum.size())-1; i >= 0; i--) - printf("%s%s", to_string(sum[i]).c_str(), i ? ", " : ""); - printf("]\n"); -#endif - - return sum; -} - -std::vector ezSAT::vec_add(const std::vector &vec1, const std::vector &vec2) -{ - assert(vec1.size() == vec2.size()); - std::vector vec(vec1.size()); - int carry = CONST_FALSE; - for (int i = 0; i < int(vec1.size()); i++) - fulladder(this, vec1[i], vec2[i], carry, carry, vec[i]); - -#if 0 - printf("ADD> vec1=["); - for (int i = int(vec1.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec1[i]).c_str(), i ? ", " : ""); - printf("], vec2=["); - for (int i = int(vec2.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec2[i]).c_str(), i ? ", " : ""); - printf("], result=["); - for (int i = int(vec.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec[i]).c_str(), i ? ", " : ""); - printf("]\n"); -#endif - - return vec; -} - -std::vector ezSAT::vec_sub(const std::vector &vec1, const std::vector &vec2) -{ - assert(vec1.size() == vec2.size()); - std::vector vec(vec1.size()); - int carry = CONST_TRUE; - for (int i = 0; i < int(vec1.size()); i++) - fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, vec[i]); - -#if 0 - printf("SUB> vec1=["); - for (int i = int(vec1.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec1[i]).c_str(), i ? ", " : ""); - printf("], vec2=["); - for (int i = int(vec2.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec2[i]).c_str(), i ? ", " : ""); - printf("], result=["); - for (int i = int(vec.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec[i]).c_str(), i ? ", " : ""); - printf("]\n"); -#endif - - return vec; -} - -std::vector ezSAT::vec_neg(const std::vector &vec) -{ - std::vector zero(vec.size(), CONST_FALSE); - return vec_sub(zero, vec); -} - -void ezSAT::vec_cmp(const std::vector &vec1, const std::vector &vec2, int &carry, int &overflow, int &sign, int &zero) -{ - assert(vec1.size() == vec2.size()); - carry = CONST_TRUE; - zero = CONST_FALSE; - for (int i = 0; i < int(vec1.size()); i++) { - overflow = carry; - fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, sign); - zero = OR(zero, sign); - } - overflow = XOR(overflow, carry); - carry = NOT(carry); - zero = NOT(zero); - -#if 0 - printf("CMP> vec1=["); - for (int i = int(vec1.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec1[i]).c_str(), i ? ", " : ""); - printf("], vec2=["); - for (int i = int(vec2.size())-1; i >= 0; i--) - printf("%s%s", to_string(vec2[i]).c_str(), i ? ", " : ""); - printf("], carry=%s, overflow=%s, sign=%s, zero=%s\n", to_string(carry).c_str(), to_string(overflow).c_str(), to_string(sign).c_str(), to_string(zero).c_str()); -#endif -} - -int ezSAT::vec_lt_signed(const std::vector &vec1, const std::vector &vec2) -{ - int carry, overflow, sign, zero; - vec_cmp(vec1, vec2, carry, overflow, sign, zero); - return OR(AND(NOT(overflow), sign), AND(overflow, NOT(sign))); -} - -int ezSAT::vec_le_signed(const std::vector &vec1, const std::vector &vec2) -{ - int carry, overflow, sign, zero; - vec_cmp(vec1, vec2, carry, overflow, sign, zero); - return OR(AND(NOT(overflow), sign), AND(overflow, NOT(sign)), zero); -} - -int ezSAT::vec_ge_signed(const std::vector &vec1, const std::vector &vec2) -{ - int carry, overflow, sign, zero; - vec_cmp(vec1, vec2, carry, overflow, sign, zero); - return OR(AND(NOT(overflow), NOT(sign)), AND(overflow, sign)); -} - -int ezSAT::vec_gt_signed(const std::vector &vec1, const std::vector &vec2) -{ - int carry, overflow, sign, zero; - vec_cmp(vec1, vec2, carry, overflow, sign, zero); - return AND(OR(AND(NOT(overflow), NOT(sign)), AND(overflow, sign)), NOT(zero)); -} - -int ezSAT::vec_lt_unsigned(const std::vector &vec1, const std::vector &vec2) -{ - int carry, overflow, sign, zero; - vec_cmp(vec1, vec2, carry, overflow, sign, zero); - return carry; -} - -int ezSAT::vec_le_unsigned(const std::vector &vec1, const std::vector &vec2) -{ - int carry, overflow, sign, zero; - vec_cmp(vec1, vec2, carry, overflow, sign, zero); - return OR(carry, zero); -} - -int ezSAT::vec_ge_unsigned(const std::vector &vec1, const std::vector &vec2) -{ - int carry, overflow, sign, zero; - vec_cmp(vec1, vec2, carry, overflow, sign, zero); - return NOT(carry); -} - -int ezSAT::vec_gt_unsigned(const std::vector &vec1, const std::vector &vec2) -{ - int carry, overflow, sign, zero; - vec_cmp(vec1, vec2, carry, overflow, sign, zero); - return AND(NOT(carry), NOT(zero)); -} - -int ezSAT::vec_eq(const std::vector &vec1, const std::vector &vec2) -{ - return vec_reduce_and(vec_iff(vec1, vec2)); -} - -int ezSAT::vec_ne(const std::vector &vec1, const std::vector &vec2) -{ - return NOT(vec_reduce_and(vec_iff(vec1, vec2))); -} - -std::vector ezSAT::vec_shl(const std::vector &vec1, int shift, bool signExtend) -{ - std::vector vec; - for (int i = 0; i < int(vec1.size()); i++) { - int j = i-shift; - if (int(vec1.size()) <= j) - vec.push_back(signExtend ? vec1.back() : CONST_FALSE); - else if (0 <= j) - vec.push_back(vec1[j]); - else - vec.push_back(CONST_FALSE); - } - return vec; -} - -std::vector ezSAT::vec_srl(const std::vector &vec1, int shift) -{ - std::vector vec; - for (int i = 0; i < int(vec1.size()); i++) { - int j = i-shift; - while (j < 0) - j += vec1.size(); - while (j >= int(vec1.size())) - j -= vec1.size(); - vec.push_back(vec1[j]); - } - return vec; -} - -std::vector ezSAT::vec_shift(const std::vector &vec1, int shift, int extend_left, int extend_right) -{ - std::vector vec; - for (int i = 0; i < int(vec1.size()); i++) { - int j = i+shift; - if (j < 0) - vec.push_back(extend_right); - else if (j >= int(vec1.size())) - vec.push_back(extend_left); - else - vec.push_back(vec1[j]); - } - return vec; -} - -static int my_clog2(int x) -{ - int result = 0; - for (x--; x > 0; result++) - x >>= 1; - return result; -} - -std::vector ezSAT::vec_shift_right(const std::vector &vec1, const std::vector &vec2, bool vec2_signed, int extend_left, int extend_right) -{ - int vec2_bits = std::min(my_clog2(vec1.size()) + (vec2_signed ? 1 : 0), int(vec2.size())); - - std::vector overflow_bits(vec2.begin() + vec2_bits, vec2.end()); - int overflow_left = CONST_FALSE, overflow_right = CONST_FALSE; - - if (vec2_signed) { - int overflow = CONST_FALSE; - for (auto bit : overflow_bits) - overflow = OR(overflow, XOR(bit, vec2[vec2_bits-1])); - overflow_left = AND(overflow, NOT(vec2.back())); - overflow_right = AND(overflow, vec2.back()); - } else - overflow_left = vec_reduce_or(overflow_bits); - - std::vector buffer = vec1; - - if (vec2_signed) - while (buffer.size() < vec1.size() + (1 << vec2_bits)) - buffer.push_back(extend_left); - - std::vector overflow_pattern_left(buffer.size(), extend_left); - std::vector overflow_pattern_right(buffer.size(), extend_right); - - buffer = vec_ite(overflow_left, overflow_pattern_left, buffer); - - if (vec2_signed) - buffer = vec_ite(overflow_right, overflow_pattern_left, buffer); - - for (int i = vec2_bits-1; i >= 0; i--) { - std::vector shifted_buffer; - if (vec2_signed && i == vec2_bits-1) - shifted_buffer = vec_shift(buffer, -(1 << i), extend_left, extend_right); - else - shifted_buffer = vec_shift(buffer, 1 << i, extend_left, extend_right); - buffer = vec_ite(vec2[i], shifted_buffer, buffer); - } - - buffer.resize(vec1.size()); - return buffer; -} - -std::vector ezSAT::vec_shift_left(const std::vector &vec1, const std::vector &vec2, bool vec2_signed, int extend_left, int extend_right) -{ - // vec2_signed is not implemented in vec_shift_left() yet - if (vec2_signed) assert(vec2_signed == false); - - int vec2_bits = std::min(my_clog2(vec1.size()), int(vec2.size())); - - std::vector overflow_bits(vec2.begin() + vec2_bits, vec2.end()); - int overflow = vec_reduce_or(overflow_bits); - - std::vector buffer = vec1; - std::vector overflow_pattern_right(buffer.size(), extend_right); - buffer = vec_ite(overflow, overflow_pattern_right, buffer); - - for (int i = 0; i < vec2_bits; i++) { - std::vector shifted_buffer; - shifted_buffer = vec_shift(buffer, -(1 << i), extend_left, extend_right); - buffer = vec_ite(vec2[i], shifted_buffer, buffer); - } - - buffer.resize(vec1.size()); - return buffer; -} - -void ezSAT::vec_append(std::vector &vec, const std::vector &vec1) const -{ - for (auto bit : vec1) - vec.push_back(bit); -} - -void ezSAT::vec_append_signed(std::vector &vec, const std::vector &vec1, int64_t value) -{ - assert(int(vec1.size()) <= 64); - for (int i = 0; i < int(vec1.size()); i++) { - if (((value >> i) & 1) != 0) - vec.push_back(vec1[i]); - else - vec.push_back(NOT(vec1[i])); - } -} - -void ezSAT::vec_append_unsigned(std::vector &vec, const std::vector &vec1, uint64_t value) -{ - assert(int(vec1.size()) <= 64); - for (int i = 0; i < int(vec1.size()); i++) { - if (((value >> i) & 1) != 0) - vec.push_back(vec1[i]); - else - vec.push_back(NOT(vec1[i])); - } -} - -int64_t ezSAT::vec_model_get_signed(const std::vector &modelExpressions, const std::vector &modelValues, const std::vector &vec1) const -{ - int64_t value = 0; - std::map modelMap; - assert(modelExpressions.size() == modelValues.size()); - for (int i = 0; i < int(modelExpressions.size()); i++) - modelMap[modelExpressions[i]] = modelValues[i]; - for (int i = 0; i < 64; i++) { - int j = i < int(vec1.size()) ? i : vec1.size()-1; - if (modelMap.at(vec1[j])) - value |= int64_t(1) << i; - } - return value; -} - -uint64_t ezSAT::vec_model_get_unsigned(const std::vector &modelExpressions, const std::vector &modelValues, const std::vector &vec1) const -{ - uint64_t value = 0; - std::map modelMap; - assert(modelExpressions.size() == modelValues.size()); - for (int i = 0; i < int(modelExpressions.size()); i++) - modelMap[modelExpressions[i]] = modelValues[i]; - for (int i = 0; i < int(vec1.size()); i++) - if (modelMap.at(vec1[i])) - value |= uint64_t(1) << i; - return value; -} - -int ezSAT::vec_reduce_and(const std::vector &vec1) -{ - return expression(OpAnd, vec1); -} - -int ezSAT::vec_reduce_or(const std::vector &vec1) -{ - return expression(OpOr, vec1); -} - -void ezSAT::vec_set(const std::vector &vec1, const std::vector &vec2) -{ - assert(vec1.size() == vec2.size()); - for (int i = 0; i < int(vec1.size()); i++) - SET(vec1[i], vec2[i]); -} - -void ezSAT::vec_set_signed(const std::vector &vec1, int64_t value) -{ - assert(int(vec1.size()) <= 64); - for (int i = 0; i < int(vec1.size()); i++) { - if (((value >> i) & 1) != 0) - assume(vec1[i]); - else - assume(NOT(vec1[i])); - } -} - -void ezSAT::vec_set_unsigned(const std::vector &vec1, uint64_t value) -{ - assert(int(vec1.size()) <= 64); - for (int i = 0; i < int(vec1.size()); i++) { - if (((value >> i) & 1) != 0) - assume(vec1[i]); - else - assume(NOT(vec1[i])); - } -} - -ezSATbit ezSAT::bit(_V a) -{ - return ezSATbit(*this, a); -} - -ezSATvec ezSAT::vec(const std::vector &vec) -{ - return ezSATvec(*this, vec); -} - -void ezSAT::printDIMACS(FILE *f, bool verbose) const -{ - if (cnfConsumed) { - fprintf(stderr, "Usage error: printDIMACS() must not be called after cnfConsumed()!"); - abort(); - } - - int digits = ceil(log10f(cnfVariableCount)) + 2; - - fprintf(f, "c generated by ezSAT\n"); - - if (verbose) - { - fprintf(f, "c\n"); - fprintf(f, "c mapping of variables to literals:\n"); - for (int i = 0; i < int(cnfLiteralVariables.size()); i++) - if (cnfLiteralVariables[i] != 0) - fprintf(f, "c %*d: %s\n", digits, cnfLiteralVariables[i], literals[i].c_str()); - - fprintf(f, "c\n"); - fprintf(f, "c mapping of variables to expressions:\n"); - for (int i = 0; i < int(cnfExpressionVariables.size()); i++) - if (cnfExpressionVariables[i] != 0) - fprintf(f, "c %*d: %d\n", digits, cnfExpressionVariables[i], -i-1); - - if (mode_keep_cnf()) { - fprintf(f, "c\n"); - fprintf(f, "c %d clauses from backup, %d from current buffer\n", - int(cnfClausesBackup.size()), int(cnfClauses.size())); - } - - fprintf(f, "c\n"); - } - - std::vector> all_clauses; - getFullCnf(all_clauses); - assert(cnfClausesCount == int(all_clauses.size())); - - fprintf(f, "p cnf %d %d\n", cnfVariableCount, cnfClausesCount); - int maxClauseLen = 0; - for (auto &clause : all_clauses) - maxClauseLen = std::max(int(clause.size()), maxClauseLen); - if (!verbose) - maxClauseLen = std::min(maxClauseLen, 3); - for (auto &clause : all_clauses) { - for (auto idx : clause) - fprintf(f, " %*d", digits, idx); - if (maxClauseLen >= int(clause.size())) - fprintf(f, " %*d\n", (digits + 1)*int(maxClauseLen - clause.size()) + digits, 0); - else - fprintf(f, " %*d\n", digits, 0); - } -} - -static std::string expression2str(const std::pair> &data) -{ - std::string text; - switch (data.first) { -#define X(op) case ezSAT::op: text += #op; break; - X(OpNot) - X(OpAnd) - X(OpOr) - X(OpXor) - X(OpIFF) - X(OpITE) - default: - abort(); -#undef X - } - text += ":"; - for (auto it : data.second) - text += " " + my_int_to_string(it); - return text; -} - -void ezSAT::printInternalState(FILE *f) const -{ - fprintf(f, "--8<-- snip --8<--\n"); - - fprintf(f, "literalsCache:\n"); - for (auto &it : literalsCache) - fprintf(f, " `%s' -> %d\n", it.first.c_str(), it.second); - - fprintf(f, "literals:\n"); - for (int i = 0; i < int(literals.size()); i++) - fprintf(f, " %d: `%s'\n", i+1, literals[i].c_str()); - - fprintf(f, "expressionsCache:\n"); - for (auto &it : expressionsCache) - fprintf(f, " `%s' -> %d\n", expression2str(it.first).c_str(), it.second); - - fprintf(f, "expressions:\n"); - for (int i = 0; i < int(expressions.size()); i++) - fprintf(f, " %d: `%s'\n", -i-1, expression2str(expressions[i]).c_str()); - - fprintf(f, "cnfVariables (count=%d):\n", cnfVariableCount); - for (int i = 0; i < int(cnfLiteralVariables.size()); i++) - if (cnfLiteralVariables[i] != 0) - fprintf(f, " literal %d -> %d (%s)\n", i+1, cnfLiteralVariables[i], to_string(i+1).c_str()); - for (int i = 0; i < int(cnfExpressionVariables.size()); i++) - if (cnfExpressionVariables[i] != 0) - fprintf(f, " expression %d -> %d (%s)\n", -i-1, cnfExpressionVariables[i], to_string(-i-1).c_str()); - - fprintf(f, "cnfClauses:\n"); - for (auto &i1 : cnfClauses) { - for (auto &i2 : i1) - fprintf(f, " %4d", i2); - fprintf(f, "\n"); - } - if (cnfConsumed) - fprintf(f, " *** more clauses consumed via cnfConsume() ***\n"); - - fprintf(f, "--8<-- snap --8<--\n"); -} - -static int clog2(int x) -{ - int y = (x & (x - 1)); - y = (y | -y) >> 31; - - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - - x >>= 1; - x -= ((x >> 1) & 0x55555555); - x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); - x = (((x >> 4) + x) & 0x0f0f0f0f); - x += (x >> 8); - x += (x >> 16); - x = x & 0x0000003f; - - return x - y; -} - -int ezSAT::onehot(const std::vector &vec, bool max_only) -{ - // Mixed one-hot/binary encoding as described by Claessen in Sec. 4.2 of - // "Successful SAT Encoding Techniques. Magnus Bjiirk. 25th July 2009". - // http://jsat.ewi.tudelft.nl/addendum/Bjork_encoding.pdf - - std::vector formula; - - // add at-leat-one constraint - if (max_only == false) - formula.push_back(expression(OpOr, vec)); - - // create binary vector - int num_bits = clog2(vec.size()); - std::vector bits; - for (int k = 0; k < num_bits; k++) - bits.push_back(literal()); - - // add at-most-one clauses using binary encoding - for (size_t i = 0; i < vec.size(); i++) - for (int k = 0; k < num_bits; k++) { - std::vector clause; - clause.push_back(NOT(vec[i])); - clause.push_back((i & (1 << k)) != 0 ? bits[k] : NOT(bits[k])); - formula.push_back(expression(OpOr, clause)); - } - - return expression(OpAnd, formula); -} - -int ezSAT::manyhot(const std::vector &vec, int min_hot, int max_hot) -{ - // many-hot encoding using a simple sorting network - - if (max_hot < 0) - max_hot = min_hot; - - std::vector formula; - int M = max_hot+1, N = vec.size(); - std::map, int> x; - - for (int i = -1; i < N; i++) - for (int j = -1; j < M; j++) - x[std::pair(i,j)] = j < 0 ? CONST_TRUE : i < 0 ? CONST_FALSE : literal(); - - for (int i = 0; i < N; i++) - for (int j = 0; j < M; j++) { - formula.push_back(OR(NOT(vec[i]), x[std::pair(i-1,j-1)], NOT(x[std::pair(i,j)]))); - formula.push_back(OR(NOT(vec[i]), NOT(x[std::pair(i-1,j-1)]), x[std::pair(i,j)])); - formula.push_back(OR(vec[i], x[std::pair(i-1,j)], NOT(x[std::pair(i,j)]))); - formula.push_back(OR(vec[i], NOT(x[std::pair(i-1,j)]), x[std::pair(i,j)])); -#if 0 - // explicit resolution clauses -- in tests it was better to let the sat solver figure those out - formula.push_back(OR(NOT(x[std::pair(i-1,j-1)]), NOT(x[std::pair(i-1,j)]), x[std::pair(i,j)])); - formula.push_back(OR(x[std::pair(i-1,j-1)], x[std::pair(i-1,j)], NOT(x[std::pair(i,j)]))); -#endif - } - - for (int j = 0; j < M; j++) { - if (j+1 <= min_hot) - formula.push_back(x[std::pair(N-1,j)]); - else if (j+1 > max_hot) - formula.push_back(NOT(x[std::pair(N-1,j)])); - } - - return expression(OpAnd, formula); -} - -int ezSAT::ordered(const std::vector &vec1, const std::vector &vec2, bool allow_equal) -{ - std::vector formula; - int last_x = CONST_FALSE; - - assert(vec1.size() == vec2.size()); - for (size_t i = 0; i < vec1.size(); i++) - { - int a = vec1[i], b = vec2[i]; - formula.push_back(OR(NOT(a), b, last_x)); - - int next_x = i+1 < vec1.size() ? literal() : allow_equal ? CONST_FALSE : CONST_TRUE; - formula.push_back(OR(a, b, last_x, NOT(next_x))); - formula.push_back(OR(NOT(a), NOT(b), last_x, NOT(next_x))); - last_x = next_x; - } - - return expression(OpAnd, formula); -} - diff --git a/yosys/libs/ezsat/ezsat.h b/yosys/libs/ezsat/ezsat.h deleted file mode 100644 index 85b13685f..000000000 --- a/yosys/libs/ezsat/ezsat.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef EZSAT_H -#define EZSAT_H - -#include -#include -#include -#include -#include -#include - -class ezSAT -{ - // each token (terminal or non-terminal) is represented by an integer number - // - // the zero token: - // the number zero is not used as valid token number and is used to encode - // unused parameters for the functions. - // - // positive numbers are literals, with 1 = CONST_TRUE and 2 = CONST_FALSE; - // - // negative numbers are non-literal expressions. each expression is represented - // by an operator id and a list of expressions (literals or non-literals). - -public: - enum OpId { - OpNot, OpAnd, OpOr, OpXor, OpIFF, OpITE - }; - - static const int CONST_TRUE; - static const int CONST_FALSE; - -private: - bool flag_keep_cnf; - bool flag_non_incremental; - - bool non_incremental_solve_used_up; - - std::map literalsCache; - std::vector literals; - - std::map>, int> expressionsCache; - std::vector>> expressions; - - bool cnfConsumed; - int cnfVariableCount, cnfClausesCount; - std::vector cnfLiteralVariables, cnfExpressionVariables; - std::vector> cnfClauses, cnfClausesBackup; - - void add_clause(const std::vector &args); - void add_clause(const std::vector &args, bool argsPolarity, int a = 0, int b = 0, int c = 0); - void add_clause(int a, int b = 0, int c = 0); - - int bind_cnf_not(const std::vector &args); - int bind_cnf_and(const std::vector &args); - int bind_cnf_or(const std::vector &args); - -protected: - void preSolverCallback(); - -public: - int solverTimeout; - bool solverTimoutStatus; - - ezSAT(); - virtual ~ezSAT(); - - unsigned int statehash; - void addhash(unsigned int); - - void keep_cnf() { flag_keep_cnf = true; } - void non_incremental() { flag_non_incremental = true; } - - bool mode_keep_cnf() const { return flag_keep_cnf; } - bool mode_non_incremental() const { return flag_non_incremental; } - - // manage expressions - - int value(bool val); - int literal(); - int literal(const std::string &name); - int frozen_literal(); - int frozen_literal(const std::string &name); - int expression(OpId op, int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0); - int expression(OpId op, const std::vector &args); - - void lookup_literal(int id, std::string &name) const; - const std::string &lookup_literal(int id) const; - - void lookup_expression(int id, OpId &op, std::vector &args) const; - const std::vector &lookup_expression(int id, OpId &op) const; - - int parse_string(const std::string &text); - std::string to_string(int id) const; - - int numLiterals() const { return literals.size(); } - int numExpressions() const { return expressions.size(); } - - int eval(int id, const std::vector &values) const; - - // SAT solver interface - // If you are planning on using the solver API (and not simply create a CNF) you must use a child class - // of ezSAT that actually implements a solver backend, such as ezMiniSAT (see ezminisat.h). - - virtual bool solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions); - - bool solve(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) { - return solver(modelExpressions, modelValues, assumptions); - } - - bool solve(const std::vector &modelExpressions, std::vector &modelValues, int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0) { - std::vector assumptions; - if (a != 0) assumptions.push_back(a); - if (b != 0) assumptions.push_back(b); - if (c != 0) assumptions.push_back(c); - if (d != 0) assumptions.push_back(d); - if (e != 0) assumptions.push_back(e); - if (f != 0) assumptions.push_back(f); - return solver(modelExpressions, modelValues, assumptions); - } - - bool solve(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0) { - std::vector assumptions, modelExpressions; - std::vector modelValues; - if (a != 0) assumptions.push_back(a); - if (b != 0) assumptions.push_back(b); - if (c != 0) assumptions.push_back(c); - if (d != 0) assumptions.push_back(d); - if (e != 0) assumptions.push_back(e); - if (f != 0) assumptions.push_back(f); - return solver(modelExpressions, modelValues, assumptions); - } - - void setSolverTimeout(int newTimeoutSeconds) { - solverTimeout = newTimeoutSeconds; - } - - bool getSolverTimoutStatus() { - return solverTimoutStatus; - } - - // manage CNF (usually only accessed by SAT solvers) - - virtual void clear(); - virtual void freeze(int id); - virtual bool eliminated(int idx); - void assume(int id); - void assume(int id, int context_id) { assume(OR(id, NOT(context_id))); } - int bind(int id, bool auto_freeze = true); - int bound(int id) const; - - int numCnfVariables() const { return cnfVariableCount; } - int numCnfClauses() const { return cnfClausesCount; } - const std::vector> &cnf() const { return cnfClauses; } - - void consumeCnf(); - void consumeCnf(std::vector> &cnf); - - // use this function to get the full CNF in keep_cnf mode - void getFullCnf(std::vector> &full_cnf) const; - - std::string cnfLiteralInfo(int idx) const; - - // simple helpers for build expressions easily - - struct _V { - int id; - std::string name; - _V(int id) : id(id) { } - _V(const char *name) : id(0), name(name) { } - _V(const std::string &name) : id(0), name(name) { } - int get(ezSAT *that) { - if (name.empty()) - return id; - return that->frozen_literal(name); - } - }; - - int VAR(_V a) { - return a.get(this); - } - - int NOT(_V a) { - return expression(OpNot, a.get(this)); - } - - int AND(_V a = 0, _V b = 0, _V c = 0, _V d = 0, _V e = 0, _V f = 0) { - return expression(OpAnd, a.get(this), b.get(this), c.get(this), d.get(this), e.get(this), f.get(this)); - } - - int OR(_V a = 0, _V b = 0, _V c = 0, _V d = 0, _V e = 0, _V f = 0) { - return expression(OpOr, a.get(this), b.get(this), c.get(this), d.get(this), e.get(this), f.get(this)); - } - - int XOR(_V a = 0, _V b = 0, _V c = 0, _V d = 0, _V e = 0, _V f = 0) { - return expression(OpXor, a.get(this), b.get(this), c.get(this), d.get(this), e.get(this), f.get(this)); - } - - int IFF(_V a, _V b = 0, _V c = 0, _V d = 0, _V e = 0, _V f = 0) { - return expression(OpIFF, a.get(this), b.get(this), c.get(this), d.get(this), e.get(this), f.get(this)); - } - - int ITE(_V a, _V b, _V c) { - return expression(OpITE, a.get(this), b.get(this), c.get(this)); - } - - void SET(_V a, _V b) { - assume(IFF(a.get(this), b.get(this))); - } - - // simple helpers for building expressions with bit vectors - - std::vector vec_const(const std::vector &bits); - std::vector vec_const_signed(int64_t value, int numBits); - std::vector vec_const_unsigned(uint64_t value, int numBits); - std::vector vec_var(int numBits); - std::vector vec_var(std::string name, int numBits); - std::vector vec_cast(const std::vector &vec1, int toBits, bool signExtend = false); - - std::vector vec_not(const std::vector &vec1); - std::vector vec_and(const std::vector &vec1, const std::vector &vec2); - std::vector vec_or(const std::vector &vec1, const std::vector &vec2); - std::vector vec_xor(const std::vector &vec1, const std::vector &vec2); - - std::vector vec_iff(const std::vector &vec1, const std::vector &vec2); - std::vector vec_ite(const std::vector &vec1, const std::vector &vec2, const std::vector &vec3); - std::vector vec_ite(int sel, const std::vector &vec1, const std::vector &vec2); - - std::vector vec_count(const std::vector &vec, int numBits, bool clip = true); - std::vector vec_add(const std::vector &vec1, const std::vector &vec2); - std::vector vec_sub(const std::vector &vec1, const std::vector &vec2); - std::vector vec_neg(const std::vector &vec); - - void vec_cmp(const std::vector &vec1, const std::vector &vec2, int &carry, int &overflow, int &sign, int &zero); - - int vec_lt_signed(const std::vector &vec1, const std::vector &vec2); - int vec_le_signed(const std::vector &vec1, const std::vector &vec2); - int vec_ge_signed(const std::vector &vec1, const std::vector &vec2); - int vec_gt_signed(const std::vector &vec1, const std::vector &vec2); - - int vec_lt_unsigned(const std::vector &vec1, const std::vector &vec2); - int vec_le_unsigned(const std::vector &vec1, const std::vector &vec2); - int vec_ge_unsigned(const std::vector &vec1, const std::vector &vec2); - int vec_gt_unsigned(const std::vector &vec1, const std::vector &vec2); - - int vec_eq(const std::vector &vec1, const std::vector &vec2); - int vec_ne(const std::vector &vec1, const std::vector &vec2); - - std::vector vec_shl(const std::vector &vec1, int shift, bool signExtend = false); - std::vector vec_srl(const std::vector &vec1, int shift); - - std::vector vec_shr(const std::vector &vec1, int shift, bool signExtend = false) { return vec_shl(vec1, -shift, signExtend); } - std::vector vec_srr(const std::vector &vec1, int shift) { return vec_srl(vec1, -shift); } - - std::vector vec_shift(const std::vector &vec1, int shift, int extend_left, int extend_right); - std::vector vec_shift_right(const std::vector &vec1, const std::vector &vec2, bool vec2_signed, int extend_left, int extend_right); - std::vector vec_shift_left(const std::vector &vec1, const std::vector &vec2, bool vec2_signed, int extend_left, int extend_right); - - void vec_append(std::vector &vec, const std::vector &vec1) const; - void vec_append_signed(std::vector &vec, const std::vector &vec1, int64_t value); - void vec_append_unsigned(std::vector &vec, const std::vector &vec1, uint64_t value); - - int64_t vec_model_get_signed(const std::vector &modelExpressions, const std::vector &modelValues, const std::vector &vec1) const; - uint64_t vec_model_get_unsigned(const std::vector &modelExpressions, const std::vector &modelValues, const std::vector &vec1) const; - - int vec_reduce_and(const std::vector &vec1); - int vec_reduce_or(const std::vector &vec1); - - void vec_set(const std::vector &vec1, const std::vector &vec2); - void vec_set_signed(const std::vector &vec1, int64_t value); - void vec_set_unsigned(const std::vector &vec1, uint64_t value); - - // helpers for generating ezSATbit and ezSATvec objects - - struct ezSATbit bit(_V a); - struct ezSATvec vec(const std::vector &vec); - - // printing CNF and internal state - - void printDIMACS(FILE *f, bool verbose = false) const; - void printInternalState(FILE *f) const; - - // more sophisticated constraints (designed to be used directly with assume(..)) - - int onehot(const std::vector &vec, bool max_only = false); - int manyhot(const std::vector &vec, int min_hot, int max_hot = -1); - int ordered(const std::vector &vec1, const std::vector &vec2, bool allow_equal = true); -}; - -// helper classes for using operator overloading when generating complex expressions - -struct ezSATbit -{ - ezSAT &sat; - int id; - - ezSATbit(ezSAT &sat, ezSAT::_V a) : sat(sat), id(sat.VAR(a)) { } - - ezSATbit operator ~() { return ezSATbit(sat, sat.NOT(id)); } - ezSATbit operator &(const ezSATbit &other) { return ezSATbit(sat, sat.AND(id, other.id)); } - ezSATbit operator |(const ezSATbit &other) { return ezSATbit(sat, sat.OR(id, other.id)); } - ezSATbit operator ^(const ezSATbit &other) { return ezSATbit(sat, sat.XOR(id, other.id)); } - ezSATbit operator ==(const ezSATbit &other) { return ezSATbit(sat, sat.IFF(id, other.id)); } - ezSATbit operator !=(const ezSATbit &other) { return ezSATbit(sat, sat.NOT(sat.IFF(id, other.id))); } - - operator int() const { return id; } - operator ezSAT::_V() const { return ezSAT::_V(id); } - operator std::vector() const { return std::vector(1, id); } -}; - -struct ezSATvec -{ - ezSAT &sat; - std::vector vec; - - ezSATvec(ezSAT &sat, const std::vector &vec) : sat(sat), vec(vec) { } - - ezSATvec operator ~() { return ezSATvec(sat, sat.vec_not(vec)); } - ezSATvec operator -() { return ezSATvec(sat, sat.vec_neg(vec)); } - - ezSATvec operator &(const ezSATvec &other) { return ezSATvec(sat, sat.vec_and(vec, other.vec)); } - ezSATvec operator |(const ezSATvec &other) { return ezSATvec(sat, sat.vec_or(vec, other.vec)); } - ezSATvec operator ^(const ezSATvec &other) { return ezSATvec(sat, sat.vec_xor(vec, other.vec)); } - - ezSATvec operator +(const ezSATvec &other) { return ezSATvec(sat, sat.vec_add(vec, other.vec)); } - ezSATvec operator -(const ezSATvec &other) { return ezSATvec(sat, sat.vec_sub(vec, other.vec)); } - - ezSATbit operator < (const ezSATvec &other) { return ezSATbit(sat, sat.vec_lt_unsigned(vec, other.vec)); } - ezSATbit operator <=(const ezSATvec &other) { return ezSATbit(sat, sat.vec_le_unsigned(vec, other.vec)); } - ezSATbit operator ==(const ezSATvec &other) { return ezSATbit(sat, sat.vec_eq(vec, other.vec)); } - ezSATbit operator !=(const ezSATvec &other) { return ezSATbit(sat, sat.vec_ne(vec, other.vec)); } - ezSATbit operator >=(const ezSATvec &other) { return ezSATbit(sat, sat.vec_ge_unsigned(vec, other.vec)); } - ezSATbit operator > (const ezSATvec &other) { return ezSATbit(sat, sat.vec_gt_unsigned(vec, other.vec)); } - - ezSATvec operator <<(int shift) { return ezSATvec(sat, sat.vec_shl(vec, shift)); } - ezSATvec operator >>(int shift) { return ezSATvec(sat, sat.vec_shr(vec, shift)); } - - operator std::vector() const { return vec; } -}; - -#endif diff --git a/yosys/libs/ezsat/puzzle3d.cc b/yosys/libs/ezsat/puzzle3d.cc deleted file mode 100644 index 59f840f9e..000000000 --- a/yosys/libs/ezsat/puzzle3d.cc +++ /dev/null @@ -1,295 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "ezminisat.h" -#include -#include - -#define DIM_X 5 -#define DIM_Y 5 -#define DIM_Z 5 - -#define NUM_124 6 -#define NUM_223 6 - -ezMiniSAT ez; -int blockidx = 0; -std::map blockinfo; -std::vector grid[DIM_X][DIM_Y][DIM_Z]; - -struct blockgeom_t -{ - int center_x, center_y, center_z; - int size_x, size_y, size_z; - int var; - - void mirror_x() { center_x *= -1; } - void mirror_y() { center_y *= -1; } - void mirror_z() { center_z *= -1; } - - void rotate_x() { int tmp[4] = { center_y, center_z, size_y, size_z }; center_y = tmp[1]; center_z = -tmp[0]; size_y = tmp[3]; size_z = tmp[2]; } - void rotate_y() { int tmp[4] = { center_x, center_z, size_x, size_z }; center_x = tmp[1]; center_z = -tmp[0]; size_x = tmp[3]; size_z = tmp[2]; } - void rotate_z() { int tmp[4] = { center_x, center_y, size_x, size_y }; center_x = tmp[1]; center_y = -tmp[0]; size_x = tmp[3]; size_y = tmp[2]; } - - bool operator< (const blockgeom_t &other) const { - if (center_x != other.center_x) return center_x < other.center_x; - if (center_y != other.center_y) return center_y < other.center_y; - if (center_z != other.center_z) return center_z < other.center_z; - if (size_x != other.size_x) return size_x < other.size_x; - if (size_y != other.size_y) return size_y < other.size_y; - if (size_z != other.size_z) return size_z < other.size_z; - if (var != other.var) return var < other.var; - return false; - } -}; - -// geometry data for spatial symmetry constraints -std::set blockgeom; - -int add_block(int pos_x, int pos_y, int pos_z, int size_x, int size_y, int size_z, int blockidx) -{ - char buffer[1024]; - snprintf(buffer, 1024, "block(%d,%d,%d,%d,%d,%d,%d);", size_x, size_y, size_z, pos_x, pos_y, pos_z, blockidx); - - int var = ez.literal(); - blockinfo[var] = buffer; - - for (int ix = pos_x; ix < pos_x+size_x; ix++) - for (int iy = pos_y; iy < pos_y+size_y; iy++) - for (int iz = pos_z; iz < pos_z+size_z; iz++) - grid[ix][iy][iz].push_back(var); - - blockgeom_t bg; - bg.size_x = 2*size_x; - bg.size_y = 2*size_y; - bg.size_z = 2*size_z; - bg.center_x = (2*pos_x + size_x) - DIM_X; - bg.center_y = (2*pos_y + size_y) - DIM_Y; - bg.center_z = (2*pos_z + size_z) - DIM_Z; - bg.var = var; - - assert(blockgeom.count(bg) == 0); - blockgeom.insert(bg); - - return var; -} - -void add_block_positions_124(std::vector &block_positions_124) -{ - block_positions_124.clear(); - for (int size_x = 1; size_x <= 4; size_x *= 2) - for (int size_y = 1; size_y <= 4; size_y *= 2) - for (int size_z = 1; size_z <= 4; size_z *= 2) { - if (size_x == size_y || size_y == size_z || size_z == size_x) - continue; - for (int ix = 0; ix <= DIM_X-size_x; ix++) - for (int iy = 0; iy <= DIM_Y-size_y; iy++) - for (int iz = 0; iz <= DIM_Z-size_z; iz++) - block_positions_124.push_back(add_block(ix, iy, iz, size_x, size_y, size_z, blockidx++)); - } -} - -void add_block_positions_223(std::vector &block_positions_223) -{ - block_positions_223.clear(); - for (int orientation = 0; orientation < 3; orientation++) { - int size_x = orientation == 0 ? 3 : 2; - int size_y = orientation == 1 ? 3 : 2; - int size_z = orientation == 2 ? 3 : 2; - for (int ix = 0; ix <= DIM_X-size_x; ix++) - for (int iy = 0; iy <= DIM_Y-size_y; iy++) - for (int iz = 0; iz <= DIM_Z-size_z; iz++) - block_positions_223.push_back(add_block(ix, iy, iz, size_x, size_y, size_z, blockidx++)); - } -} - -// use simple built-in random number generator to -// ensure determinism of the program across platforms -uint32_t xorshift32() { - static uint32_t x = 314159265; - x ^= x << 13; - x ^= x >> 17; - x ^= x << 5; - return x; -} - -void condense_exclusives(std::vector &vars) -{ - std::map> exclusive; - - for (int ix = 0; ix < DIM_X; ix++) - for (int iy = 0; iy < DIM_Y; iy++) - for (int iz = 0; iz < DIM_Z; iz++) { - for (int a : grid[ix][iy][iz]) - for (int b : grid[ix][iy][iz]) - if (a != b) - exclusive[a].insert(b); - } - - std::vector> pools; - - for (int a : vars) - { - std::vector candidate_pools; - for (size_t i = 0; i < pools.size(); i++) - { - for (int b : pools[i]) - if (exclusive[a].count(b) == 0) - goto no_candidate_pool; - candidate_pools.push_back(i); - no_candidate_pool:; - } - - if (candidate_pools.size() > 0) { - int p = candidate_pools[xorshift32() % candidate_pools.size()]; - pools[p].push_back(a); - } else { - pools.push_back(std::vector()); - pools.back().push_back(a); - } - } - - std::vector new_vars; - for (auto &pool : pools) - { - std::vector formula; - int var = ez.literal(); - - for (int a : pool) - formula.push_back(ez.OR(ez.NOT(a), var)); - formula.push_back(ez.OR(ez.expression(ezSAT::OpOr, pool), ez.NOT(var))); - - ez.assume(ez.onehot(pool, true)); - ez.assume(ez.expression(ezSAT::OpAnd, formula)); - new_vars.push_back(var); - } - - printf("Condensed %d variables into %d one-hot pools.\n", int(vars.size()), int(new_vars.size())); - vars.swap(new_vars); -} - -int main() -{ - printf("\nCreating SAT encoding..\n"); - - // add 1x2x4 blocks - std::vector block_positions_124; - add_block_positions_124(block_positions_124); - condense_exclusives(block_positions_124); - ez.assume(ez.manyhot(block_positions_124, NUM_124)); - - // add 2x2x3 blocks - std::vector block_positions_223; - add_block_positions_223(block_positions_223); - condense_exclusives(block_positions_223); - ez.assume(ez.manyhot(block_positions_223, NUM_223)); - - // add constraint for max one block per grid element - for (int ix = 0; ix < DIM_X; ix++) - for (int iy = 0; iy < DIM_Y; iy++) - for (int iz = 0; iz < DIM_Z; iz++) { - assert(grid[ix][iy][iz].size() > 0); - ez.assume(ez.onehot(grid[ix][iy][iz], true)); - } - - printf("Found %d possible block positions.\n", int(blockgeom.size())); - - // look for spatial symmetries - std::set> symmetries; - symmetries.insert(blockgeom); - bool keep_running = true; - while (keep_running) { - keep_running = false; - std::set> old_sym; - old_sym.swap(symmetries); - for (auto &old_sym_set : old_sym) - { - std::set mx, my, mz; - std::set rx, ry, rz; - for (auto &bg : old_sym_set) { - blockgeom_t bg_mx = bg, bg_my = bg, bg_mz = bg; - blockgeom_t bg_rx = bg, bg_ry = bg, bg_rz = bg; - bg_mx.mirror_x(), bg_my.mirror_y(), bg_mz.mirror_z(); - bg_rx.rotate_x(), bg_ry.rotate_y(), bg_rz.rotate_z(); - mx.insert(bg_mx), my.insert(bg_my), mz.insert(bg_mz); - rx.insert(bg_rx), ry.insert(bg_ry), rz.insert(bg_rz); - } - if (!old_sym.count(mx) || !old_sym.count(my) || !old_sym.count(mz) || - !old_sym.count(rx) || !old_sym.count(ry) || !old_sym.count(rz)) - keep_running = true; - symmetries.insert(old_sym_set); - symmetries.insert(mx); - symmetries.insert(my); - symmetries.insert(mz); - symmetries.insert(rx); - symmetries.insert(ry); - symmetries.insert(rz); - } - } - - // add constraints to eliminate all the spatial symmetries - std::vector> vecvec; - for (auto &sym : symmetries) { - std::vector vec; - for (auto &bg : sym) - vec.push_back(bg.var); - vecvec.push_back(vec); - } - for (size_t i = 1; i < vecvec.size(); i++) - ez.assume(ez.ordered(vecvec[0], vecvec[1])); - - printf("Found and eliminated %d spatial symmetries.\n", int(symmetries.size())); - printf("Generated %d clauses over %d variables.\n", ez.numCnfClauses(), ez.numCnfVariables()); - - std::vector modelExpressions; - std::vector modelValues; - - for (auto &it : blockinfo) { - ez.freeze(it.first); - modelExpressions.push_back(it.first); - } - - int solution_counter = 0; - while (1) - { - printf("\nSolving puzzle..\n"); - bool ok = ez.solve(modelExpressions, modelValues); - - if (!ok) { - printf("No more solutions found!\n"); - break; - } - - printf("Puzzle solution:\n"); - std::vector constraint; - for (size_t i = 0; i < modelExpressions.size(); i++) - if (modelValues[i]) { - constraint.push_back(ez.NOT(modelExpressions[i])); - printf("%s\n", blockinfo.at(modelExpressions[i]).c_str()); - } - ez.assume(ez.expression(ezSAT::OpOr, constraint)); - solution_counter++; - } - - printf("\nFound %d distinct solutions.\n", solution_counter); - printf("Have a nice day.\n\n"); - - return 0; -} - diff --git a/yosys/libs/ezsat/puzzle3d.scad b/yosys/libs/ezsat/puzzle3d.scad deleted file mode 100644 index 693f8d853..000000000 --- a/yosys/libs/ezsat/puzzle3d.scad +++ /dev/null @@ -1,82 +0,0 @@ - -gap = 30; -layers = 0; -variant = 1; - -module block(size_x, size_y, size_z, pos_x, pos_y, pos_z, idx) -{ - col = idx % 6 == 0 ? [ 0, 0, 1 ] : - idx % 6 == 1 ? [ 0, 1, 0 ] : - idx % 6 == 2 ? [ 0, 1, 1 ] : - idx % 6 == 3 ? [ 1, 0, 0 ] : - idx % 6 == 4 ? [ 1, 0, 1 ] : - idx % 6 == 5 ? [ 1, 1, 0 ] : [ 0, 0, 0 ]; - translate([-2.5, -2.5, 0] * (100+gap)) difference() { - color(col) translate([pos_x, pos_y, pos_z] * (100 + gap)) - cube([size_x, size_y, size_z] * (100+gap) - [gap, gap, gap], false); - if (layers > 0) - color([0.3, 0.3, 0.3]) translate([0, 0, layers * (100+gap)] - [0.5, 0.5, 0.5] * gap) - cube([5, 5, 5] * (100 + gap), false); - } -} - -if (variant == 1) { - block(1,4,2,0,1,3,47); - block(1,4,2,4,0,0,72); - block(2,1,4,0,0,0,80); - block(2,1,4,3,4,1,119); - block(4,2,1,0,3,0,215); - block(4,2,1,1,0,4,224); - block(3,2,2,0,3,1,253); - block(3,2,2,2,0,2,274); - block(2,3,2,1,2,3,311); - block(2,3,2,2,0,0,312); - block(2,2,3,0,1,0,339); - block(2,2,3,3,2,2,380); -} - -if (variant == 2) { - block(1,2,4,0,0,1,1); - block(1,2,4,4,3,0,38); - block(2,4,1,0,1,0,125); - block(2,4,1,3,0,4,154); - block(4,1,2,0,4,3,179); - block(4,1,2,1,0,0,180); - block(3,2,2,0,2,3,251); - block(3,2,2,2,1,0,276); - block(2,3,2,0,2,1,297); - block(2,3,2,3,0,2,326); - block(2,2,3,1,0,2,350); - block(2,2,3,2,3,0,369); -} - -if (variant == 3) { - block(1,4,2,0,0,3,43); - block(1,4,2,4,1,0,76); - block(2,1,4,0,4,0,88); - block(2,1,4,3,0,1,111); - block(4,2,1,0,0,0,200); - block(4,2,1,1,3,4,239); - block(3,2,2,0,0,1,241); - block(3,2,2,2,3,2,286); - block(2,3,2,1,0,3,303); - block(2,3,2,2,2,0,320); - block(2,2,3,0,2,0,342); - block(2,2,3,3,1,2,377); -} - -if (variant == 4) { - block(1,2,4,0,3,1,7); - block(1,2,4,4,0,0,32); - block(2,4,1,0,0,0,120); - block(2,4,1,3,1,4,159); - block(4,1,2,0,0,3,163); - block(4,1,2,1,4,0,196); - block(3,2,2,0,1,3,247); - block(3,2,2,2,2,0,280); - block(2,3,2,0,0,1,289); - block(2,3,2,3,2,2,334); - block(2,2,3,1,3,2,359); - block(2,2,3,2,0,0,360); -} - diff --git a/yosys/libs/ezsat/testbench.cc b/yosys/libs/ezsat/testbench.cc deleted file mode 100644 index d6dc41fa9..000000000 --- a/yosys/libs/ezsat/testbench.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "ezminisat.h" -#include - -struct xorshift128 { - uint32_t x, y, z, w; - xorshift128() { - x = 123456789; - y = 362436069; - z = 521288629; - w = 88675123; - } - uint32_t operator()() { - uint32_t t = x ^ (x << 11); - x = y; y = z; z = w; - w ^= (w >> 19) ^ t ^ (t >> 8); - return w; - } -}; - -bool test(ezSAT &sat, int assumption = 0) -{ - std::vector modelExpressions; - std::vector modelValues; - - for (int id = 1; id <= sat.numLiterals(); id++) - if (sat.bound(id)) - modelExpressions.push_back(id); - - if (sat.solve(modelExpressions, modelValues, assumption)) { - printf("satisfiable:"); - for (int i = 0; i < int(modelExpressions.size()); i++) - printf(" %s=%d", sat.to_string(modelExpressions[i]).c_str(), int(modelValues[i])); - printf("\n\n"); - return true; - } else { - printf("not satisfiable.\n\n"); - return false; - } -} - -// ------------------------------------------------------------------------------------------------------------ - -void test_simple() -{ - printf("==== %s ====\n\n", __PRETTY_FUNCTION__); - - ezMiniSAT sat; - sat.non_incremental(); - sat.assume(sat.OR("A", "B")); - sat.assume(sat.NOT(sat.AND("A", "B"))); - test(sat); -} - -// ------------------------------------------------------------------------------------------------------------ - -void test_xorshift32_try(ezSAT &sat, uint32_t input_pattern) -{ - uint32_t output_pattern = input_pattern; - output_pattern ^= output_pattern << 13; - output_pattern ^= output_pattern >> 17; - output_pattern ^= output_pattern << 5; - - std::vector modelExpressions; - std::vector forwardAssumptions, backwardAssumptions; - std::vector forwardModel, backwardModel; - - sat.vec_append(modelExpressions, sat.vec_var("i", 32)); - sat.vec_append(modelExpressions, sat.vec_var("o", 32)); - - sat.vec_append_unsigned(forwardAssumptions, sat.vec_var("i", 32), input_pattern); - sat.vec_append_unsigned(backwardAssumptions, sat.vec_var("o", 32), output_pattern); - - if (!sat.solve(modelExpressions, backwardModel, backwardAssumptions)) { - printf("backward solving failed!\n"); - abort(); - } - - if (!sat.solve(modelExpressions, forwardModel, forwardAssumptions)) { - printf("forward solving failed!\n"); - abort(); - } - - printf("xorshift32 test with input pattern 0x%08x:\n", input_pattern); - - printf("forward solution: input=0x%08x output=0x%08x\n", - (unsigned int)sat.vec_model_get_unsigned(modelExpressions, forwardModel, sat.vec_var("i", 32)), - (unsigned int)sat.vec_model_get_unsigned(modelExpressions, forwardModel, sat.vec_var("o", 32))); - - printf("backward solution: input=0x%08x output=0x%08x\n", - (unsigned int)sat.vec_model_get_unsigned(modelExpressions, backwardModel, sat.vec_var("i", 32)), - (unsigned int)sat.vec_model_get_unsigned(modelExpressions, backwardModel, sat.vec_var("o", 32))); - - if (forwardModel != backwardModel) { - printf("forward and backward results are inconsistend!\n"); - abort(); - } - - printf("passed.\n\n"); -} - -void test_xorshift32() -{ - printf("==== %s ====\n\n", __PRETTY_FUNCTION__); - - ezMiniSAT sat; - sat.keep_cnf(); - - xorshift128 rng; - - std::vector bits = sat.vec_var("i", 32); - - bits = sat.vec_xor(bits, sat.vec_shl(bits, 13)); - bits = sat.vec_xor(bits, sat.vec_shr(bits, 17)); - bits = sat.vec_xor(bits, sat.vec_shl(bits, 5)); - - sat.vec_set(bits, sat.vec_var("o", 32)); - - test_xorshift32_try(sat, 0); - test_xorshift32_try(sat, 314159265); - test_xorshift32_try(sat, rng()); - test_xorshift32_try(sat, rng()); - test_xorshift32_try(sat, rng()); - test_xorshift32_try(sat, rng()); - - sat.printDIMACS(stdout, true); - printf("\n"); -} - -// ------------------------------------------------------------------------------------------------------------ - -#define CHECK(_expr1, _expr2) check(#_expr1, _expr1, #_expr2, _expr2) - -void check(const char *expr1_str, bool expr1, const char *expr2_str, bool expr2) -{ - if (expr1 == expr2) { - printf("[ %s ] == [ %s ] .. ok (%s == %s)\n", expr1_str, expr2_str, expr1 ? "true" : "false", expr2 ? "true" : "false"); - } else { - printf("[ %s ] != [ %s ] .. ERROR (%s != %s)\n", expr1_str, expr2_str, expr1 ? "true" : "false", expr2 ? "true" : "false"); - abort(); - } -} - -void test_signed(int8_t a, int8_t b, int8_t c) -{ - ezMiniSAT sat; - - std::vector av = sat.vec_const_signed(a, 8); - std::vector bv = sat.vec_const_signed(b, 8); - std::vector cv = sat.vec_const_signed(c, 8); - - printf("Testing signed arithmetic using: a=%+d, b=%+d, c=%+d\n", int(a), int(b), int(c)); - - CHECK(a < b+c, sat.solve(sat.vec_lt_signed(av, sat.vec_add(bv, cv)))); - CHECK(a <= b-c, sat.solve(sat.vec_le_signed(av, sat.vec_sub(bv, cv)))); - - CHECK(a > b+c, sat.solve(sat.vec_gt_signed(av, sat.vec_add(bv, cv)))); - CHECK(a >= b-c, sat.solve(sat.vec_ge_signed(av, sat.vec_sub(bv, cv)))); - - printf("\n"); -} - -void test_unsigned(uint8_t a, uint8_t b, uint8_t c) -{ - ezMiniSAT sat; - - if (b < c) - b ^= c, c ^= b, b ^= c; - - std::vector av = sat.vec_const_unsigned(a, 8); - std::vector bv = sat.vec_const_unsigned(b, 8); - std::vector cv = sat.vec_const_unsigned(c, 8); - - printf("Testing unsigned arithmetic using: a=%d, b=%d, c=%d\n", int(a), int(b), int(c)); - - CHECK(a < b+c, sat.solve(sat.vec_lt_unsigned(av, sat.vec_add(bv, cv)))); - CHECK(a <= b-c, sat.solve(sat.vec_le_unsigned(av, sat.vec_sub(bv, cv)))); - - CHECK(a > b+c, sat.solve(sat.vec_gt_unsigned(av, sat.vec_add(bv, cv)))); - CHECK(a >= b-c, sat.solve(sat.vec_ge_unsigned(av, sat.vec_sub(bv, cv)))); - - printf("\n"); -} - -void test_count(uint32_t x) -{ - ezMiniSAT sat; - - int count = 0; - for (int i = 0; i < 32; i++) - if (((x >> i) & 1) != 0) - count++; - - printf("Testing bit counting using x=0x%08x (%d set bits) .. ", x, count); - - std::vector v = sat.vec_const_unsigned(x, 32); - - std::vector cv6 = sat.vec_const_unsigned(count, 6); - std::vector cv4 = sat.vec_const_unsigned(count <= 15 ? count : 15, 4); - - if (cv6 != sat.vec_count(v, 6, false)) { - fprintf(stderr, "FAILED 6bit-no-clipping test!\n"); - abort(); - } - - if (cv4 != sat.vec_count(v, 4, true)) { - fprintf(stderr, "FAILED 4bit-clipping test!\n"); - abort(); - } - - printf("ok.\n"); -} - -void test_arith() -{ - printf("==== %s ====\n\n", __PRETTY_FUNCTION__); - - xorshift128 rng; - - for (int i = 0; i < 100; i++) - test_signed(rng() % 19 - 10, rng() % 19 - 10, rng() % 19 - 10); - - for (int i = 0; i < 100; i++) - test_unsigned(rng() % 10, rng() % 10, rng() % 10); - - test_count(0x00000000); - test_count(0xffffffff); - for (int i = 0; i < 30; i++) - test_count(rng()); - - printf("\n"); -} - -// ------------------------------------------------------------------------------------------------------------ - -void test_onehot() -{ - printf("==== %s ====\n\n", __PRETTY_FUNCTION__); - ezMiniSAT ez; - - int a = ez.frozen_literal("a"); - int b = ez.frozen_literal("b"); - int c = ez.frozen_literal("c"); - int d = ez.frozen_literal("d"); - - std::vector abcd; - abcd.push_back(a); - abcd.push_back(b); - abcd.push_back(c); - abcd.push_back(d); - - ez.assume(ez.onehot(abcd)); - - int solution_counter = 0; - while (1) - { - std::vector modelValues; - bool ok = ez.solve(abcd, modelValues); - - if (!ok) - break; - - printf("Solution: %d %d %d %d\n", int(modelValues[0]), int(modelValues[1]), int(modelValues[2]), int(modelValues[3])); - - int count_hot = 0; - std::vector sol; - for (int i = 0; i < 4; i++) { - if (modelValues[i]) - count_hot++; - sol.push_back(modelValues[i] ? abcd[i] : ez.NOT(abcd[i])); - } - ez.assume(ez.NOT(ez.expression(ezSAT::OpAnd, sol))); - - if (count_hot != 1) { - fprintf(stderr, "Wrong number of hot bits!\n"); - abort(); - } - - solution_counter++; - } - - if (solution_counter != 4) { - fprintf(stderr, "Wrong number of one-hot solutions!\n"); - abort(); - } - - printf("\n"); -} - -void test_manyhot() -{ - printf("==== %s ====\n\n", __PRETTY_FUNCTION__); - ezMiniSAT ez; - - int a = ez.frozen_literal("a"); - int b = ez.frozen_literal("b"); - int c = ez.frozen_literal("c"); - int d = ez.frozen_literal("d"); - - std::vector abcd; - abcd.push_back(a); - abcd.push_back(b); - abcd.push_back(c); - abcd.push_back(d); - - ez.assume(ez.manyhot(abcd, 1, 2)); - - int solution_counter = 0; - while (1) - { - std::vector modelValues; - bool ok = ez.solve(abcd, modelValues); - - if (!ok) - break; - - printf("Solution: %d %d %d %d\n", int(modelValues[0]), int(modelValues[1]), int(modelValues[2]), int(modelValues[3])); - - int count_hot = 0; - std::vector sol; - for (int i = 0; i < 4; i++) { - if (modelValues[i]) - count_hot++; - sol.push_back(modelValues[i] ? abcd[i] : ez.NOT(abcd[i])); - } - ez.assume(ez.NOT(ez.expression(ezSAT::OpAnd, sol))); - - if (count_hot != 1 && count_hot != 2) { - fprintf(stderr, "Wrong number of hot bits!\n"); - abort(); - } - - solution_counter++; - } - - if (solution_counter != 4 + 4*3/2) { - fprintf(stderr, "Wrong number of one-hot solutions!\n"); - abort(); - } - - printf("\n"); -} - -void test_ordered() -{ - printf("==== %s ====\n\n", __PRETTY_FUNCTION__); - ezMiniSAT ez; - - int a = ez.frozen_literal("a"); - int b = ez.frozen_literal("b"); - int c = ez.frozen_literal("c"); - - int x = ez.frozen_literal("x"); - int y = ez.frozen_literal("y"); - int z = ez.frozen_literal("z"); - - std::vector abc; - abc.push_back(a); - abc.push_back(b); - abc.push_back(c); - - std::vector xyz; - xyz.push_back(x); - xyz.push_back(y); - xyz.push_back(z); - - ez.assume(ez.ordered(abc, xyz)); - - int solution_counter = 0; - - while (1) - { - std::vector modelVariables; - std::vector modelValues; - - modelVariables.push_back(a); - modelVariables.push_back(b); - modelVariables.push_back(c); - - modelVariables.push_back(x); - modelVariables.push_back(y); - modelVariables.push_back(z); - - bool ok = ez.solve(modelVariables, modelValues); - - if (!ok) - break; - - printf("Solution: %d %d %d | %d %d %d\n", - int(modelValues[0]), int(modelValues[1]), int(modelValues[2]), - int(modelValues[3]), int(modelValues[4]), int(modelValues[5])); - - std::vector sol; - for (size_t i = 0; i < modelVariables.size(); i++) - sol.push_back(modelValues[i] ? modelVariables[i] : ez.NOT(modelVariables[i])); - ez.assume(ez.NOT(ez.expression(ezSAT::OpAnd, sol))); - - solution_counter++; - } - - if (solution_counter != 8+7+6+5+4+3+2+1) { - fprintf(stderr, "Wrong number of solutions!\n"); - abort(); - } - - printf("\n"); -} - -// ------------------------------------------------------------------------------------------------------------ - - -int main() -{ - test_simple(); - test_xorshift32(); - test_arith(); - test_onehot(); - test_manyhot(); - test_ordered(); - printf("Passed all tests.\n\n"); - return 0; -} - diff --git a/yosys/libs/minisat/00_PATCH_mkLit_default_arg.patch b/yosys/libs/minisat/00_PATCH_mkLit_default_arg.patch deleted file mode 100644 index e21683f98..000000000 --- a/yosys/libs/minisat/00_PATCH_mkLit_default_arg.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- SolverTypes.h -+++ SolverTypes.h -@@ -52,7 +52,7 @@ struct Lit { - int x; - - // Use this as a constructor: -- friend Lit mkLit(Var var, bool sign = false); -+ friend Lit mkLit(Var var, bool sign); - - bool operator == (Lit p) const { return x == p.x; } - bool operator != (Lit p) const { return x != p.x; } -@@ -60,7 +60,7 @@ struct Lit { - }; - - --inline Lit mkLit (Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; } -+inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; } - inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; } - inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; } - inline bool sign (Lit p) { return p.x & 1; } diff --git a/yosys/libs/minisat/00_PATCH_no_fpu_control.patch b/yosys/libs/minisat/00_PATCH_no_fpu_control.patch deleted file mode 100644 index 6c754b1ed..000000000 --- a/yosys/libs/minisat/00_PATCH_no_fpu_control.patch +++ /dev/null @@ -1,43 +0,0 @@ ---- System.cc -+++ System.cc -@@ -97,17 +97,6 @@ double Minisat::memUsedPeak(bool) { return 0; } - #endif - - --void Minisat::setX86FPUPrecision() --{ --#if defined(__linux__) && defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE) && defined(_FPU_GETCW) -- // Only correct FPU precision on Linux architectures that needs and supports it: -- fpu_control_t oldcw, newcw; -- _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw); -- printf("WARNING: for repeatability, setting FPU to use double precision\n"); --#endif --} -- -- - #if !defined(_MSC_VER) && !defined(__MINGW32__) - void Minisat::limitMemory(uint64_t max_mem_mb) - { ---- System.h -+++ System.h -@@ -21,10 +21,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA - #ifndef Minisat_System_h - #define Minisat_System_h - --#if defined(__linux__) --#include --#endif -- - #include "IntTypes.h" - - //------------------------------------------------------------------------------------------------- -@@ -36,9 +32,6 @@ static inline double cpuTime(void); // CPU-time in seconds. - extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures). - extern double memUsedPeak(bool strictlyPeak = false); // Peak-memory in mega bytes (returns 0 for unsupported architectures). - --extern void setX86FPUPrecision(); // Make sure double's are represented with the same precision -- // in memory and registers. -- - extern void limitMemory(uint64_t max_mem_mb); // Set a limit on total memory usage. The exact - // semantics varies depending on architecture. - diff --git a/yosys/libs/minisat/00_PATCH_remove_zlib.patch b/yosys/libs/minisat/00_PATCH_remove_zlib.patch deleted file mode 100644 index 068356b73..000000000 --- a/yosys/libs/minisat/00_PATCH_remove_zlib.patch +++ /dev/null @@ -1,55 +0,0 @@ ---- ParseUtils.h -+++ ParseUtils.h -@@ -24,8 +24,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA - #include - #include - --#include -- - #include "XAlloc.h" - - namespace Minisat { -@@ -36,24 +34,16 @@ namespace Minisat { - - - class StreamBuffer { -- gzFile in; - unsigned char* buf; - int pos; - int size; - - enum { buffer_size = 64*1024 }; - -- void assureLookahead() { -- if (pos >= size) { -- pos = 0; -- size = gzread(in, buf, buffer_size); } } -+ virtual void assureLookahead() = 0; - - public: -- explicit StreamBuffer(gzFile i) : in(i), pos(0), size(0){ -- buf = (unsigned char*)xrealloc(NULL, buffer_size); -- assureLookahead(); -- } -- ~StreamBuffer() { free(buf); } -+ virtual ~StreamBuffer() { } - - int operator * () const { return (pos >= size) ? EOF : buf[pos]; } - void operator ++ () { pos++; assureLookahead(); } ---- Dimacs.h -+++ Dimacs.h -@@ -76,10 +76,10 @@ static void parse_DIMACS_main(B& in, Solver& S, bool strictp = false) { - - // Inserts problem into solver. - // --template --static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) { -- StreamBuffer in(input_stream); -- parse_DIMACS_main(in, S, strictp); } -+//template -+//static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) { -+// StreamBuffer in(input_stream); -+// parse_DIMACS_main(in, S, strictp); } - - //================================================================================================= - } diff --git a/yosys/libs/minisat/00_PATCH_typofixes.patch b/yosys/libs/minisat/00_PATCH_typofixes.patch deleted file mode 100644 index 175f483bf..000000000 --- a/yosys/libs/minisat/00_PATCH_typofixes.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- Solver.h -+++ Solver.h -@@ -103,7 +103,7 @@ public: - int nFreeVars () const; - void printStats () const; // Print some current statistics to standard output. - -- // Resource contraints: -+ // Resource constraints: - // - void setConfBudget(int64_t x); - void setPropBudget(int64_t x); -@@ -230,7 +230,7 @@ protected: - double learntsize_adjust_confl; - int learntsize_adjust_cnt; - -- // Resource contraints: -+ // Resource constraints: - // - int64_t conflict_budget; // -1 means no budget. - int64_t propagation_budget; // -1 means no budget. diff --git a/yosys/libs/minisat/00_UPDATE.sh b/yosys/libs/minisat/00_UPDATE.sh deleted file mode 100755 index ea26215ab..000000000 --- a/yosys/libs/minisat/00_UPDATE.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -rm -f LICENSE *.cc *.h -git clone --depth 1 https://github.com/niklasso/minisat minisat_upstream -rm minisat_upstream/minisat/*/Main.cc -mv minisat_upstream/LICENSE minisat_upstream/minisat/*/*.{h,cc} . -rm -rf minisat_upstream - -sed -i -e 's,^#include *"minisat/[^/]\+/\?,#include ",' *.cc *.h -sed -i -e 's/Minisat::memUsedPeak()/Minisat::memUsedPeak(bool)/' System.cc -sed -i -e 's/PRI[iu]64/ & /' Options.h Solver.cc -sed -i -e '1 i #ifndef __STDC_LIMIT_MACROS\n#define __STDC_LIMIT_MACROS\n#endif' *.cc -sed -i -e '1 i #ifndef __STDC_FORMAT_MACROS\n#define __STDC_FORMAT_MACROS\n#endif' *.cc - -patch -p0 < 00_PATCH_mkLit_default_arg.patch -patch -p0 < 00_PATCH_remove_zlib.patch -patch -p0 < 00_PATCH_no_fpu_control.patch -patch -p0 < 00_PATCH_typofixes.patch - diff --git a/yosys/libs/minisat/Alg.h b/yosys/libs/minisat/Alg.h deleted file mode 100644 index ddb972e77..000000000 --- a/yosys/libs/minisat/Alg.h +++ /dev/null @@ -1,84 +0,0 @@ -/*******************************************************************************************[Alg.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Alg_h -#define Minisat_Alg_h - -#include "Vec.h" - -namespace Minisat { - -//================================================================================================= -// Useful functions on vector-like types: - -//================================================================================================= -// Removing and searching for elements: -// - -template -static inline void remove(V& ts, const T& t) -{ - int j = 0; - for (; j < (int)ts.size() && ts[j] != t; j++); - assert(j < (int)ts.size()); - for (; j < (int)ts.size()-1; j++) ts[j] = ts[j+1]; - ts.pop(); -} - - -template -static inline bool find(V& ts, const T& t) -{ - int j = 0; - for (; j < (int)ts.size() && ts[j] != t; j++); - return j < (int)ts.size(); -} - - -//================================================================================================= -// Copying vectors with support for nested vector types: -// - -// Base case: -template -static inline void copy(const T& from, T& to) -{ - to = from; -} - -// Recursive case: -template -static inline void copy(const vec& from, vec& to, bool append = false) -{ - if (!append) - to.clear(); - for (int i = 0; i < from.size(); i++){ - to.push(); - copy(from[i], to.last()); - } -} - -template -static inline void append(const vec& from, vec& to){ copy(from, to, true); } - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/Alloc.h b/yosys/libs/minisat/Alloc.h deleted file mode 100644 index 6591dcd55..000000000 --- a/yosys/libs/minisat/Alloc.h +++ /dev/null @@ -1,131 +0,0 @@ -/*****************************************************************************************[Alloc.h] -Copyright (c) 2008-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - - -#ifndef Minisat_Alloc_h -#define Minisat_Alloc_h - -#include "XAlloc.h" -#include "Vec.h" - -namespace Minisat { - -//================================================================================================= -// Simple Region-based memory allocator: - -template -class RegionAllocator -{ - T* memory; - uint32_t sz; - uint32_t cap; - uint32_t wasted_; - - void capacity(uint32_t min_cap); - - public: - // TODO: make this a class for better type-checking? - typedef uint32_t Ref; - enum { Ref_Undef = UINT32_MAX }; - enum { Unit_Size = sizeof(T) }; - - explicit RegionAllocator(uint32_t start_cap = 1024*1024) : memory(NULL), sz(0), cap(0), wasted_(0){ capacity(start_cap); } - ~RegionAllocator() - { - if (memory != NULL) - ::free(memory); - } - - - uint32_t size () const { return sz; } - uint32_t wasted () const { return wasted_; } - - Ref alloc (int size); - void free (int size) { wasted_ += size; } - - // Deref, Load Effective Address (LEA), Inverse of LEA (AEL): - T& operator[](Ref r) { assert(r < sz); return memory[r]; } - const T& operator[](Ref r) const { assert(r < sz); return memory[r]; } - - T* lea (Ref r) { assert(r < sz); return &memory[r]; } - const T* lea (Ref r) const { assert(r < sz); return &memory[r]; } - Ref ael (const T* t) { assert((void*)t >= (void*)&memory[0] && (void*)t < (void*)&memory[sz-1]); - return (Ref)(t - &memory[0]); } - - void moveTo(RegionAllocator& to) { - if (to.memory != NULL) ::free(to.memory); - to.memory = memory; - to.sz = sz; - to.cap = cap; - to.wasted_ = wasted_; - - memory = NULL; - sz = cap = wasted_ = 0; - } - - -}; - -template -void RegionAllocator::capacity(uint32_t min_cap) -{ - if (cap >= min_cap) return; - - uint32_t prev_cap = cap; - while (cap < min_cap){ - // NOTE: Multiply by a factor (13/8) without causing overflow, then add 2 and make the - // result even by clearing the least significant bit. The resulting sequence of capacities - // is carefully chosen to hit a maximum capacity that is close to the '2^32-1' limit when - // using 'uint32_t' as indices so that as much as possible of this space can be used. - uint32_t delta = ((cap >> 1) + (cap >> 3) + 2) & ~1; - cap += delta; - - if (cap <= prev_cap) - throw OutOfMemoryException(); - } - // printf(" .. (%p) cap = %u\n", this, cap); - - assert(cap > 0); - memory = (T*)xrealloc(memory, sizeof(T)*cap); -} - - -template -typename RegionAllocator::Ref -RegionAllocator::alloc(int size) -{ - // printf("ALLOC called (this = %p, size = %d)\n", this, size); fflush(stdout); - assert(size > 0); - capacity(sz + size); - - uint32_t prev_sz = sz; - sz += size; - - // Handle overflow: - if (sz < prev_sz) - throw OutOfMemoryException(); - - return prev_sz; -} - - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/Dimacs.h b/yosys/libs/minisat/Dimacs.h deleted file mode 100644 index 61b9d3ca0..000000000 --- a/yosys/libs/minisat/Dimacs.h +++ /dev/null @@ -1,87 +0,0 @@ -/****************************************************************************************[Dimacs.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Dimacs_h -#define Minisat_Dimacs_h - -#include - -#include "ParseUtils.h" -#include "SolverTypes.h" - -namespace Minisat { - -//================================================================================================= -// DIMACS Parser: - -template -static void readClause(B& in, Solver& S, vec& lits) { - int parsed_lit, var; - lits.clear(); - for (;;){ - parsed_lit = parseInt(in); - if (parsed_lit == 0) break; - var = abs(parsed_lit)-1; - while (var >= S.nVars()) S.newVar(); - lits.push( (parsed_lit > 0) ? mkLit(var) : ~mkLit(var) ); - } -} - -template -static void parse_DIMACS_main(B& in, Solver& S, bool strictp = false) { - vec lits; - int vars = 0; - int clauses = 0; - int cnt = 0; - for (;;){ - skipWhitespace(in); - if (*in == EOF) break; - else if (*in == 'p'){ - if (eagerMatch(in, "p cnf")){ - vars = parseInt(in); - clauses = parseInt(in); - // SATRACE'06 hack - // if (clauses > 4000000) - // S.eliminate(true); - }else{ - printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3); - } - } else if (*in == 'c' || *in == 'p') - skipLine(in); - else{ - cnt++; - readClause(in, S, lits); - S.addClause_(lits); } - } - if (strictp && cnt != clauses) - printf("PARSE ERROR! DIMACS header mismatch: wrong number of clauses\n"); -} - -// Inserts problem into solver. -// -//template -//static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) { -// StreamBuffer in(input_stream); -// parse_DIMACS_main(in, S, strictp); } - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/Heap.h b/yosys/libs/minisat/Heap.h deleted file mode 100644 index 057a3cdf2..000000000 --- a/yosys/libs/minisat/Heap.h +++ /dev/null @@ -1,168 +0,0 @@ -/******************************************************************************************[Heap.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Heap_h -#define Minisat_Heap_h - -#include "Vec.h" -#include "IntMap.h" - -namespace Minisat { - -//================================================================================================= -// A heap implementation with support for decrease/increase key. - - -template > -class Heap { - vec heap; // Heap of Keys - IntMap indices; // Each Key's position (index) in the Heap - Comp lt; // The heap is a minimum-heap with respect to this comparator - - // Index "traversal" functions - static inline int left (int i) { return i*2+1; } - static inline int right (int i) { return (i+1)*2; } - static inline int parent(int i) { return (i-1) >> 1; } - - - void percolateUp(int i) - { - K x = heap[i]; - int p = parent(i); - - while (i != 0 && lt(x, heap[p])){ - heap[i] = heap[p]; - indices[heap[p]] = i; - i = p; - p = parent(p); - } - heap [i] = x; - indices[x] = i; - } - - - void percolateDown(int i) - { - K x = heap[i]; - while (left(i) < heap.size()){ - int child = right(i) < heap.size() && lt(heap[right(i)], heap[left(i)]) ? right(i) : left(i); - if (!lt(heap[child], x)) break; - heap[i] = heap[child]; - indices[heap[i]] = i; - i = child; - } - heap [i] = x; - indices[x] = i; - } - - - public: - Heap(const Comp& c, MkIndex _index = MkIndex()) : indices(_index), lt(c) {} - - int size () const { return heap.size(); } - bool empty () const { return heap.size() == 0; } - bool inHeap (K k) const { return indices.has(k) && indices[k] >= 0; } - int operator[](int index) const { assert(index < heap.size()); return heap[index]; } - - void decrease (K k) { assert(inHeap(k)); percolateUp (indices[k]); } - void increase (K k) { assert(inHeap(k)); percolateDown(indices[k]); } - - - // Safe variant of insert/decrease/increase: - void update(K k) - { - if (!inHeap(k)) - insert(k); - else { - percolateUp(indices[k]); - percolateDown(indices[k]); } - } - - - void insert(K k) - { - indices.reserve(k, -1); - assert(!inHeap(k)); - - indices[k] = heap.size(); - heap.push(k); - percolateUp(indices[k]); - } - - - void remove(K k) - { - assert(inHeap(k)); - - int k_pos = indices[k]; - indices[k] = -1; - - if (k_pos < heap.size()-1){ - heap[k_pos] = heap.last(); - indices[heap[k_pos]] = k_pos; - heap.pop(); - percolateDown(k_pos); - }else - heap.pop(); - } - - - K removeMin() - { - K x = heap[0]; - heap[0] = heap.last(); - indices[heap[0]] = 0; - indices[x] = -1; - heap.pop(); - if (heap.size() > 1) percolateDown(0); - return x; - } - - - // Rebuild the heap from scratch, using the elements in 'ns': - void build(const vec& ns) { - for (int i = 0; i < heap.size(); i++) - indices[heap[i]] = -1; - heap.clear(); - - for (int i = 0; i < ns.size(); i++){ - // TODO: this should probably call reserve instead of relying on it being reserved already. - assert(indices.has(ns[i])); - indices[ns[i]] = i; - heap.push(ns[i]); } - - for (int i = heap.size() / 2 - 1; i >= 0; i--) - percolateDown(i); - } - - void clear(bool dispose = false) - { - // TODO: shouldn't the 'indices' map also be dispose-cleared? - for (int i = 0; i < heap.size(); i++) - indices[heap[i]] = -1; - heap.clear(dispose); - } -}; - - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/IntMap.h b/yosys/libs/minisat/IntMap.h deleted file mode 100644 index 9a66315d1..000000000 --- a/yosys/libs/minisat/IntMap.h +++ /dev/null @@ -1,106 +0,0 @@ -/****************************************************************************************[IntMap.h] -Copyright (c) 2011, Niklas Sorensson -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_IntMap_h -#define Minisat_IntMap_h - -#include "Vec.h" - -namespace Minisat { - - template struct MkIndexDefault { - typename vec::Size operator()(T t) const { return (typename vec::Size)t; } - }; - - template > - class IntMap { - vec map; - MkIndex index; - public: - explicit IntMap(MkIndex _index = MkIndex()) : index(_index){} - - bool has (K k) const { return index(k) < map.size(); } - - const V& operator[](K k) const { assert(has(k)); return map[index(k)]; } - V& operator[](K k) { assert(has(k)); return map[index(k)]; } - - const V* begin () const { return &map[0]; } - const V* end () const { return &map[map.size()]; } - V* begin () { return &map[0]; } - V* end () { return &map[map.size()]; } - - void reserve(K key, V pad) { map.growTo(index(key)+1, pad); } - void reserve(K key) { map.growTo(index(key)+1); } - void insert (K key, V val, V pad){ reserve(key, pad); operator[](key) = val; } - void insert (K key, V val) { reserve(key); operator[](key) = val; } - - void clear (bool dispose = false) { map.clear(dispose); } - void moveTo (IntMap& to) { map.moveTo(to.map); to.index = index; } - void copyTo (IntMap& to) const { map.copyTo(to.map); to.index = index; } - }; - - - template > - class IntSet - { - IntMap in_set; - vec xs; - - public: - // Size operations: - int size (void) const { return xs.size(); } - void clear (bool free = false){ - if (free) - in_set.clear(true); - else - for (int i = 0; i < xs.size(); i++) - in_set[xs[i]] = 0; - xs.clear(free); - } - - // Allow inspecting the internal vector: - const vec& - toVec () const { return xs; } - - // Vector interface: - K operator [] (int index) const { return xs[index]; } - - - void insert (K k) { in_set.reserve(k, 0); if (!in_set[k]) { in_set[k] = 1; xs.push(k); } } - bool has (K k) { in_set.reserve(k, 0); return in_set[k]; } - }; - - #if 0 - template > - class IntMapNil { - vec map; - V nil; - - public: - IntMap(){} - - void reserve(K); - V& find (K); - const V& operator[](K k) const; - - }; - #endif - -//================================================================================================= -} // namespace Minisat -#endif diff --git a/yosys/libs/minisat/IntTypes.h b/yosys/libs/minisat/IntTypes.h deleted file mode 100644 index c48816284..000000000 --- a/yosys/libs/minisat/IntTypes.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************************[IntTypes.h] -Copyright (c) 2009-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_IntTypes_h -#define Minisat_IntTypes_h - -#ifdef __sun - // Not sure if there are newer versions that support C99 headers. The - // needed features are implemented in the headers below though: - -# include -# include -# include - -#else - -# include -# include - -#endif - -#include - -//================================================================================================= - -#endif diff --git a/yosys/libs/minisat/LICENSE b/yosys/libs/minisat/LICENSE deleted file mode 100644 index 22816ff39..000000000 --- a/yosys/libs/minisat/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson - Copyright (c) 2007-2010 Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/yosys/libs/minisat/Map.h b/yosys/libs/minisat/Map.h deleted file mode 100644 index a6f832000..000000000 --- a/yosys/libs/minisat/Map.h +++ /dev/null @@ -1,193 +0,0 @@ -/*******************************************************************************************[Map.h] -Copyright (c) 2006-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Map_h -#define Minisat_Map_h - -#include "IntTypes.h" -#include "Vec.h" - -namespace Minisat { - -//================================================================================================= -// Default hash/equals functions -// - -template struct Hash { uint32_t operator()(const K& k) const { return hash(k); } }; -template struct Equal { bool operator()(const K& k1, const K& k2) const { return k1 == k2; } }; - -template struct DeepHash { uint32_t operator()(const K* k) const { return hash(*k); } }; -template struct DeepEqual { bool operator()(const K* k1, const K* k2) const { return *k1 == *k2; } }; - -static inline uint32_t hash(uint32_t x){ return x; } -static inline uint32_t hash(uint64_t x){ return (uint32_t)x; } -static inline uint32_t hash(int32_t x) { return (uint32_t)x; } -static inline uint32_t hash(int64_t x) { return (uint32_t)x; } - - -//================================================================================================= -// Some primes -// - -static const int nprimes = 25; -static const int primes [nprimes] = { 31, 73, 151, 313, 643, 1291, 2593, 5233, 10501, 21013, 42073, 84181, 168451, 337219, 674701, 1349473, 2699299, 5398891, 10798093, 21596719, 43193641, 86387383, 172775299, 345550609, 691101253 }; - -//================================================================================================= -// Hash table implementation of Maps -// - -template, class E = Equal > -class Map { - public: - struct Pair { K key; D data; }; - - private: - H hash; - E equals; - - vec* table; - int cap; - int size; - - // Don't allow copying (error prone): - Map& operator = (Map& other); - Map (Map& other); - - bool checkCap(int new_size) const { return new_size > cap; } - - int32_t index (const K& k) const { return hash(k) % cap; } - void _insert (const K& k, const D& d) { - vec& ps = table[index(k)]; - ps.push(); ps.last().key = k; ps.last().data = d; } - - void rehash () { - const vec* old = table; - - int old_cap = cap; - int newsize = primes[0]; - for (int i = 1; newsize <= cap && i < nprimes; i++) - newsize = primes[i]; - - table = new vec[newsize]; - cap = newsize; - - for (int i = 0; i < old_cap; i++){ - for (int j = 0; j < old[i].size(); j++){ - _insert(old[i][j].key, old[i][j].data); }} - - delete [] old; - - // printf(" --- rehashing, old-cap=%d, new-cap=%d\n", cap, newsize); - } - - - public: - - Map () : table(NULL), cap(0), size(0) {} - Map (const H& h, const E& e) : hash(h), equals(e), table(NULL), cap(0), size(0){} - ~Map () { delete [] table; } - - // PRECONDITION: the key must already exist in the map. - const D& operator [] (const K& k) const - { - assert(size != 0); - const D* res = NULL; - const vec& ps = table[index(k)]; - for (int i = 0; i < ps.size(); i++) - if (equals(ps[i].key, k)) - res = &ps[i].data; - assert(res != NULL); - return *res; - } - - // PRECONDITION: the key must already exist in the map. - D& operator [] (const K& k) - { - assert(size != 0); - D* res = NULL; - vec& ps = table[index(k)]; - for (int i = 0; i < ps.size(); i++) - if (equals(ps[i].key, k)) - res = &ps[i].data; - assert(res != NULL); - return *res; - } - - // PRECONDITION: the key must *NOT* exist in the map. - void insert (const K& k, const D& d) { if (checkCap(size+1)) rehash(); _insert(k, d); size++; } - bool peek (const K& k, D& d) const { - if (size == 0) return false; - const vec& ps = table[index(k)]; - for (int i = 0; i < ps.size(); i++) - if (equals(ps[i].key, k)){ - d = ps[i].data; - return true; } - return false; - } - - bool has (const K& k) const { - if (size == 0) return false; - const vec& ps = table[index(k)]; - for (int i = 0; i < ps.size(); i++) - if (equals(ps[i].key, k)) - return true; - return false; - } - - // PRECONDITION: the key must exist in the map. - void remove(const K& k) { - assert(table != NULL); - vec& ps = table[index(k)]; - int j = 0; - for (; j < ps.size() && !equals(ps[j].key, k); j++); - assert(j < ps.size()); - ps[j] = ps.last(); - ps.pop(); - size--; - } - - void clear () { - cap = size = 0; - delete [] table; - table = NULL; - } - - int elems() const { return size; } - int bucket_count() const { return cap; } - - // NOTE: the hash and equality objects are not moved by this method: - void moveTo(Map& other){ - delete [] other.table; - - other.table = table; - other.cap = cap; - other.size = size; - - table = NULL; - size = cap = 0; - } - - // NOTE: given a bit more time, I could make a more C++-style iterator out of this: - const vec& bucket(int i) const { return table[i]; } -}; - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/Options.cc b/yosys/libs/minisat/Options.cc deleted file mode 100644 index 5c45dd6ac..000000000 --- a/yosys/libs/minisat/Options.cc +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif -/**************************************************************************************[Options.cc] -Copyright (c) 2008-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include "Sort.h" -#include "Options.h" -#include "ParseUtils.h" - -using namespace Minisat; - -void Minisat::parseOptions(int& argc, char** argv, bool strict) -{ - int i, j; - for (i = j = 1; i < argc; i++){ - const char* str = argv[i]; - if (match(str, "--") && match(str, Option::getHelpPrefixString()) && match(str, "help")){ - if (*str == '\0') - printUsageAndExit(argc, argv); - else if (match(str, "-verb")) - printUsageAndExit(argc, argv, true); - } else { - bool parsed_ok = false; - - for (int k = 0; !parsed_ok && k < Option::getOptionList().size(); k++){ - parsed_ok = Option::getOptionList()[k]->parse(argv[i]); - - // fprintf(stderr, "checking %d: %s against flag <%s> (%s)\n", i, argv[i], Option::getOptionList()[k]->name, parsed_ok ? "ok" : "skip"); - } - - if (!parsed_ok){ - if (strict && match(argv[i], "-")) - fprintf(stderr, "ERROR! Unknown flag \"%s\". Use '--%shelp' for help.\n", argv[i], Option::getHelpPrefixString()), exit(1); - else - argv[j++] = argv[i]; - } - } - } - - argc -= (i - j); -} - - -void Minisat::setUsageHelp (const char* str){ Option::getUsageString() = str; } -void Minisat::setHelpPrefixStr (const char* str){ Option::getHelpPrefixString() = str; } -void Minisat::printUsageAndExit (int /*argc*/, char** argv, bool verbose) -{ - const char* usage = Option::getUsageString(); - if (usage != NULL) - fprintf(stderr, usage, argv[0]); - - sort(Option::getOptionList(), Option::OptionLt()); - - const char* prev_cat = NULL; - const char* prev_type = NULL; - - for (int i = 0; i < Option::getOptionList().size(); i++){ - const char* cat = Option::getOptionList()[i]->category; - const char* type = Option::getOptionList()[i]->type_name; - - if (cat != prev_cat) - fprintf(stderr, "\n%s OPTIONS:\n\n", cat); - else if (type != prev_type) - fprintf(stderr, "\n"); - - Option::getOptionList()[i]->help(verbose); - - prev_cat = Option::getOptionList()[i]->category; - prev_type = Option::getOptionList()[i]->type_name; - } - - fprintf(stderr, "\nHELP OPTIONS:\n\n"); - fprintf(stderr, " --%shelp Print help message.\n", Option::getHelpPrefixString()); - fprintf(stderr, " --%shelp-verb Print verbose help message.\n", Option::getHelpPrefixString()); - fprintf(stderr, "\n"); - exit(0); -} - diff --git a/yosys/libs/minisat/Options.h b/yosys/libs/minisat/Options.h deleted file mode 100644 index d602769cf..000000000 --- a/yosys/libs/minisat/Options.h +++ /dev/null @@ -1,386 +0,0 @@ -/***************************************************************************************[Options.h] -Copyright (c) 2008-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Options_h -#define Minisat_Options_h - -#include -#include -#include -#include - -#include "IntTypes.h" -#include "Vec.h" -#include "ParseUtils.h" - -namespace Minisat { - -//================================================================================================== -// Top-level option parse/help functions: - - -extern void parseOptions (int& argc, char** argv, bool strict = false); -extern void printUsageAndExit(int argc, char** argv, bool verbose = false); -extern void setUsageHelp (const char* str); -extern void setHelpPrefixStr (const char* str); - - -//================================================================================================== -// Options is an abstract class that gives the interface for all types options: - - -class Option -{ - protected: - const char* name; - const char* description; - const char* category; - const char* type_name; - - static vec& getOptionList () { static vec options; return options; } - static const char*& getUsageString() { static const char* usage_str; return usage_str; } - static const char*& getHelpPrefixString() { static const char* help_prefix_str = ""; return help_prefix_str; } - - struct OptionLt { - bool operator()(const Option* x, const Option* y) { - int test1 = strcmp(x->category, y->category); - return test1 < 0 || (test1 == 0 && strcmp(x->type_name, y->type_name) < 0); - } - }; - - Option(const char* name_, - const char* desc_, - const char* cate_, - const char* type_) : - name (name_) - , description(desc_) - , category (cate_) - , type_name (type_) - { - getOptionList().push(this); - } - - public: - virtual ~Option() {} - - virtual bool parse (const char* str) = 0; - virtual void help (bool verbose = false) = 0; - - friend void parseOptions (int& argc, char** argv, bool strict); - friend void printUsageAndExit (int argc, char** argv, bool verbose); - friend void setUsageHelp (const char* str); - friend void setHelpPrefixStr (const char* str); -}; - - -//================================================================================================== -// Range classes with specialization for floating types: - - -struct IntRange { - int begin; - int end; - IntRange(int b, int e) : begin(b), end(e) {} -}; - -struct Int64Range { - int64_t begin; - int64_t end; - Int64Range(int64_t b, int64_t e) : begin(b), end(e) {} -}; - -struct DoubleRange { - double begin; - double end; - bool begin_inclusive; - bool end_inclusive; - DoubleRange(double b, bool binc, double e, bool einc) : begin(b), end(e), begin_inclusive(binc), end_inclusive(einc) {} -}; - - -//================================================================================================== -// Double options: - - -class DoubleOption : public Option -{ - protected: - DoubleRange range; - double value; - - public: - DoubleOption(const char* c, const char* n, const char* d, double def = double(), DoubleRange r = DoubleRange(-HUGE_VAL, false, HUGE_VAL, false)) - : Option(n, d, c, ""), range(r), value(def) { - // FIXME: set LC_NUMERIC to "C" to make sure that strtof/strtod parses decimal point correctly. - } - - operator double (void) const { return value; } - operator double& (void) { return value; } - DoubleOption& operator=(double x) { value = x; return *this; } - - virtual bool parse(const char* str){ - const char* span = str; - - if (!match(span, "-") || !match(span, name) || !match(span, "=")) - return false; - - char* end; - double tmp = strtod(span, &end); - - if (end == NULL) - return false; - else if (tmp >= range.end && (!range.end_inclusive || tmp != range.end)){ - fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name); - exit(1); - }else if (tmp <= range.begin && (!range.begin_inclusive || tmp != range.begin)){ - fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name); - exit(1); } - - value = tmp; - // fprintf(stderr, "READ VALUE: %g\n", value); - - return true; - } - - virtual void help (bool verbose = false){ - fprintf(stderr, " -%-12s = %-8s %c%4.2g .. %4.2g%c (default: %g)\n", - name, type_name, - range.begin_inclusive ? '[' : '(', - range.begin, - range.end, - range.end_inclusive ? ']' : ')', - value); - if (verbose){ - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; - - -//================================================================================================== -// Int options: - - -class IntOption : public Option -{ - protected: - IntRange range; - int32_t value; - - public: - IntOption(const char* c, const char* n, const char* d, int32_t def = int32_t(), IntRange r = IntRange(INT32_MIN, INT32_MAX)) - : Option(n, d, c, ""), range(r), value(def) {} - - operator int32_t (void) const { return value; } - operator int32_t& (void) { return value; } - IntOption& operator= (int32_t x) { value = x; return *this; } - - virtual bool parse(const char* str){ - const char* span = str; - - if (!match(span, "-") || !match(span, name) || !match(span, "=")) - return false; - - char* end; - int32_t tmp = strtol(span, &end, 10); - - if (end == NULL) - return false; - else if (tmp > range.end){ - fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name); - exit(1); - }else if (tmp < range.begin){ - fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name); - exit(1); } - - value = tmp; - - return true; - } - - virtual void help (bool verbose = false){ - fprintf(stderr, " -%-12s = %-8s [", name, type_name); - if (range.begin == INT32_MIN) - fprintf(stderr, "imin"); - else - fprintf(stderr, "%4d", range.begin); - - fprintf(stderr, " .. "); - if (range.end == INT32_MAX) - fprintf(stderr, "imax"); - else - fprintf(stderr, "%4d", range.end); - - fprintf(stderr, "] (default: %d)\n", value); - if (verbose){ - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; - - -// Leave this out for visual C++ until Microsoft implements C99 and gets support for strtoll. -#ifndef _MSC_VER - -class Int64Option : public Option -{ - protected: - Int64Range range; - int64_t value; - - public: - Int64Option(const char* c, const char* n, const char* d, int64_t def = int64_t(), Int64Range r = Int64Range(INT64_MIN, INT64_MAX)) - : Option(n, d, c, ""), range(r), value(def) {} - - operator int64_t (void) const { return value; } - operator int64_t& (void) { return value; } - Int64Option& operator= (int64_t x) { value = x; return *this; } - - virtual bool parse(const char* str){ - const char* span = str; - - if (!match(span, "-") || !match(span, name) || !match(span, "=")) - return false; - - char* end; - int64_t tmp = strtoll(span, &end, 10); - - if (end == NULL) - return false; - else if (tmp > range.end){ - fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name); - exit(1); - }else if (tmp < range.begin){ - fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name); - exit(1); } - - value = tmp; - - return true; - } - - virtual void help (bool verbose = false){ - fprintf(stderr, " -%-12s = %-8s [", name, type_name); - if (range.begin == INT64_MIN) - fprintf(stderr, "imin"); - else - fprintf(stderr, "%4" PRIi64 , range.begin); - - fprintf(stderr, " .. "); - if (range.end == INT64_MAX) - fprintf(stderr, "imax"); - else - fprintf(stderr, "%4" PRIi64 , range.end); - - fprintf(stderr, "] (default: %" PRIi64 ")\n", value); - if (verbose){ - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; -#endif - -//================================================================================================== -// String option: - - -class StringOption : public Option -{ - const char* value; - public: - StringOption(const char* c, const char* n, const char* d, const char* def = NULL) - : Option(n, d, c, ""), value(def) {} - - operator const char* (void) const { return value; } - operator const char*& (void) { return value; } - StringOption& operator= (const char* x) { value = x; return *this; } - - virtual bool parse(const char* str){ - const char* span = str; - - if (!match(span, "-") || !match(span, name) || !match(span, "=")) - return false; - - value = span; - return true; - } - - virtual void help (bool verbose = false){ - fprintf(stderr, " -%-10s = %8s\n", name, type_name); - if (verbose){ - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; - - -//================================================================================================== -// Bool option: - - -class BoolOption : public Option -{ - bool value; - - public: - BoolOption(const char* c, const char* n, const char* d, bool v) - : Option(n, d, c, ""), value(v) {} - - operator bool (void) const { return value; } - operator bool& (void) { return value; } - BoolOption& operator=(bool b) { value = b; return *this; } - - virtual bool parse(const char* str){ - const char* span = str; - - if (match(span, "-")){ - bool b = !match(span, "no-"); - - if (strcmp(span, name) == 0){ - value = b; - return true; } - } - - return false; - } - - virtual void help (bool verbose = false){ - - fprintf(stderr, " -%s, -no-%s", name, name); - - for (uint32_t i = 0; i < 32 - strlen(name)*2; i++) - fprintf(stderr, " "); - - fprintf(stderr, " "); - fprintf(stderr, "(default: %s)\n", value ? "on" : "off"); - if (verbose){ - fprintf(stderr, "\n %s\n", description); - fprintf(stderr, "\n"); - } - } -}; - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/ParseUtils.h b/yosys/libs/minisat/ParseUtils.h deleted file mode 100644 index 04911c70a..000000000 --- a/yosys/libs/minisat/ParseUtils.h +++ /dev/null @@ -1,119 +0,0 @@ -/************************************************************************************[ParseUtils.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_ParseUtils_h -#define Minisat_ParseUtils_h - -#include -#include - -#include "XAlloc.h" - -namespace Minisat { - -//------------------------------------------------------------------------------------------------- -// A simple buffered character stream class: - - - -class StreamBuffer { - unsigned char* buf; - int pos; - int size; - - enum { buffer_size = 64*1024 }; - - virtual void assureLookahead() = 0; - -public: - virtual ~StreamBuffer() { } - - int operator * () const { return (pos >= size) ? EOF : buf[pos]; } - void operator ++ () { pos++; assureLookahead(); } - int position () const { return pos; } -}; - - -//------------------------------------------------------------------------------------------------- -// End-of-file detection functions for StreamBuffer and char*: - - -static inline bool isEof(StreamBuffer& in) { return *in == EOF; } -static inline bool isEof(const char* in) { return *in == '\0'; } - -//------------------------------------------------------------------------------------------------- -// Generic parse functions parametrized over the input-stream type. - - -template -static void skipWhitespace(B& in) { - while ((*in >= 9 && *in <= 13) || *in == 32) - ++in; } - - -template -static void skipLine(B& in) { - for (;;){ - if (isEof(in)) return; - if (*in == '\n') { ++in; return; } - ++in; } } - - -template -static int parseInt(B& in) { - int val = 0; - bool neg = false; - skipWhitespace(in); - if (*in == '-') neg = true, ++in; - else if (*in == '+') ++in; - if (*in < '0' || *in > '9') fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", *in), exit(3); - while (*in >= '0' && *in <= '9') - val = val*10 + (*in - '0'), - ++in; - return neg ? -val : val; } - - -// String matching: in case of a match the input iterator will be advanced the corresponding -// number of characters. -template -static bool match(B& in, const char* str) { - int i; - for (i = 0; str[i] != '\0'; i++) - if (in[i] != str[i]) - return false; - - in += i; - - return true; -} - -// String matching: consumes characters eagerly, but does not require random access iterator. -template -static bool eagerMatch(B& in, const char* str) { - for (; *str != '\0'; ++str, ++in) - if (*str != *in) - return false; - return true; } - - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/Queue.h b/yosys/libs/minisat/Queue.h deleted file mode 100644 index 5ba50cd2b..000000000 --- a/yosys/libs/minisat/Queue.h +++ /dev/null @@ -1,69 +0,0 @@ -/*****************************************************************************************[Queue.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Queue_h -#define Minisat_Queue_h - -#include "Vec.h" - -namespace Minisat { - -//================================================================================================= - -template -class Queue { - vec buf; - int first; - int end; - -public: - typedef T Key; - - Queue() : buf(1), first(0), end(0) {} - - void clear (bool dealloc = false) { buf.clear(dealloc); buf.growTo(1); first = end = 0; } - int size () const { return (end >= first) ? end - first : end - first + buf.size(); } - - const T& operator [] (int index) const { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; } - T& operator [] (int index) { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; } - - T peek () const { assert(first != end); return buf[first]; } - void pop () { assert(first != end); first++; if (first == buf.size()) first = 0; } - void insert(T elem) { // INVARIANT: buf[end] is always unused - buf[end++] = elem; - if (end == buf.size()) end = 0; - if (first == end){ // Resize: - vec tmp((buf.size()*3 + 1) >> 1); - //**/printf("queue alloc: %d elems (%.1f MB)\n", tmp.size(), tmp.size() * sizeof(T) / 1000000.0); - int i = 0; - for (int j = first; j < buf.size(); j++) tmp[i++] = buf[j]; - for (int j = 0 ; j < end ; j++) tmp[i++] = buf[j]; - first = 0; - end = buf.size(); - tmp.moveTo(buf); - } - } -}; - - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/Rnd.h b/yosys/libs/minisat/Rnd.h deleted file mode 100644 index ccb94c6ce..000000000 --- a/yosys/libs/minisat/Rnd.h +++ /dev/null @@ -1,67 +0,0 @@ -/*******************************************************************************************[Rnd.h] -Copyright (c) 2012, Niklas Sorensson -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Rnd_h -#define Minisat_Rnd_h - -#include "Vec.h" - -namespace Minisat { - -// Generate a random double: -static inline double drand(double& seed) -{ - seed *= 1389796; - int q = (int)(seed / 2147483647); - seed -= (double)q * 2147483647; - return seed / 2147483647; -} - - -// Generate a random integer: -static inline int irand(double& seed, int size) { return (int)(drand(seed) * size); } - - -// Randomly shuffle the contents of a vector: -template -static void randomShuffle(double& seed, vec& xs) -{ - for (int i = 0; i < xs.size(); i++){ - int pick = i + irand(seed, xs.size() - i); - T tmp = xs[i]; - xs[i] = xs[pick]; - xs[pick] = tmp; - } -} - -// Randomly shuffle a vector of a vector (ugly) -template -static void randomShuffle(double& seed, vec >& xs) -{ - for (int i = 0; i < xs.size(); i++){ - int pick = i + irand(seed, xs.size() - i); - vec tmp; xs[i].moveTo(tmp); - xs[pick].moveTo(xs[i]); - tmp.moveTo(xs[pick]); - } -} - - -//================================================================================================= -} // namespace Minisat -#endif diff --git a/yosys/libs/minisat/SimpSolver.cc b/yosys/libs/minisat/SimpSolver.cc deleted file mode 100644 index 7348a905d..000000000 --- a/yosys/libs/minisat/SimpSolver.cc +++ /dev/null @@ -1,731 +0,0 @@ -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif -/***********************************************************************************[SimpSolver.cc] -Copyright (c) 2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include "Sort.h" -#include "SimpSolver.h" -#include "System.h" - -using namespace Minisat; - -//================================================================================================= -// Options: - - -static const char* _cat = "SIMP"; - -static BoolOption opt_use_asymm (_cat, "asymm", "Shrink clauses by asymmetric branching.", false); -static BoolOption opt_use_rcheck (_cat, "rcheck", "Check if a clause is already implied. (costly)", false); -static BoolOption opt_use_elim (_cat, "elim", "Perform variable elimination.", true); -static IntOption opt_grow (_cat, "grow", "Allow a variable elimination step to grow by a number of clauses.", 0); -static IntOption opt_clause_lim (_cat, "cl-lim", "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20, IntRange(-1, INT32_MAX)); -static IntOption opt_subsumption_lim (_cat, "sub-lim", "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX)); -static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.", 0.5, DoubleRange(0, false, HUGE_VAL, false)); - - -//================================================================================================= -// Constructor/Destructor: - - -SimpSolver::SimpSolver() : - grow (opt_grow) - , clause_lim (opt_clause_lim) - , subsumption_lim (opt_subsumption_lim) - , simp_garbage_frac (opt_simp_garbage_frac) - , use_asymm (opt_use_asymm) - , use_rcheck (opt_use_rcheck) - , use_elim (opt_use_elim) - , extend_model (true) - , merges (0) - , asymm_lits (0) - , eliminated_vars (0) - , elimorder (1) - , use_simplification (true) - , occurs (ClauseDeleted(ca)) - , elim_heap (ElimLt(n_occ)) - , bwdsub_assigns (0) - , n_touched (0) -{ - vec dummy(1,lit_Undef); - ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below. - bwdsub_tmpunit = ca.alloc(dummy); - remove_satisfied = false; -} - - -SimpSolver::~SimpSolver() -{ -} - - -Var SimpSolver::newVar(lbool upol, bool dvar) { - Var v = Solver::newVar(upol, dvar); - - frozen .insert(v, (char)false); - eliminated.insert(v, (char)false); - - if (use_simplification){ - n_occ .insert( mkLit(v), 0); - n_occ .insert(~mkLit(v), 0); - occurs .init (v); - touched .insert(v, 0); - elim_heap .insert(v); - } - return v; } - - -void SimpSolver::releaseVar(Lit l) -{ - assert(!isEliminated(var(l))); - if (!use_simplification && var(l) >= max_simp_var) - // Note: Guarantees that no references to this variable is - // left in model extension datastructure. Could be improved! - Solver::releaseVar(l); - else - // Otherwise, don't allow variable to be reused. - Solver::addClause(l); -} - - -lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp) -{ - vec extra_frozen; - lbool result = l_True; - - do_simp &= use_simplification; - - if (do_simp){ - // Assumptions must be temporarily frozen to run variable elimination: - for (int i = 0; i < assumptions.size(); i++){ - Var v = var(assumptions[i]); - - // If an assumption has been eliminated, remember it. - assert(!isEliminated(v)); - - if (!frozen[v]){ - // Freeze and store. - setFrozen(v, true); - extra_frozen.push(v); - } } - - result = lbool(eliminate(turn_off_simp)); - } - - if (result == l_True) - result = Solver::solve_(); - else if (verbosity >= 1) - printf("===============================================================================\n"); - - if (result == l_True && extend_model) - extendModel(); - - if (do_simp) - // Unfreeze the assumptions that were frozen: - for (int i = 0; i < extra_frozen.size(); i++) - setFrozen(extra_frozen[i], false); - - return result; -} - - - -bool SimpSolver::addClause_(vec& ps) -{ -#ifndef NDEBUG - for (int i = 0; i < ps.size(); i++) - assert(!isEliminated(var(ps[i]))); -#endif - - int nclauses = clauses.size(); - - if (use_rcheck && implied(ps)) - return true; - - if (!Solver::addClause_(ps)) - return false; - - if (use_simplification && clauses.size() == nclauses + 1){ - CRef cr = clauses.last(); - const Clause& c = ca[cr]; - - // NOTE: the clause is added to the queue immediately and then - // again during 'gatherTouchedClauses()'. If nothing happens - // in between, it will only be checked once. Otherwise, it may - // be checked twice unnecessarily. This is an unfortunate - // consequence of how backward subsumption is used to mimic - // forward subsumption. - subsumption_queue.insert(cr); - for (int i = 0; i < c.size(); i++){ - occurs[var(c[i])].push(cr); - n_occ[c[i]]++; - touched[var(c[i])] = 1; - n_touched++; - if (elim_heap.inHeap(var(c[i]))) - elim_heap.increase(var(c[i])); - } - } - - return true; -} - - -void SimpSolver::removeClause(CRef cr) -{ - const Clause& c = ca[cr]; - - if (use_simplification) - for (int i = 0; i < c.size(); i++){ - n_occ[c[i]]--; - updateElimHeap(var(c[i])); - occurs.smudge(var(c[i])); - } - - Solver::removeClause(cr); -} - - -bool SimpSolver::strengthenClause(CRef cr, Lit l) -{ - Clause& c = ca[cr]; - assert(decisionLevel() == 0); - assert(use_simplification); - - // FIX: this is too inefficient but would be nice to have (properly implemented) - // if (!find(subsumption_queue, &c)) - subsumption_queue.insert(cr); - - if (c.size() == 2){ - removeClause(cr); - c.strengthen(l); - }else{ - detachClause(cr, true); - c.strengthen(l); - attachClause(cr); - remove(occurs[var(l)], cr); - n_occ[l]--; - updateElimHeap(var(l)); - } - - return c.size() == 1 ? enqueue(c[0]) && propagate() == CRef_Undef : true; -} - - -// Returns FALSE if clause is always satisfied ('out_clause' should not be used). -bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec& out_clause) -{ - merges++; - out_clause.clear(); - - bool ps_smallest = _ps.size() < _qs.size(); - const Clause& ps = ps_smallest ? _qs : _ps; - const Clause& qs = ps_smallest ? _ps : _qs; - - for (int i = 0; i < qs.size(); i++){ - if (var(qs[i]) != v){ - for (int j = 0; j < ps.size(); j++) - if (var(ps[j]) == var(qs[i])){ - if (ps[j] == ~qs[i]) - return false; - else - goto next; - } - out_clause.push(qs[i]); - } - next:; - } - - for (int i = 0; i < ps.size(); i++) - if (var(ps[i]) != v) - out_clause.push(ps[i]); - - return true; -} - - -// Returns FALSE if clause is always satisfied. -bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size) -{ - merges++; - - bool ps_smallest = _ps.size() < _qs.size(); - const Clause& ps = ps_smallest ? _qs : _ps; - const Clause& qs = ps_smallest ? _ps : _qs; - const Lit* __ps = (const Lit*)ps; - const Lit* __qs = (const Lit*)qs; - - size = ps.size()-1; - - for (int i = 0; i < qs.size(); i++){ - if (var(__qs[i]) != v){ - for (int j = 0; j < ps.size(); j++) - if (var(__ps[j]) == var(__qs[i])){ - if (__ps[j] == ~__qs[i]) - return false; - else - goto next; - } - size++; - } - next:; - } - - return true; -} - - -void SimpSolver::gatherTouchedClauses() -{ - if (n_touched == 0) return; - - int i,j; - for (i = j = 0; i < subsumption_queue.size(); i++) - if (ca[subsumption_queue[i]].mark() == 0) - ca[subsumption_queue[i]].mark(2); - - for (i = 0; i < nVars(); i++) - if (touched[i]){ - const vec& cs = occurs.lookup(i); - for (j = 0; j < cs.size(); j++) - if (ca[cs[j]].mark() == 0){ - subsumption_queue.insert(cs[j]); - ca[cs[j]].mark(2); - } - touched[i] = 0; - } - - for (i = 0; i < subsumption_queue.size(); i++) - if (ca[subsumption_queue[i]].mark() == 2) - ca[subsumption_queue[i]].mark(0); - - n_touched = 0; -} - - -bool SimpSolver::implied(const vec& c) -{ - assert(decisionLevel() == 0); - - trail_lim.push(trail.size()); - for (int i = 0; i < c.size(); i++) - if (value(c[i]) == l_True){ - cancelUntil(0); - return true; - }else if (value(c[i]) != l_False){ - assert(value(c[i]) == l_Undef); - uncheckedEnqueue(~c[i]); - } - - bool result = propagate() != CRef_Undef; - cancelUntil(0); - return result; -} - - -// Backward subsumption + backward subsumption resolution -bool SimpSolver::backwardSubsumptionCheck(bool verbose) -{ - int cnt = 0; - int subsumed = 0; - int deleted_literals = 0; - assert(decisionLevel() == 0); - - while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){ - - // Empty subsumption queue and return immediately on user-interrupt: - if (asynch_interrupt){ - subsumption_queue.clear(); - bwdsub_assigns = trail.size(); - break; } - - // Check top-level assignments by creating a dummy clause and placing it in the queue: - if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){ - Lit l = trail[bwdsub_assigns++]; - ca[bwdsub_tmpunit][0] = l; - ca[bwdsub_tmpunit].calcAbstraction(); - subsumption_queue.insert(bwdsub_tmpunit); } - - CRef cr = subsumption_queue.peek(); subsumption_queue.pop(); - Clause& c = ca[cr]; - - if (c.mark()) continue; - - if (verbose && verbosity >= 2 && cnt++ % 1000 == 0) - printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals); - - assert(c.size() > 1 || value(c[0]) == l_True); // Unit-clauses should have been propagated before this point. - - // Find best variable to scan: - Var best = var(c[0]); - for (int i = 1; i < c.size(); i++) - if (occurs[var(c[i])].size() < occurs[best].size()) - best = var(c[i]); - - // Search all candidates: - vec& _cs = occurs.lookup(best); - CRef* cs = (CRef*)_cs; - - for (int j = 0; j < _cs.size(); j++) - if (c.mark()) - break; - else if (!ca[cs[j]].mark() && cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){ - Lit l = c.subsumes(ca[cs[j]]); - - if (l == lit_Undef) - subsumed++, removeClause(cs[j]); - else if (l != lit_Error){ - deleted_literals++; - - if (!strengthenClause(cs[j], ~l)) - return false; - - // Did current candidate get deleted from cs? Then check candidate at index j again: - if (var(l) == best) - j--; - } - } - } - - return true; -} - - -bool SimpSolver::asymm(Var v, CRef cr) -{ - Clause& c = ca[cr]; - assert(decisionLevel() == 0); - - if (c.mark() || satisfied(c)) return true; - - trail_lim.push(trail.size()); - Lit l = lit_Undef; - for (int i = 0; i < c.size(); i++) - if (var(c[i]) != v && value(c[i]) != l_False) - uncheckedEnqueue(~c[i]); - else - l = c[i]; - - if (propagate() != CRef_Undef){ - cancelUntil(0); - asymm_lits++; - if (!strengthenClause(cr, l)) - return false; - }else - cancelUntil(0); - - return true; -} - - -bool SimpSolver::asymmVar(Var v) -{ - assert(use_simplification); - - const vec& cls = occurs.lookup(v); - - if (value(v) != l_Undef || cls.size() == 0) - return true; - - for (int i = 0; i < cls.size(); i++) - if (!asymm(v, cls[i])) - return false; - - return backwardSubsumptionCheck(); -} - - -static void mkElimClause(vec& elimclauses, Lit x) -{ - elimclauses.push(toInt(x)); - elimclauses.push(1); -} - - -static void mkElimClause(vec& elimclauses, Var v, Clause& c) -{ - int first = elimclauses.size(); - int v_pos = -1; - - // Copy clause to elimclauses-vector. Remember position where the - // variable 'v' occurs: - for (int i = 0; i < c.size(); i++){ - elimclauses.push(toInt(c[i])); - if (var(c[i]) == v) - v_pos = i + first; - } - assert(v_pos != -1); - - // Swap the first literal with the 'v' literal, so that the literal - // containing 'v' will occur first in the clause: - uint32_t tmp = elimclauses[v_pos]; - elimclauses[v_pos] = elimclauses[first]; - elimclauses[first] = tmp; - - // Store the length of the clause last: - elimclauses.push(c.size()); -} - - - -bool SimpSolver::eliminateVar(Var v) -{ - assert(!frozen[v]); - assert(!isEliminated(v)); - assert(value(v) == l_Undef); - - // Split the occurrences into positive and negative: - // - const vec& cls = occurs.lookup(v); - vec pos, neg; - for (int i = 0; i < cls.size(); i++) - (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]); - - // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no - // clause must exceed the limit on the maximal clause size (if it is set): - // - int cnt = 0; - int clause_size = 0; - - for (int i = 0; i < pos.size(); i++) - for (int j = 0; j < neg.size(); j++) - if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) && - (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim))) - return true; - - // Delete and store old clauses: - eliminated[v] = true; - setDecisionVar(v, false); - eliminated_vars++; - - if (pos.size() > neg.size()){ - for (int i = 0; i < neg.size(); i++) - mkElimClause(elimclauses, v, ca[neg[i]]); - mkElimClause(elimclauses, mkLit(v)); - }else{ - for (int i = 0; i < pos.size(); i++) - mkElimClause(elimclauses, v, ca[pos[i]]); - mkElimClause(elimclauses, ~mkLit(v)); - } - - for (int i = 0; i < cls.size(); i++) - removeClause(cls[i]); - - // Produce clauses in cross product: - vec& resolvent = add_tmp; - for (int i = 0; i < pos.size(); i++) - for (int j = 0; j < neg.size(); j++) - if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent)) - return false; - - // Free occurs list for this variable: - occurs[v].clear(true); - - // Free watchers lists for this variable, if possible: - if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true); - if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true); - - return backwardSubsumptionCheck(); -} - - -bool SimpSolver::substitute(Var v, Lit x) -{ - assert(!frozen[v]); - assert(!isEliminated(v)); - assert(value(v) == l_Undef); - - if (!ok) return false; - - eliminated[v] = true; - setDecisionVar(v, false); - const vec& cls = occurs.lookup(v); - - vec& subst_clause = add_tmp; - for (int i = 0; i < cls.size(); i++){ - Clause& c = ca[cls[i]]; - - subst_clause.clear(); - for (int j = 0; j < c.size(); j++){ - Lit p = c[j]; - subst_clause.push(var(p) == v ? x ^ sign(p) : p); - } - - removeClause(cls[i]); - - if (!addClause_(subst_clause)) - return ok = false; - } - - return true; -} - - -void SimpSolver::extendModel() -{ - int i, j; - Lit x; - - for (i = elimclauses.size()-1; i > 0; i -= j){ - for (j = elimclauses[i--]; j > 1; j--, i--) - if (modelValue(toLit(elimclauses[i])) != l_False) - goto next; - - x = toLit(elimclauses[i]); - model[var(x)] = lbool(!sign(x)); - next:; - } -} - - -bool SimpSolver::eliminate(bool turn_off_elim) -{ - if (!simplify()) - return false; - else if (!use_simplification) - return true; - - // Main simplification loop: - // - while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0){ - - gatherTouchedClauses(); - // printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns); - if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) && - !backwardSubsumptionCheck(true)){ - ok = false; goto cleanup; } - - // Empty elim_heap and return immediately on user-interrupt: - if (asynch_interrupt){ - assert(bwdsub_assigns == trail.size()); - assert(subsumption_queue.size() == 0); - assert(n_touched == 0); - elim_heap.clear(); - goto cleanup; } - - // printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size()); - for (int cnt = 0; !elim_heap.empty(); cnt++){ - Var elim = elim_heap.removeMin(); - - if (asynch_interrupt) break; - - if (isEliminated(elim) || value(elim) != l_Undef) continue; - - if (verbosity >= 2 && cnt % 100 == 0) - printf("elimination left: %10d\r", elim_heap.size()); - - if (use_asymm){ - // Temporarily freeze variable. Otherwise, it would immediately end up on the queue again: - bool was_frozen = frozen[elim]; - frozen[elim] = true; - if (!asymmVar(elim)){ - ok = false; goto cleanup; } - frozen[elim] = was_frozen; } - - // At this point, the variable may have been set by assymetric branching, so check it - // again. Also, don't eliminate frozen variables: - if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){ - ok = false; goto cleanup; } - - checkGarbage(simp_garbage_frac); - } - - assert(subsumption_queue.size() == 0); - } - cleanup: - - // If no more simplification is needed, free all simplification-related data structures: - if (turn_off_elim){ - touched .clear(true); - occurs .clear(true); - n_occ .clear(true); - elim_heap.clear(true); - subsumption_queue.clear(true); - - use_simplification = false; - remove_satisfied = true; - ca.extra_clause_field = false; - max_simp_var = nVars(); - - // Force full cleanup (this is safe and desirable since it only happens once): - rebuildOrderHeap(); - garbageCollect(); - }else{ - // Cheaper cleanup: - checkGarbage(); - } - - if (verbosity >= 1 && elimclauses.size() > 0) - printf("| Eliminated clauses: %10.2f Mb |\n", - double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024)); - - return ok; -} - - -//================================================================================================= -// Garbage Collection methods: - - -void SimpSolver::relocAll(ClauseAllocator& to) -{ - if (!use_simplification) return; - - // All occurs lists: - // - for (int i = 0; i < nVars(); i++){ - occurs.clean(i); - vec& cs = occurs[i]; - for (int j = 0; j < cs.size(); j++) - ca.reloc(cs[j], to); - } - - // Subsumption queue: - // - for (int i = subsumption_queue.size(); i > 0; i--){ - CRef cr = subsumption_queue.peek(); subsumption_queue.pop(); - if (ca[cr].mark()) continue; - ca.reloc(cr, to); - subsumption_queue.insert(cr); - } - - // Temporary clause: - // - ca.reloc(bwdsub_tmpunit, to); -} - - -void SimpSolver::garbageCollect() -{ - // Initialize the next region to a size corresponding to the estimated utilization degree. This - // is not precise but should avoid some unnecessary reallocations for the new region: - ClauseAllocator to(ca.size() - ca.wasted()); - - to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields. - relocAll(to); - Solver::relocAll(to); - if (verbosity >= 2) - printf("| Garbage collection: %12d bytes => %12d bytes |\n", - ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size); - to.moveTo(ca); -} diff --git a/yosys/libs/minisat/SimpSolver.h b/yosys/libs/minisat/SimpSolver.h deleted file mode 100644 index 76d5aca1f..000000000 --- a/yosys/libs/minisat/SimpSolver.h +++ /dev/null @@ -1,222 +0,0 @@ -/************************************************************************************[SimpSolver.h] -Copyright (c) 2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_SimpSolver_h -#define Minisat_SimpSolver_h - -#include "Queue.h" -#include "Solver.h" - - -namespace Minisat { - -//================================================================================================= - - -class SimpSolver : public Solver { - public: - // Constructor/Destructor: - // - SimpSolver(); - ~SimpSolver(); - - // Problem specification: - // - Var newVar (lbool upol = l_Undef, bool dvar = true); - void releaseVar(Lit l); - bool addClause (const vec& ps); - bool addEmptyClause(); // Add the empty clause to the solver. - bool addClause (Lit p); // Add a unit clause to the solver. - bool addClause (Lit p, Lit q); // Add a binary clause to the solver. - bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver. - bool addClause (Lit p, Lit q, Lit r, Lit s); // Add a quaternary clause to the solver. - bool addClause_( vec& ps); - bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction). - - // Variable mode: - // - void setFrozen (Var v, bool b); // If a variable is frozen it will not be eliminated. - bool isEliminated(Var v) const; - - // Alternative freeze interface (may replace 'setFrozen()'): - void freezeVar (Var v); // Freeze one variable so it will not be eliminated. - void thaw (); // Thaw all frozen variables. - - - // Solving: - // - bool solve (const vec& assumps, bool do_simp = true, bool turn_off_simp = false); - lbool solveLimited(const vec& assumps, bool do_simp = true, bool turn_off_simp = false); - bool solve ( bool do_simp = true, bool turn_off_simp = false); - bool solve (Lit p , bool do_simp = true, bool turn_off_simp = false); - bool solve (Lit p, Lit q, bool do_simp = true, bool turn_off_simp = false); - bool solve (Lit p, Lit q, Lit r, bool do_simp = true, bool turn_off_simp = false); - bool eliminate (bool turn_off_elim = false); // Perform variable elimination based simplification. - - // Memory managment: - // - virtual void garbageCollect(); - - - // Generate a (possibly simplified) DIMACS file: - // -#if 0 - void toDimacs (const char* file, const vec& assumps); - void toDimacs (const char* file); - void toDimacs (const char* file, Lit p); - void toDimacs (const char* file, Lit p, Lit q); - void toDimacs (const char* file, Lit p, Lit q, Lit r); -#endif - - // Mode of operation: - // - int grow; // Allow a variable elimination step to grow by a number of clauses (default to zero). - int clause_lim; // Variables are not eliminated if it produces a resolvent with a length above this limit. - // -1 means no limit. - int subsumption_lim; // Do not check if subsumption against a clause larger than this. -1 means no limit. - double simp_garbage_frac; // A different limit for when to issue a GC during simplification (Also see 'garbage_frac'). - - bool use_asymm; // Shrink clauses by asymmetric branching. - bool use_rcheck; // Check if a clause is already implied. Prett costly, and subsumes subsumptions :) - bool use_elim; // Perform variable elimination. - bool extend_model; // Flag to indicate whether the user needs to look at the full model. - - // Statistics: - // - int merges; - int asymm_lits; - int eliminated_vars; - - protected: - - // Helper structures: - // - struct ElimLt { - const LMap& n_occ; - explicit ElimLt(const LMap& no) : n_occ(no) {} - - // TODO: are 64-bit operations here noticably bad on 32-bit platforms? Could use a saturating - // 32-bit implementation instead then, but this will have to do for now. - uint64_t cost (Var x) const { return (uint64_t)n_occ[mkLit(x)] * (uint64_t)n_occ[~mkLit(x)]; } - bool operator()(Var x, Var y) const { return cost(x) < cost(y); } - - // TODO: investigate this order alternative more. - // bool operator()(Var x, Var y) const { - // int c_x = cost(x); - // int c_y = cost(y); - // return c_x < c_y || c_x == c_y && x < y; } - }; - - struct ClauseDeleted { - const ClauseAllocator& ca; - explicit ClauseDeleted(const ClauseAllocator& _ca) : ca(_ca) {} - bool operator()(const CRef& cr) const { return ca[cr].mark() == 1; } }; - - // Solver state: - // - int elimorder; - bool use_simplification; - Var max_simp_var; // Max variable at the point simplification was turned off. - vec elimclauses; - VMap touched; - OccLists, ClauseDeleted> - occurs; - LMap n_occ; - Heap elim_heap; - Queue subsumption_queue; - VMap frozen; - vec frozen_vars; - VMap eliminated; - int bwdsub_assigns; - int n_touched; - - // Temporaries: - // - CRef bwdsub_tmpunit; - - // Main internal methods: - // - lbool solve_ (bool do_simp = true, bool turn_off_simp = false); - bool asymm (Var v, CRef cr); - bool asymmVar (Var v); - void updateElimHeap (Var v); - void gatherTouchedClauses (); - bool merge (const Clause& _ps, const Clause& _qs, Var v, vec& out_clause); - bool merge (const Clause& _ps, const Clause& _qs, Var v, int& size); - bool backwardSubsumptionCheck (bool verbose = false); - bool eliminateVar (Var v); - void extendModel (); - - void removeClause (CRef cr); - bool strengthenClause (CRef cr, Lit l); - bool implied (const vec& c); - void relocAll (ClauseAllocator& to); -}; - - -//================================================================================================= -// Implementation of inline methods: - - -inline bool SimpSolver::isEliminated (Var v) const { return eliminated[v]; } -inline void SimpSolver::updateElimHeap(Var v) { - assert(use_simplification); - // if (!frozen[v] && !isEliminated(v) && value(v) == l_Undef) - if (elim_heap.inHeap(v) || (!frozen[v] && !isEliminated(v) && value(v) == l_Undef)) - elim_heap.update(v); } - - -inline bool SimpSolver::addClause (const vec& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); } -inline bool SimpSolver::addEmptyClause() { add_tmp.clear(); return addClause_(add_tmp); } -inline bool SimpSolver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); } -inline bool SimpSolver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); } -inline bool SimpSolver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); } -inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, Lit s){ add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); add_tmp.push(s); return addClause_(add_tmp); } -inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } } - -inline void SimpSolver::freezeVar(Var v){ - if (!frozen[v]){ - frozen[v] = 1; - frozen_vars.push(v); - } } - -inline void SimpSolver::thaw(){ - for (int i = 0; i < frozen_vars.size(); i++){ - Var v = frozen_vars[i]; - frozen[v] = 0; - if (use_simplification) - updateElimHeap(v); - } - frozen_vars.clear(); } - -inline bool SimpSolver::solve ( bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); return solve_(do_simp, turn_off_simp) == l_True; } -inline bool SimpSolver::solve (Lit p , bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_(do_simp, turn_off_simp) == l_True; } -inline bool SimpSolver::solve (Lit p, Lit q, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_(do_simp, turn_off_simp) == l_True; } -inline bool SimpSolver::solve (Lit p, Lit q, Lit r, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_(do_simp, turn_off_simp) == l_True; } -inline bool SimpSolver::solve (const vec& assumps, bool do_simp, bool turn_off_simp){ - budgetOff(); assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp) == l_True; } - -inline lbool SimpSolver::solveLimited (const vec& assumps, bool do_simp, bool turn_off_simp){ - assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp); } - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/Solver.cc b/yosys/libs/minisat/Solver.cc deleted file mode 100644 index f6d4fb5ae..000000000 --- a/yosys/libs/minisat/Solver.cc +++ /dev/null @@ -1,1072 +0,0 @@ -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif -/***************************************************************************************[Solver.cc] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include - -#include "Alg.h" -#include "Sort.h" -#include "System.h" -#include "Solver.h" - -using namespace Minisat; - -//================================================================================================= -// Options: - - -static const char* _cat = "CORE"; - -static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.95, DoubleRange(0, false, 1, false)); -static DoubleOption opt_clause_decay (_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false)); -static DoubleOption opt_random_var_freq (_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true)); -static DoubleOption opt_random_seed (_cat, "rnd-seed", "Used by the random variable selection", 91648253, DoubleRange(0, false, HUGE_VAL, false)); -static IntOption opt_ccmin_mode (_cat, "ccmin-mode", "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 2, IntRange(0, 2)); -static IntOption opt_phase_saving (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2)); -static BoolOption opt_rnd_init_act (_cat, "rnd-init", "Randomize the initial activity", false); -static BoolOption opt_luby_restart (_cat, "luby", "Use the Luby restart sequence", true); -static IntOption opt_restart_first (_cat, "rfirst", "The base restart interval", 100, IntRange(1, INT32_MAX)); -static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interval increase factor", 2, DoubleRange(1, false, HUGE_VAL, false)); -static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false)); -static IntOption opt_min_learnts_lim (_cat, "min-learnts", "Minimum learnt clause limit", 0, IntRange(0, INT32_MAX)); - - -//================================================================================================= -// Constructor/Destructor: - - -Solver::Solver() : - - // Parameters (user settable): - // - verbosity (0) - , var_decay (opt_var_decay) - , clause_decay (opt_clause_decay) - , random_var_freq (opt_random_var_freq) - , random_seed (opt_random_seed) - , luby_restart (opt_luby_restart) - , ccmin_mode (opt_ccmin_mode) - , phase_saving (opt_phase_saving) - , rnd_pol (false) - , rnd_init_act (opt_rnd_init_act) - , garbage_frac (opt_garbage_frac) - , min_learnts_lim (opt_min_learnts_lim) - , restart_first (opt_restart_first) - , restart_inc (opt_restart_inc) - - // Parameters (the rest): - // - , learntsize_factor((double)1/(double)3), learntsize_inc(1.1) - - // Parameters (experimental): - // - , learntsize_adjust_start_confl (100) - , learntsize_adjust_inc (1.5) - - // Statistics: (formerly in 'SolverStats') - // - , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0) - , dec_vars(0), num_clauses(0), num_learnts(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0) - - , watches (WatcherDeleted(ca)) - , order_heap (VarOrderLt(activity)) - , ok (true) - , cla_inc (1) - , var_inc (1) - , qhead (0) - , simpDB_assigns (-1) - , simpDB_props (0) - , progress_estimate (0) - , remove_satisfied (true) - , next_var (0) - - // Resource constraints: - // - , conflict_budget (-1) - , propagation_budget (-1) - , asynch_interrupt (false) -{} - - -Solver::~Solver() -{ -} - - -//================================================================================================= -// Minor methods: - - -// Creates a new SAT variable in the solver. If 'decision' is cleared, variable will not be -// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result). -// -Var Solver::newVar(lbool upol, bool dvar) -{ - Var v; - if (free_vars.size() > 0){ - v = free_vars.last(); - free_vars.pop(); - }else - v = next_var++; - - watches .init(mkLit(v, false)); - watches .init(mkLit(v, true )); - assigns .insert(v, l_Undef); - vardata .insert(v, mkVarData(CRef_Undef, 0)); - activity .insert(v, rnd_init_act ? drand(random_seed) * 0.00001 : 0); - seen .insert(v, 0); - polarity .insert(v, true); - user_pol .insert(v, upol); - decision .reserve(v); - trail .capacity(v+1); - setDecisionVar(v, dvar); - return v; -} - - -// Note: at the moment, only unassigned variable will be released (this is to avoid duplicate -// releases of the same variable). -void Solver::releaseVar(Lit l) -{ - if (value(l) == l_Undef){ - addClause(l); - released_vars.push(var(l)); - } -} - - -bool Solver::addClause_(vec& ps) -{ - assert(decisionLevel() == 0); - if (!ok) return false; - - // Check if clause is satisfied and remove false/duplicate literals: - sort(ps); - Lit p; int i, j; - for (i = j = 0, p = lit_Undef; i < ps.size(); i++) - if (value(ps[i]) == l_True || ps[i] == ~p) - return true; - else if (value(ps[i]) != l_False && ps[i] != p) - ps[j++] = p = ps[i]; - ps.shrink(i - j); - - if (ps.size() == 0) - return ok = false; - else if (ps.size() == 1){ - uncheckedEnqueue(ps[0]); - return ok = (propagate() == CRef_Undef); - }else{ - CRef cr = ca.alloc(ps, false); - clauses.push(cr); - attachClause(cr); - } - - return true; -} - - -void Solver::attachClause(CRef cr){ - const Clause& c = ca[cr]; - assert(c.size() > 1); - watches[~c[0]].push(Watcher(cr, c[1])); - watches[~c[1]].push(Watcher(cr, c[0])); - if (c.learnt()) num_learnts++, learnts_literals += c.size(); - else num_clauses++, clauses_literals += c.size(); -} - - -void Solver::detachClause(CRef cr, bool strict){ - const Clause& c = ca[cr]; - assert(c.size() > 1); - - // Strict or lazy detaching: - if (strict){ - remove(watches[~c[0]], Watcher(cr, c[1])); - remove(watches[~c[1]], Watcher(cr, c[0])); - }else{ - watches.smudge(~c[0]); - watches.smudge(~c[1]); - } - - if (c.learnt()) num_learnts--, learnts_literals -= c.size(); - else num_clauses--, clauses_literals -= c.size(); -} - - -void Solver::removeClause(CRef cr) { - Clause& c = ca[cr]; - detachClause(cr); - // Don't leave pointers to free'd memory! - if (locked(c)) vardata[var(c[0])].reason = CRef_Undef; - c.mark(1); - ca.free(cr); -} - - -bool Solver::satisfied(const Clause& c) const { - for (int i = 0; i < c.size(); i++) - if (value(c[i]) == l_True) - return true; - return false; } - - -// Revert to the state at given level (keeping all assignment at 'level' but not beyond). -// -void Solver::cancelUntil(int level) { - if (decisionLevel() > level){ - for (int c = trail.size()-1; c >= trail_lim[level]; c--){ - Var x = var(trail[c]); - assigns [x] = l_Undef; - if (phase_saving > 1 || (phase_saving == 1 && c > trail_lim.last())) - polarity[x] = sign(trail[c]); - insertVarOrder(x); } - qhead = trail_lim[level]; - trail.shrink(trail.size() - trail_lim[level]); - trail_lim.shrink(trail_lim.size() - level); - } } - - -//================================================================================================= -// Major methods: - - -Lit Solver::pickBranchLit() -{ - Var next = var_Undef; - - // Random decision: - if (drand(random_seed) < random_var_freq && !order_heap.empty()){ - next = order_heap[irand(random_seed,order_heap.size())]; - if (value(next) == l_Undef && decision[next]) - rnd_decisions++; } - - // Activity based decision: - while (next == var_Undef || value(next) != l_Undef || !decision[next]) - if (order_heap.empty()){ - next = var_Undef; - break; - }else - next = order_heap.removeMin(); - - // Choose polarity based on different polarity modes (global or per-variable): - if (next == var_Undef) - return lit_Undef; - else if (user_pol[next] != l_Undef) - return mkLit(next, user_pol[next] == l_True); - else if (rnd_pol) - return mkLit(next, drand(random_seed) < 0.5); - else - return mkLit(next, polarity[next]); -} - - -/*_________________________________________________________________________________________________ -| -| analyze : (confl : Clause*) (out_learnt : vec&) (out_btlevel : int&) -> [void] -| -| Description: -| Analyze conflict and produce a reason clause. -| -| Pre-conditions: -| * 'out_learnt' is assumed to be cleared. -| * Current decision level must be greater than root level. -| -| Post-conditions: -| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'. -| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the -| rest of literals. There may be others from the same level though. -| -|________________________________________________________________________________________________@*/ -void Solver::analyze(CRef confl, vec& out_learnt, int& out_btlevel) -{ - int pathC = 0; - Lit p = lit_Undef; - - // Generate conflict clause: - // - out_learnt.push(); // (leave room for the asserting literal) - int index = trail.size() - 1; - - do{ - assert(confl != CRef_Undef); // (otherwise should be UIP) - Clause& c = ca[confl]; - - if (c.learnt()) - claBumpActivity(c); - - for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){ - Lit q = c[j]; - - if (!seen[var(q)] && level(var(q)) > 0){ - varBumpActivity(var(q)); - seen[var(q)] = 1; - if (level(var(q)) >= decisionLevel()) - pathC++; - else - out_learnt.push(q); - } - } - - // Select next clause to look at: - while (!seen[var(trail[index--])]); - p = trail[index+1]; - confl = reason(var(p)); - seen[var(p)] = 0; - pathC--; - - }while (pathC > 0); - out_learnt[0] = ~p; - - // Simplify conflict clause: - // - int i, j; - out_learnt.copyTo(analyze_toclear); - if (ccmin_mode == 2){ - for (i = j = 1; i < out_learnt.size(); i++) - if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i])) - out_learnt[j++] = out_learnt[i]; - - }else if (ccmin_mode == 1){ - for (i = j = 1; i < out_learnt.size(); i++){ - Var x = var(out_learnt[i]); - - if (reason(x) == CRef_Undef) - out_learnt[j++] = out_learnt[i]; - else{ - Clause& c = ca[reason(var(out_learnt[i]))]; - for (int k = 1; k < c.size(); k++) - if (!seen[var(c[k])] && level(var(c[k])) > 0){ - out_learnt[j++] = out_learnt[i]; - break; } - } - } - }else - i = j = out_learnt.size(); - - max_literals += out_learnt.size(); - out_learnt.shrink(i - j); - tot_literals += out_learnt.size(); - - // Find correct backtrack level: - // - if (out_learnt.size() == 1) - out_btlevel = 0; - else{ - int max_i = 1; - // Find the first literal assigned at the next-highest level: - for (int i = 2; i < out_learnt.size(); i++) - if (level(var(out_learnt[i])) > level(var(out_learnt[max_i]))) - max_i = i; - // Swap-in this literal at index 1: - Lit p = out_learnt[max_i]; - out_learnt[max_i] = out_learnt[1]; - out_learnt[1] = p; - out_btlevel = level(var(p)); - } - - for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared) -} - - -// Check if 'p' can be removed from a conflict clause. -bool Solver::litRedundant(Lit p) -{ - enum { seen_undef = 0, seen_source = 1, seen_removable = 2, seen_failed = 3 }; - assert(seen[var(p)] == seen_undef || seen[var(p)] == seen_source); - assert(reason(var(p)) != CRef_Undef); - - Clause* c = &ca[reason(var(p))]; - vec& stack = analyze_stack; - stack.clear(); - - for (uint32_t i = 1; ; i++){ - if (i < (uint32_t)c->size()){ - // Checking 'p'-parents 'l': - Lit l = (*c)[i]; - - // Variable at level 0 or previously removable: - if (level(var(l)) == 0 || seen[var(l)] == seen_source || seen[var(l)] == seen_removable){ - continue; } - - // Check variable can not be removed for some local reason: - if (reason(var(l)) == CRef_Undef || seen[var(l)] == seen_failed){ - stack.push(ShrinkStackElem(0, p)); - for (int i = 0; i < stack.size(); i++) - if (seen[var(stack[i].l)] == seen_undef){ - seen[var(stack[i].l)] = seen_failed; - analyze_toclear.push(stack[i].l); - } - - return false; - } - - // Recursively check 'l': - stack.push(ShrinkStackElem(i, p)); - i = 0; - p = l; - c = &ca[reason(var(p))]; - }else{ - // Finished with current element 'p' and reason 'c': - if (seen[var(p)] == seen_undef){ - seen[var(p)] = seen_removable; - analyze_toclear.push(p); - } - - // Terminate with success if stack is empty: - if (stack.size() == 0) break; - - // Continue with top element on stack: - i = stack.last().i; - p = stack.last().l; - c = &ca[reason(var(p))]; - - stack.pop(); - } - } - - return true; -} - - -/*_________________________________________________________________________________________________ -| -| analyzeFinal : (p : Lit) -> [void] -| -| Description: -| Specialized analysis procedure to express the final conflict in terms of assumptions. -| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and -| stores the result in 'out_conflict'. -|________________________________________________________________________________________________@*/ -void Solver::analyzeFinal(Lit p, LSet& out_conflict) -{ - out_conflict.clear(); - out_conflict.insert(p); - - if (decisionLevel() == 0) - return; - - seen[var(p)] = 1; - - for (int i = trail.size()-1; i >= trail_lim[0]; i--){ - Var x = var(trail[i]); - if (seen[x]){ - if (reason(x) == CRef_Undef){ - assert(level(x) > 0); - out_conflict.insert(~trail[i]); - }else{ - Clause& c = ca[reason(x)]; - for (int j = 1; j < c.size(); j++) - if (level(var(c[j])) > 0) - seen[var(c[j])] = 1; - } - seen[x] = 0; - } - } - - seen[var(p)] = 0; -} - - -void Solver::uncheckedEnqueue(Lit p, CRef from) -{ - assert(value(p) == l_Undef); - assigns[var(p)] = lbool(!sign(p)); - vardata[var(p)] = mkVarData(from, decisionLevel()); - trail.push_(p); -} - - -/*_________________________________________________________________________________________________ -| -| propagate : [void] -> [Clause*] -| -| Description: -| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned, -| otherwise CRef_Undef. -| -| Post-conditions: -| * the propagation queue is empty, even if there was a conflict. -|________________________________________________________________________________________________@*/ -CRef Solver::propagate() -{ - CRef confl = CRef_Undef; - int num_props = 0; - - while (qhead < trail.size()){ - Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate. - vec& ws = watches.lookup(p); - Watcher *i, *j, *end; - num_props++; - - for (i = j = (Watcher*)ws, end = i + ws.size(); i != end;){ - // Try to avoid inspecting the clause: - Lit blocker = i->blocker; - if (value(blocker) == l_True){ - *j++ = *i++; continue; } - - // Make sure the false literal is data[1]: - CRef cr = i->cref; - Clause& c = ca[cr]; - Lit false_lit = ~p; - if (c[0] == false_lit) - c[0] = c[1], c[1] = false_lit; - assert(c[1] == false_lit); - i++; - - // If 0th watch is true, then clause is already satisfied. - Lit first = c[0]; - Watcher w = Watcher(cr, first); - if (first != blocker && value(first) == l_True){ - *j++ = w; continue; } - - // Look for new watch: - for (int k = 2; k < c.size(); k++) - if (value(c[k]) != l_False){ - c[1] = c[k]; c[k] = false_lit; - watches[~c[1]].push(w); - goto NextClause; } - - // Did not find watch -- clause is unit under assignment: - *j++ = w; - if (value(first) == l_False){ - confl = cr; - qhead = trail.size(); - // Copy the remaining watches: - while (i < end) - *j++ = *i++; - }else - uncheckedEnqueue(first, cr); - - NextClause:; - } - ws.shrink(i - j); - } - propagations += num_props; - simpDB_props -= num_props; - - return confl; -} - - -/*_________________________________________________________________________________________________ -| -| reduceDB : () -> [void] -| -| Description: -| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked -| clauses are clauses that are reason to some assignment. Binary clauses are never removed. -|________________________________________________________________________________________________@*/ -struct reduceDB_lt { - ClauseAllocator& ca; - reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {} - bool operator () (CRef x, CRef y) { - return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); } -}; -void Solver::reduceDB() -{ - int i, j; - double extra_lim = cla_inc / learnts.size(); // Remove any clause below this activity - - sort(learnts, reduceDB_lt(ca)); - // Don't delete binary or locked clauses. From the rest, delete clauses from the first half - // and clauses with activity smaller than 'extra_lim': - for (i = j = 0; i < learnts.size(); i++){ - Clause& c = ca[learnts[i]]; - if (c.size() > 2 && !locked(c) && (i < learnts.size() / 2 || c.activity() < extra_lim)) - removeClause(learnts[i]); - else - learnts[j++] = learnts[i]; - } - learnts.shrink(i - j); - checkGarbage(); -} - - -void Solver::removeSatisfied(vec& cs) -{ - int i, j; - for (i = j = 0; i < cs.size(); i++){ - Clause& c = ca[cs[i]]; - if (satisfied(c)) - removeClause(cs[i]); - else{ - // Trim clause: - assert(value(c[0]) == l_Undef && value(c[1]) == l_Undef); - for (int k = 2; k < c.size(); k++) - if (value(c[k]) == l_False){ - c[k--] = c[c.size()-1]; - c.pop(); - } - cs[j++] = cs[i]; - } - } - cs.shrink(i - j); -} - - -void Solver::rebuildOrderHeap() -{ - vec vs; - for (Var v = 0; v < nVars(); v++) - if (decision[v] && value(v) == l_Undef) - vs.push(v); - order_heap.build(vs); -} - - -/*_________________________________________________________________________________________________ -| -| simplify : [void] -> [bool] -| -| Description: -| Simplify the clause database according to the current top-level assigment. Currently, the only -| thing done here is the removal of satisfied clauses, but more things can be put here. -|________________________________________________________________________________________________@*/ -bool Solver::simplify() -{ - assert(decisionLevel() == 0); - - if (!ok || propagate() != CRef_Undef) - return ok = false; - - if (nAssigns() == simpDB_assigns || (simpDB_props > 0)) - return true; - - // Remove satisfied clauses: - removeSatisfied(learnts); - if (remove_satisfied){ // Can be turned off. - removeSatisfied(clauses); - - // TODO: what todo in if 'remove_satisfied' is false? - - // Remove all released variables from the trail: - for (int i = 0; i < released_vars.size(); i++){ - assert(seen[released_vars[i]] == 0); - seen[released_vars[i]] = 1; - } - - int i, j; - for (i = j = 0; i < trail.size(); i++) - if (seen[var(trail[i])] == 0) - trail[j++] = trail[i]; - trail.shrink(i - j); - //printf("trail.size()= %d, qhead = %d\n", trail.size(), qhead); - qhead = trail.size(); - - for (int i = 0; i < released_vars.size(); i++) - seen[released_vars[i]] = 0; - - // Released variables are now ready to be reused: - append(released_vars, free_vars); - released_vars.clear(); - } - checkGarbage(); - rebuildOrderHeap(); - - simpDB_assigns = nAssigns(); - simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now) - - return true; -} - - -/*_________________________________________________________________________________________________ -| -| search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool] -| -| Description: -| Search for a model the specified number of conflicts. -| NOTE! Use negative value for 'nof_conflicts' indicate infinity. -| -| Output: -| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If -| all variables are decision variables, this means that the clause set is satisfiable. 'l_False' -| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached. -|________________________________________________________________________________________________@*/ -lbool Solver::search(int nof_conflicts) -{ - assert(ok); - int backtrack_level; - int conflictC = 0; - vec learnt_clause; - starts++; - - for (;;){ - CRef confl = propagate(); - if (confl != CRef_Undef){ - // CONFLICT - conflicts++; conflictC++; - if (decisionLevel() == 0) return l_False; - - learnt_clause.clear(); - analyze(confl, learnt_clause, backtrack_level); - cancelUntil(backtrack_level); - - if (learnt_clause.size() == 1){ - uncheckedEnqueue(learnt_clause[0]); - }else{ - CRef cr = ca.alloc(learnt_clause, true); - learnts.push(cr); - attachClause(cr); - claBumpActivity(ca[cr]); - uncheckedEnqueue(learnt_clause[0], cr); - } - - varDecayActivity(); - claDecayActivity(); - - if (--learntsize_adjust_cnt == 0){ - learntsize_adjust_confl *= learntsize_adjust_inc; - learntsize_adjust_cnt = (int)learntsize_adjust_confl; - max_learnts *= learntsize_inc; - - if (verbosity >= 1) - printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", - (int)conflicts, - (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals, - (int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100); - } - - }else{ - // NO CONFLICT - if ((nof_conflicts >= 0 && conflictC >= nof_conflicts) || !withinBudget()){ - // Reached bound on number of conflicts: - progress_estimate = progressEstimate(); - cancelUntil(0); - return l_Undef; } - - // Simplify the set of problem clauses: - if (decisionLevel() == 0 && !simplify()) - return l_False; - - if (learnts.size()-nAssigns() >= max_learnts) - // Reduce the set of learnt clauses: - reduceDB(); - - Lit next = lit_Undef; - while (decisionLevel() < assumptions.size()){ - // Perform user provided assumption: - Lit p = assumptions[decisionLevel()]; - if (value(p) == l_True){ - // Dummy decision level: - newDecisionLevel(); - }else if (value(p) == l_False){ - analyzeFinal(~p, conflict); - return l_False; - }else{ - next = p; - break; - } - } - - if (next == lit_Undef){ - // New variable decision: - decisions++; - next = pickBranchLit(); - - if (next == lit_Undef) - // Model found: - return l_True; - } - - // Increase decision level and enqueue 'next' - newDecisionLevel(); - uncheckedEnqueue(next); - } - } -} - - -double Solver::progressEstimate() const -{ - double progress = 0; - double F = 1.0 / nVars(); - - for (int i = 0; i <= decisionLevel(); i++){ - int beg = i == 0 ? 0 : trail_lim[i - 1]; - int end = i == decisionLevel() ? trail.size() : trail_lim[i]; - progress += pow(F, i) * (end - beg); - } - - return progress / nVars(); -} - -/* - Finite subsequences of the Luby-sequence: - - 0: 1 - 1: 1 1 2 - 2: 1 1 2 1 1 2 4 - 3: 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8 - ... - - - */ - -static double luby(double y, int x){ - - // Find the finite subsequence that contains index 'x', and the - // size of that subsequence: - int size, seq; - for (size = 1, seq = 0; size < x+1; seq++, size = 2*size+1); - - while (size-1 != x){ - size = (size-1)>>1; - seq--; - x = x % size; - } - - return pow(y, seq); -} - -// NOTE: assumptions passed in member-variable 'assumptions'. -lbool Solver::solve_() -{ - model.clear(); - conflict.clear(); - if (!ok) return l_False; - - solves++; - - max_learnts = nClauses() * learntsize_factor; - if (max_learnts < min_learnts_lim) - max_learnts = min_learnts_lim; - - learntsize_adjust_confl = learntsize_adjust_start_confl; - learntsize_adjust_cnt = (int)learntsize_adjust_confl; - lbool status = l_Undef; - - if (verbosity >= 1){ - printf("============================[ Search Statistics ]==============================\n"); - printf("| Conflicts | ORIGINAL | LEARNT | Progress |\n"); - printf("| | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n"); - printf("===============================================================================\n"); - } - - // Search: - int curr_restarts = 0; - while (status == l_Undef){ - double rest_base = luby_restart ? luby(restart_inc, curr_restarts) : pow(restart_inc, curr_restarts); - status = search(rest_base * restart_first); - if (!withinBudget()) break; - curr_restarts++; - } - - if (verbosity >= 1) - printf("===============================================================================\n"); - - - if (status == l_True){ - // Extend & copy model: - model.growTo(nVars()); - for (int i = 0; i < nVars(); i++) model[i] = value(i); - }else if (status == l_False && conflict.size() == 0) - ok = false; - - cancelUntil(0); - return status; -} - - -bool Solver::implies(const vec& assumps, vec& out) -{ - trail_lim.push(trail.size()); - for (int i = 0; i < assumps.size(); i++){ - Lit a = assumps[i]; - - if (value(a) == l_False){ - cancelUntil(0); - return false; - }else if (value(a) == l_Undef) - uncheckedEnqueue(a); - } - - unsigned trail_before = trail.size(); - bool ret = true; - if (propagate() == CRef_Undef){ - out.clear(); - for (int j = trail_before; j < trail.size(); j++) - out.push(trail[j]); - }else - ret = false; - - cancelUntil(0); - return ret; -} - -//================================================================================================= -// Writing CNF to DIMACS: -// -// FIXME: this needs to be rewritten completely. - -static Var mapVar(Var x, vec& map, Var& max) -{ - if (map.size() <= x || map[x] == -1){ - map.growTo(x+1, -1); - map[x] = max++; - } - return map[x]; -} - - -void Solver::toDimacs(FILE* f, Clause& c, vec& map, Var& max) -{ - if (satisfied(c)) return; - - for (int i = 0; i < c.size(); i++) - if (value(c[i]) != l_False) - fprintf(f, "%s%d ", sign(c[i]) ? "-" : "", mapVar(var(c[i]), map, max)+1); - fprintf(f, "0\n"); -} - - -void Solver::toDimacs(const char *file, const vec& assumps) -{ - FILE* f = fopen(file, "wr"); - if (f == NULL) - fprintf(stderr, "could not open file %s\n", file), exit(1); - toDimacs(f, assumps); - fclose(f); -} - - -void Solver::toDimacs(FILE* f, const vec& assumps) -{ - // Handle case when solver is in contradictory state: - if (!ok){ - fprintf(f, "p cnf 1 2\n1 0\n-1 0\n"); - return; } - - vec map; Var max = 0; - - // Cannot use removeClauses here because it is not safe - // to deallocate them at this point. Could be improved. - int cnt = 0; - for (int i = 0; i < clauses.size(); i++) - if (!satisfied(ca[clauses[i]])) - cnt++; - - for (int i = 0; i < clauses.size(); i++) - if (!satisfied(ca[clauses[i]])){ - Clause& c = ca[clauses[i]]; - for (int j = 0; j < c.size(); j++) - if (value(c[j]) != l_False) - mapVar(var(c[j]), map, max); - } - - // Assumptions are added as unit clauses: - cnt += assumps.size(); - - fprintf(f, "p cnf %d %d\n", max, cnt); - - for (int i = 0; i < assumps.size(); i++){ - assert(value(assumps[i]) != l_False); - fprintf(f, "%s%d 0\n", sign(assumps[i]) ? "-" : "", mapVar(var(assumps[i]), map, max)+1); - } - - for (int i = 0; i < clauses.size(); i++) - toDimacs(f, ca[clauses[i]], map, max); - - if (verbosity > 0) - printf("Wrote DIMACS with %d variables and %d clauses.\n", max, cnt); -} - - -void Solver::printStats() const -{ - double cpu_time = cpuTime(); - double mem_used = memUsedPeak(); - printf("restarts : %" PRIu64 "\n", starts); - printf("conflicts : %-12" PRIu64 " (%.0f /sec)\n", conflicts , conflicts /cpu_time); - printf("decisions : %-12" PRIu64 " (%4.2f %% random) (%.0f /sec)\n", decisions, (float)rnd_decisions*100 / (float)decisions, decisions /cpu_time); - printf("propagations : %-12" PRIu64 " (%.0f /sec)\n", propagations, propagations/cpu_time); - printf("conflict literals : %-12" PRIu64 " (%4.2f %% deleted)\n", tot_literals, (max_literals - tot_literals)*100 / (double)max_literals); - if (mem_used != 0) printf("Memory used : %.2f MB\n", mem_used); - printf("CPU time : %g s\n", cpu_time); -} - - -//================================================================================================= -// Garbage Collection methods: - -void Solver::relocAll(ClauseAllocator& to) -{ - // All watchers: - // - watches.cleanAll(); - for (int v = 0; v < nVars(); v++) - for (int s = 0; s < 2; s++){ - Lit p = mkLit(v, s); - vec& ws = watches[p]; - for (int j = 0; j < ws.size(); j++) - ca.reloc(ws[j].cref, to); - } - - // All reasons: - // - for (int i = 0; i < trail.size(); i++){ - Var v = var(trail[i]); - - // Note: it is not safe to call 'locked()' on a relocated clause. This is why we keep - // 'dangling' reasons here. It is safe and does not hurt. - if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)]))){ - assert(!isRemoved(reason(v))); - ca.reloc(vardata[v].reason, to); - } - } - - // All learnt: - // - int i, j; - for (i = j = 0; i < learnts.size(); i++) - if (!isRemoved(learnts[i])){ - ca.reloc(learnts[i], to); - learnts[j++] = learnts[i]; - } - learnts.shrink(i - j); - - // All original: - // - for (i = j = 0; i < clauses.size(); i++) - if (!isRemoved(clauses[i])){ - ca.reloc(clauses[i], to); - clauses[j++] = clauses[i]; - } - clauses.shrink(i - j); -} - - -void Solver::garbageCollect() -{ - // Initialize the next region to a size corresponding to the estimated utilization degree. This - // is not precise but should avoid some unnecessary reallocations for the new region: - ClauseAllocator to(ca.size() - ca.wasted()); - - relocAll(to); - if (verbosity >= 2) - printf("| Garbage collection: %12d bytes => %12d bytes |\n", - ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size); - to.moveTo(ca); -} diff --git a/yosys/libs/minisat/Solver.h b/yosys/libs/minisat/Solver.h deleted file mode 100644 index 44570b0e1..000000000 --- a/yosys/libs/minisat/Solver.h +++ /dev/null @@ -1,409 +0,0 @@ -/****************************************************************************************[Solver.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Solver_h -#define Minisat_Solver_h - -#include "Vec.h" -#include "Heap.h" -#include "Alg.h" -#include "IntMap.h" -#include "Options.h" -#include "SolverTypes.h" - - -namespace Minisat { - -//================================================================================================= -// Solver -- the main class: - -class Solver { -public: - - // Constructor/Destructor: - // - Solver(); - virtual ~Solver(); - - // Problem specification: - // - Var newVar (lbool upol = l_Undef, bool dvar = true); // Add a new variable with parameters specifying variable mode. - void releaseVar(Lit l); // Make literal true and promise to never refer to variable again. - - bool addClause (const vec& ps); // Add a clause to the solver. - bool addEmptyClause(); // Add the empty clause, making the solver contradictory. - bool addClause (Lit p); // Add a unit clause to the solver. - bool addClause (Lit p, Lit q); // Add a binary clause to the solver. - bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver. - bool addClause (Lit p, Lit q, Lit r, Lit s); // Add a quaternary clause to the solver. - bool addClause_( vec& ps); // Add a clause to the solver without making superflous internal copy. Will - // change the passed vector 'ps'. - - // Solving: - // - bool simplify (); // Removes already satisfied clauses. - bool solve (const vec& assumps); // Search for a model that respects a given set of assumptions. - lbool solveLimited (const vec& assumps); // Search for a model that respects a given set of assumptions (With resource constraints). - bool solve (); // Search without assumptions. - bool solve (Lit p); // Search for a model that respects a single assumption. - bool solve (Lit p, Lit q); // Search for a model that respects two assumptions. - bool solve (Lit p, Lit q, Lit r); // Search for a model that respects three assumptions. - bool okay () const; // FALSE means solver is in a conflicting state - - bool implies (const vec& assumps, vec& out); - - // Iterate over clauses and top-level assignments: - ClauseIterator clausesBegin() const; - ClauseIterator clausesEnd() const; - TrailIterator trailBegin() const; - TrailIterator trailEnd () const; - - void toDimacs (FILE* f, const vec& assumps); // Write CNF to file in DIMACS-format. - void toDimacs (const char *file, const vec& assumps); - void toDimacs (FILE* f, Clause& c, vec& map, Var& max); - - // Convenience versions of 'toDimacs()': - void toDimacs (const char* file); - void toDimacs (const char* file, Lit p); - void toDimacs (const char* file, Lit p, Lit q); - void toDimacs (const char* file, Lit p, Lit q, Lit r); - - // Variable mode: - // - void setPolarity (Var v, lbool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'. - void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic. - - // Read state: - // - lbool value (Var x) const; // The current value of a variable. - lbool value (Lit p) const; // The current value of a literal. - lbool modelValue (Var x) const; // The value of a variable in the last model. The last call to solve must have been satisfiable. - lbool modelValue (Lit p) const; // The value of a literal in the last model. The last call to solve must have been satisfiable. - int nAssigns () const; // The current number of assigned literals. - int nClauses () const; // The current number of original clauses. - int nLearnts () const; // The current number of learnt clauses. - int nVars () const; // The current number of variables. - int nFreeVars () const; - void printStats () const; // Print some current statistics to standard output. - - // Resource constraints: - // - void setConfBudget(int64_t x); - void setPropBudget(int64_t x); - void budgetOff(); - void interrupt(); // Trigger a (potentially asynchronous) interruption of the solver. - void clearInterrupt(); // Clear interrupt indicator flag. - - // Memory managment: - // - virtual void garbageCollect(); - void checkGarbage(double gf); - void checkGarbage(); - - // Extra results: (read-only member variable) - // - vec model; // If problem is satisfiable, this vector contains the model (if any). - LSet conflict; // If problem is unsatisfiable (possibly under assumptions), - // this vector represent the final conflict clause expressed in the assumptions. - - // Mode of operation: - // - int verbosity; - double var_decay; - double clause_decay; - double random_var_freq; - double random_seed; - bool luby_restart; - int ccmin_mode; // Controls conflict clause minimization (0=none, 1=basic, 2=deep). - int phase_saving; // Controls the level of phase saving (0=none, 1=limited, 2=full). - bool rnd_pol; // Use random polarities for branching heuristics. - bool rnd_init_act; // Initialize variable activities with a small random value. - double garbage_frac; // The fraction of wasted memory allowed before a garbage collection is triggered. - int min_learnts_lim; // Minimum number to set the learnts limit to. - - int restart_first; // The initial restart limit. (default 100) - double restart_inc; // The factor with which the restart limit is multiplied in each restart. (default 1.5) - double learntsize_factor; // The intitial limit for learnt clauses is a factor of the original clauses. (default 1 / 3) - double learntsize_inc; // The limit for learnt clauses is multiplied with this factor each restart. (default 1.1) - - int learntsize_adjust_start_confl; - double learntsize_adjust_inc; - - // Statistics: (read-only member variable) - // - uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts; - uint64_t dec_vars, num_clauses, num_learnts, clauses_literals, learnts_literals, max_literals, tot_literals; - -protected: - - // Helper structures: - // - struct VarData { CRef reason; int level; }; - static inline VarData mkVarData(CRef cr, int l){ VarData d = {cr, l}; return d; } - - struct Watcher { - CRef cref; - Lit blocker; - Watcher(CRef cr, Lit p) : cref(cr), blocker(p) {} - bool operator==(const Watcher& w) const { return cref == w.cref; } - bool operator!=(const Watcher& w) const { return cref != w.cref; } - }; - - struct WatcherDeleted - { - const ClauseAllocator& ca; - WatcherDeleted(const ClauseAllocator& _ca) : ca(_ca) {} - bool operator()(const Watcher& w) const { return ca[w.cref].mark() == 1; } - }; - - struct VarOrderLt { - const IntMap& activity; - bool operator () (Var x, Var y) const { return activity[x] > activity[y]; } - VarOrderLt(const IntMap& act) : activity(act) { } - }; - - struct ShrinkStackElem { - uint32_t i; - Lit l; - ShrinkStackElem(uint32_t _i, Lit _l) : i(_i), l(_l){} - }; - - // Solver state: - // - vec clauses; // List of problem clauses. - vec learnts; // List of learnt clauses. - vec trail; // Assignment stack; stores all assigments made in the order they were made. - vec trail_lim; // Separator indices for different decision levels in 'trail'. - vec assumptions; // Current set of assumptions provided to solve by the user. - - VMap activity; // A heuristic measurement of the activity of a variable. - VMap assigns; // The current assignments. - VMap polarity; // The preferred polarity of each variable. - VMap user_pol; // The users preferred polarity of each variable. - VMap decision; // Declares if a variable is eligible for selection in the decision heuristic. - VMap vardata; // Stores reason and level for each variable. - OccLists, WatcherDeleted, MkIndexLit> - watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true). - - Heaporder_heap; // A priority queue of variables ordered with respect to the variable activity. - - bool ok; // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used! - double cla_inc; // Amount to bump next clause with. - double var_inc; // Amount to bump next variable with. - int qhead; // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat). - int simpDB_assigns; // Number of top-level assignments since last execution of 'simplify()'. - int64_t simpDB_props; // Remaining number of propagations that must be made before next execution of 'simplify()'. - double progress_estimate;// Set by 'search()'. - bool remove_satisfied; // Indicates whether possibly inefficient linear scan for satisfied clauses should be performed in 'simplify'. - Var next_var; // Next variable to be created. - ClauseAllocator ca; - - vec released_vars; - vec free_vars; - - // Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is - // used, exept 'seen' wich is used in several places. - // - VMap seen; - vecanalyze_stack; - vec analyze_toclear; - vec add_tmp; - - double max_learnts; - double learntsize_adjust_confl; - int learntsize_adjust_cnt; - - // Resource constraints: - // - int64_t conflict_budget; // -1 means no budget. - int64_t propagation_budget; // -1 means no budget. - bool asynch_interrupt; - - // Main internal methods: - // - void insertVarOrder (Var x); // Insert a variable in the decision order priority queue. - Lit pickBranchLit (); // Return the next decision variable. - void newDecisionLevel (); // Begins a new decision level. - void uncheckedEnqueue (Lit p, CRef from = CRef_Undef); // Enqueue a literal. Assumes value of literal is undefined. - bool enqueue (Lit p, CRef from = CRef_Undef); // Test if fact 'p' contradicts current state, enqueue otherwise. - CRef propagate (); // Perform unit propagation. Returns possibly conflicting clause. - void cancelUntil (int level); // Backtrack until a certain level. - void analyze (CRef confl, vec& out_learnt, int& out_btlevel); // (bt = backtrack) - void analyzeFinal (Lit p, LSet& out_conflict); // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION? - bool litRedundant (Lit p); // (helper method for 'analyze()') - lbool search (int nof_conflicts); // Search for a given number of conflicts. - lbool solve_ (); // Main solve method (assumptions given in 'assumptions'). - void reduceDB (); // Reduce the set of learnt clauses. - void removeSatisfied (vec& cs); // Shrink 'cs' to contain only non-satisfied clauses. - void rebuildOrderHeap (); - - // Maintaining Variable/Clause activity: - // - void varDecayActivity (); // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead. - void varBumpActivity (Var v, double inc); // Increase a variable with the current 'bump' value. - void varBumpActivity (Var v); // Increase a variable with the current 'bump' value. - void claDecayActivity (); // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead. - void claBumpActivity (Clause& c); // Increase a clause with the current 'bump' value. - - // Operations on clauses: - // - void attachClause (CRef cr); // Attach a clause to watcher lists. - void detachClause (CRef cr, bool strict = false); // Detach a clause to watcher lists. - void removeClause (CRef cr); // Detach and free a clause. - bool isRemoved (CRef cr) const; // Test if a clause has been removed. - bool locked (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state. - bool satisfied (const Clause& c) const; // Returns TRUE if a clause is satisfied in the current state. - - // Misc: - // - int decisionLevel () const; // Gives the current decisionlevel. - uint32_t abstractLevel (Var x) const; // Used to represent an abstraction of sets of decision levels. - CRef reason (Var x) const; - int level (Var x) const; - double progressEstimate () const; // DELETE THIS ?? IT'S NOT VERY USEFUL ... - bool withinBudget () const; - void relocAll (ClauseAllocator& to); - - // Static helpers: - // - - // Returns a random float 0 <= x < 1. Seed must never be 0. - static inline double drand(double& seed) { - seed *= 1389796; - int q = (int)(seed / 2147483647); - seed -= (double)q * 2147483647; - return seed / 2147483647; } - - // Returns a random integer 0 <= x < size. Seed must never be 0. - static inline int irand(double& seed, int size) { - return (int)(drand(seed) * size); } -}; - - -//================================================================================================= -// Implementation of inline methods: - -inline CRef Solver::reason(Var x) const { return vardata[x].reason; } -inline int Solver::level (Var x) const { return vardata[x].level; } - -inline void Solver::insertVarOrder(Var x) { - if (!order_heap.inHeap(x) && decision[x]) order_heap.insert(x); } - -inline void Solver::varDecayActivity() { var_inc *= (1 / var_decay); } -inline void Solver::varBumpActivity(Var v) { varBumpActivity(v, var_inc); } -inline void Solver::varBumpActivity(Var v, double inc) { - if ( (activity[v] += inc) > 1e100 ) { - // Rescale: - for (int i = 0; i < nVars(); i++) - activity[i] *= 1e-100; - var_inc *= 1e-100; } - - // Update order_heap with respect to new activity: - if (order_heap.inHeap(v)) - order_heap.decrease(v); } - -inline void Solver::claDecayActivity() { cla_inc *= (1 / clause_decay); } -inline void Solver::claBumpActivity (Clause& c) { - if ( (c.activity() += cla_inc) > 1e20 ) { - // Rescale: - for (int i = 0; i < learnts.size(); i++) - ca[learnts[i]].activity() *= 1e-20; - cla_inc *= 1e-20; } } - -inline void Solver::checkGarbage(void){ return checkGarbage(garbage_frac); } -inline void Solver::checkGarbage(double gf){ - if (ca.wasted() > ca.size() * gf) - garbageCollect(); } - -// NOTE: enqueue does not set the ok flag! (only public methods do) -inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); } -inline bool Solver::addClause (const vec& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); } -inline bool Solver::addEmptyClause () { add_tmp.clear(); return addClause_(add_tmp); } -inline bool Solver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); } -inline bool Solver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); } -inline bool Solver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); } -inline bool Solver::addClause (Lit p, Lit q, Lit r, Lit s){ add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); add_tmp.push(s); return addClause_(add_tmp); } - -inline bool Solver::isRemoved (CRef cr) const { return ca[cr].mark() == 1; } -inline bool Solver::locked (const Clause& c) const { return value(c[0]) == l_True && reason(var(c[0])) != CRef_Undef && ca.lea(reason(var(c[0]))) == &c; } -inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); } - -inline int Solver::decisionLevel () const { return trail_lim.size(); } -inline uint32_t Solver::abstractLevel (Var x) const { return 1 << (level(x) & 31); } -inline lbool Solver::value (Var x) const { return assigns[x]; } -inline lbool Solver::value (Lit p) const { return assigns[var(p)] ^ sign(p); } -inline lbool Solver::modelValue (Var x) const { return model[x]; } -inline lbool Solver::modelValue (Lit p) const { return model[var(p)] ^ sign(p); } -inline int Solver::nAssigns () const { return trail.size(); } -inline int Solver::nClauses () const { return num_clauses; } -inline int Solver::nLearnts () const { return num_learnts; } -inline int Solver::nVars () const { return next_var; } -// TODO: nFreeVars() is not quite correct, try to calculate right instead of adapting it like below: -inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); } -inline void Solver::setPolarity (Var v, lbool b){ user_pol[v] = b; } -inline void Solver::setDecisionVar(Var v, bool b) -{ - if ( b && !decision[v]) dec_vars++; - else if (!b && decision[v]) dec_vars--; - - decision[v] = b; - insertVarOrder(v); -} -inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; } -inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; } -inline void Solver::interrupt(){ asynch_interrupt = true; } -inline void Solver::clearInterrupt(){ asynch_interrupt = false; } -inline void Solver::budgetOff(){ conflict_budget = propagation_budget = -1; } -inline bool Solver::withinBudget() const { - return !asynch_interrupt && - (conflict_budget < 0 || conflicts < (uint64_t)conflict_budget) && - (propagation_budget < 0 || propagations < (uint64_t)propagation_budget); } - -// FIXME: after the introduction of asynchronous interrruptions the solve-versions that return a -// pure bool do not give a safe interface. Either interrupts must be possible to turn off here, or -// all calls to solve must return an 'lbool'. I'm not yet sure which I prefer. -inline bool Solver::solve () { budgetOff(); assumptions.clear(); return solve_() == l_True; } -inline bool Solver::solve (Lit p) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_() == l_True; } -inline bool Solver::solve (Lit p, Lit q) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_() == l_True; } -inline bool Solver::solve (Lit p, Lit q, Lit r) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_() == l_True; } -inline bool Solver::solve (const vec& assumps){ budgetOff(); assumps.copyTo(assumptions); return solve_() == l_True; } -inline lbool Solver::solveLimited (const vec& assumps){ assumps.copyTo(assumptions); return solve_(); } -inline bool Solver::okay () const { return ok; } - -inline ClauseIterator Solver::clausesBegin() const { return ClauseIterator(ca, &clauses[0]); } -inline ClauseIterator Solver::clausesEnd () const { return ClauseIterator(ca, &clauses[clauses.size()]); } -inline TrailIterator Solver::trailBegin () const { return TrailIterator(&trail[0]); } -inline TrailIterator Solver::trailEnd () const { - return TrailIterator(&trail[decisionLevel() == 0 ? trail.size() : trail_lim[0]]); } - -inline void Solver::toDimacs (const char* file){ vec as; toDimacs(file, as); } -inline void Solver::toDimacs (const char* file, Lit p){ vec as; as.push(p); toDimacs(file, as); } -inline void Solver::toDimacs (const char* file, Lit p, Lit q){ vec as; as.push(p); as.push(q); toDimacs(file, as); } -inline void Solver::toDimacs (const char* file, Lit p, Lit q, Lit r){ vec as; as.push(p); as.push(q); as.push(r); toDimacs(file, as); } - - -//================================================================================================= -// Debug etc: - - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/SolverTypes.h b/yosys/libs/minisat/SolverTypes.h deleted file mode 100644 index a7df57858..000000000 --- a/yosys/libs/minisat/SolverTypes.h +++ /dev/null @@ -1,478 +0,0 @@ -/***********************************************************************************[SolverTypes.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - - -#ifndef Minisat_SolverTypes_h -#define Minisat_SolverTypes_h - -#include - -#include "IntTypes.h" -#include "Alg.h" -#include "Vec.h" -#include "IntMap.h" -#include "Map.h" -#include "Alloc.h" - -namespace Minisat { - -//================================================================================================= -// Variables, literals, lifted booleans, clauses: - - -// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N, -// so that they can be used as array indices. - -typedef int Var; -#if defined(MINISAT_CONSTANTS_AS_MACROS) -#define var_Undef (-1) -#else - const Var var_Undef = -1; -#endif - - -struct Lit { - int x; - - // Use this as a constructor: - friend Lit mkLit(Var var, bool sign); - - bool operator == (Lit p) const { return x == p.x; } - bool operator != (Lit p) const { return x != p.x; } - bool operator < (Lit p) const { return x < p.x; } // '<' makes p, ~p adjacent in the ordering. -}; - - -inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; } -inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; } -inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; } -inline bool sign (Lit p) { return p.x & 1; } -inline int var (Lit p) { return p.x >> 1; } - -// Mapping Literals to and from compact integers suitable for array indexing: -inline int toInt (Var v) { return v; } -inline int toInt (Lit p) { return p.x; } -inline Lit toLit (int i) { Lit p; p.x = i; return p; } - -//const Lit lit_Undef = mkLit(var_Undef, false); // }- Useful special constants. -//const Lit lit_Error = mkLit(var_Undef, true ); // } - -const Lit lit_Undef = { -2 }; // }- Useful special constants. -const Lit lit_Error = { -1 }; // } - -struct MkIndexLit { vec::Size operator()(Lit l) const { return vec::Size(l.x); } }; - -template class VMap : public IntMap{}; -template class LMap : public IntMap{}; -class LSet : public IntSet{}; - -//================================================================================================= -// Lifted booleans: -// -// NOTE: this implementation is optimized for the case when comparisons between values are mostly -// between one variable and one constant. Some care had to be taken to make sure that gcc -// does enough constant propagation to produce sensible code, and this appears to be somewhat -// fragile unfortunately. - -class lbool { - uint8_t value; - -public: - explicit lbool(uint8_t v) : value(v) { } - - lbool() : value(0) { } - explicit lbool(bool x) : value(!x) { } - - bool operator == (lbool b) const { return ((b.value&2) & (value&2)) | (!(b.value&2)&(value == b.value)); } - bool operator != (lbool b) const { return !(*this == b); } - lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); } - - lbool operator && (lbool b) const { - uint8_t sel = (this->value << 1) | (b.value << 3); - uint8_t v = (0xF7F755F4 >> sel) & 3; - return lbool(v); } - - lbool operator || (lbool b) const { - uint8_t sel = (this->value << 1) | (b.value << 3); - uint8_t v = (0xFCFCF400 >> sel) & 3; - return lbool(v); } - - friend int toInt (lbool l); - friend lbool toLbool(int v); -}; -inline int toInt (lbool l) { return l.value; } -inline lbool toLbool(int v) { return lbool((uint8_t)v); } - -#if defined(MINISAT_CONSTANTS_AS_MACROS) - #define l_True (lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants. - #define l_False (lbool((uint8_t)1)) - #define l_Undef (lbool((uint8_t)2)) -#else - const lbool l_True ((uint8_t)0); - const lbool l_False((uint8_t)1); - const lbool l_Undef((uint8_t)2); -#endif - - -//================================================================================================= -// Clause -- a simple class for representing a clause: - -class Clause; -typedef RegionAllocator::Ref CRef; - -class Clause { - struct { - unsigned mark : 2; - unsigned learnt : 1; - unsigned has_extra : 1; - unsigned reloced : 1; - unsigned size : 27; } header; - union { Lit lit; float act; uint32_t abs; CRef rel; } data[0]; - - friend class ClauseAllocator; - - // NOTE: This constructor cannot be used directly (doesn't allocate enough memory). - Clause(const vec& ps, bool use_extra, bool learnt) { - header.mark = 0; - header.learnt = learnt; - header.has_extra = use_extra; - header.reloced = 0; - header.size = ps.size(); - - for (int i = 0; i < ps.size(); i++) - data[i].lit = ps[i]; - - if (header.has_extra){ - if (header.learnt) - data[header.size].act = 0; - else - calcAbstraction(); - } - } - - // NOTE: This constructor cannot be used directly (doesn't allocate enough memory). - Clause(const Clause& from, bool use_extra){ - header = from.header; - header.has_extra = use_extra; // NOTE: the copied clause may lose the extra field. - - for (int i = 0; i < from.size(); i++) - data[i].lit = from[i]; - - if (header.has_extra){ - if (header.learnt) - data[header.size].act = from.data[header.size].act; - else - data[header.size].abs = from.data[header.size].abs; - } - } - -public: - void calcAbstraction() { - assert(header.has_extra); - uint32_t abstraction = 0; - for (int i = 0; i < size(); i++) - abstraction |= 1 << (var(data[i].lit) & 31); - data[header.size].abs = abstraction; } - - - int size () const { return header.size; } - void shrink (int i) { assert(i <= size()); if (header.has_extra) data[header.size-i] = data[header.size]; header.size -= i; } - void pop () { shrink(1); } - bool learnt () const { return header.learnt; } - bool has_extra () const { return header.has_extra; } - uint32_t mark () const { return header.mark; } - void mark (uint32_t m) { header.mark = m; } - const Lit& last () const { return data[header.size-1].lit; } - - bool reloced () const { return header.reloced; } - CRef relocation () const { return data[0].rel; } - void relocate (CRef c) { header.reloced = 1; data[0].rel = c; } - - // NOTE: somewhat unsafe to change the clause in-place! Must manually call 'calcAbstraction' afterwards for - // subsumption operations to behave correctly. - Lit& operator [] (int i) { return data[i].lit; } - Lit operator [] (int i) const { return data[i].lit; } - operator const Lit* (void) const { return (Lit*)data; } - - float& activity () { assert(header.has_extra); return data[header.size].act; } - uint32_t abstraction () const { assert(header.has_extra); return data[header.size].abs; } - - Lit subsumes (const Clause& other) const; - void strengthen (Lit p); -}; - - -//================================================================================================= -// ClauseAllocator -- a simple class for allocating memory for clauses: - -const CRef CRef_Undef = RegionAllocator::Ref_Undef; -class ClauseAllocator -{ - RegionAllocator ra; - - static uint32_t clauseWord32Size(int size, bool has_extra){ - return (sizeof(Clause) + (sizeof(Lit) * (size + (int)has_extra))) / sizeof(uint32_t); } - - public: - enum { Unit_Size = RegionAllocator::Unit_Size }; - - bool extra_clause_field; - - ClauseAllocator(uint32_t start_cap) : ra(start_cap), extra_clause_field(false){} - ClauseAllocator() : extra_clause_field(false){} - - void moveTo(ClauseAllocator& to){ - to.extra_clause_field = extra_clause_field; - ra.moveTo(to.ra); } - - CRef alloc(const vec& ps, bool learnt = false) - { - assert(sizeof(Lit) == sizeof(uint32_t)); - assert(sizeof(float) == sizeof(uint32_t)); - bool use_extra = learnt | extra_clause_field; - CRef cid = ra.alloc(clauseWord32Size(ps.size(), use_extra)); - new (lea(cid)) Clause(ps, use_extra, learnt); - - return cid; - } - - CRef alloc(const Clause& from) - { - bool use_extra = from.learnt() | extra_clause_field; - CRef cid = ra.alloc(clauseWord32Size(from.size(), use_extra)); - new (lea(cid)) Clause(from, use_extra); - return cid; } - - uint32_t size () const { return ra.size(); } - uint32_t wasted () const { return ra.wasted(); } - - // Deref, Load Effective Address (LEA), Inverse of LEA (AEL): - Clause& operator[](CRef r) { return (Clause&)ra[r]; } - const Clause& operator[](CRef r) const { return (Clause&)ra[r]; } - Clause* lea (CRef r) { return (Clause*)ra.lea(r); } - const Clause* lea (CRef r) const { return (Clause*)ra.lea(r);; } - CRef ael (const Clause* t){ return ra.ael((uint32_t*)t); } - - void free(CRef cid) - { - Clause& c = operator[](cid); - ra.free(clauseWord32Size(c.size(), c.has_extra())); - } - - void reloc(CRef& cr, ClauseAllocator& to) - { - Clause& c = operator[](cr); - - if (c.reloced()) { cr = c.relocation(); return; } - - cr = to.alloc(c); - c.relocate(cr); - } -}; - -//================================================================================================= -// Simple iterator classes (for iterating over clauses and top-level assignments): - -class ClauseIterator { - const ClauseAllocator& ca; - const CRef* crefs; -public: - ClauseIterator(const ClauseAllocator& _ca, const CRef* _crefs) : ca(_ca), crefs(_crefs){} - - void operator++(){ crefs++; } - const Clause& operator*() const { return ca[*crefs]; } - - // NOTE: does not compare that references use the same clause-allocator: - bool operator==(const ClauseIterator& ci) const { return crefs == ci.crefs; } - bool operator!=(const ClauseIterator& ci) const { return crefs != ci.crefs; } -}; - - -class TrailIterator { - const Lit* lits; -public: - TrailIterator(const Lit* _lits) : lits(_lits){} - - void operator++() { lits++; } - Lit operator*() const { return *lits; } - - bool operator==(const TrailIterator& ti) const { return lits == ti.lits; } - bool operator!=(const TrailIterator& ti) const { return lits != ti.lits; } -}; - - -//================================================================================================= -// OccLists -- a class for maintaining occurence lists with lazy deletion: - -template > -class OccLists -{ - IntMap occs; - IntMap dirty; - vec dirties; - Deleted deleted; - - public: - OccLists(const Deleted& d, MkIndex _index = MkIndex()) : - occs(_index), - dirty(_index), - deleted(d){} - - void init (const K& idx){ occs.reserve(idx); occs[idx].clear(); dirty.reserve(idx, 0); } - Vec& operator[](const K& idx){ return occs[idx]; } - Vec& lookup (const K& idx){ if (dirty[idx]) clean(idx); return occs[idx]; } - - void cleanAll (); - void clean (const K& idx); - void smudge (const K& idx){ - if (dirty[idx] == 0){ - dirty[idx] = 1; - dirties.push(idx); - } - } - - void clear(bool free = true){ - occs .clear(free); - dirty .clear(free); - dirties.clear(free); - } -}; - - -template -void OccLists::cleanAll() -{ - for (int i = 0; i < dirties.size(); i++) - // Dirties may contain duplicates so check here if a variable is already cleaned: - if (dirty[dirties[i]]) - clean(dirties[i]); - dirties.clear(); -} - - -template -void OccLists::clean(const K& idx) -{ - Vec& vec = occs[idx]; - int i, j; - for (i = j = 0; i < vec.size(); i++) - if (!deleted(vec[i])) - vec[j++] = vec[i]; - vec.shrink(i - j); - dirty[idx] = 0; -} - - -//================================================================================================= -// CMap -- a class for mapping clauses to values: - - -template -class CMap -{ - struct CRefHash { - uint32_t operator()(CRef cr) const { return (uint32_t)cr; } }; - - typedef Map HashTable; - HashTable map; - - public: - // Size-operations: - void clear () { map.clear(); } - int size () const { return map.elems(); } - - - // Insert/Remove/Test mapping: - void insert (CRef cr, const T& t){ map.insert(cr, t); } - void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility - void remove (CRef cr) { map.remove(cr); } - bool has (CRef cr, T& t) { return map.peek(cr, t); } - - // Vector interface (the clause 'c' must already exist): - const T& operator [] (CRef cr) const { return map[cr]; } - T& operator [] (CRef cr) { return map[cr]; } - - // Iteration (not transparent at all at the moment): - int bucket_count() const { return map.bucket_count(); } - const vec& bucket(int i) const { return map.bucket(i); } - - // Move contents to other map: - void moveTo(CMap& other){ map.moveTo(other.map); } - - // TMP debug: - void debug(){ - printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); } -}; - - -/*_________________________________________________________________________________________________ -| -| subsumes : (other : const Clause&) -> Lit -| -| Description: -| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other' -| by subsumption resolution. -| -| Result: -| lit_Error - No subsumption or simplification -| lit_Undef - Clause subsumes 'other' -| p - The literal p can be deleted from 'other' -|________________________________________________________________________________________________@*/ -inline Lit Clause::subsumes(const Clause& other) const -{ - //if (other.size() < size() || (extra.abst & ~other.extra.abst) != 0) - //if (other.size() < size() || (!learnt() && !other.learnt() && (extra.abst & ~other.extra.abst) != 0)) - assert(!header.learnt); assert(!other.header.learnt); - assert(header.has_extra); assert(other.header.has_extra); - if (other.header.size < header.size || (data[header.size].abs & ~other.data[other.header.size].abs) != 0) - return lit_Error; - - Lit ret = lit_Undef; - const Lit* c = (const Lit*)(*this); - const Lit* d = (const Lit*)other; - - for (unsigned i = 0; i < header.size; i++) { - // search for c[i] or ~c[i] - for (unsigned j = 0; j < other.header.size; j++) - if (c[i] == d[j]) - goto ok; - else if (ret == lit_Undef && c[i] == ~d[j]){ - ret = c[i]; - goto ok; - } - - // did not find it - return lit_Error; - ok:; - } - - return ret; -} - -inline void Clause::strengthen(Lit p) -{ - remove(*this, p); - calcAbstraction(); -} - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/Sort.h b/yosys/libs/minisat/Sort.h deleted file mode 100644 index cc96486d8..000000000 --- a/yosys/libs/minisat/Sort.h +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************************[Sort.h] -Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Sort_h -#define Minisat_Sort_h - -#include "Vec.h" - -//================================================================================================= -// Some sorting algorithms for vec's - - -namespace Minisat { - -template -struct LessThan_default { - bool operator () (T x, T y) { return x < y; } -}; - - -template -void selectionSort(T* array, int size, LessThan lt) -{ - int i, j, best_i; - T tmp; - - for (i = 0; i < size-1; i++){ - best_i = i; - for (j = i+1; j < size; j++){ - if (lt(array[j], array[best_i])) - best_i = j; - } - tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp; - } -} -template static inline void selectionSort(T* array, int size) { - selectionSort(array, size, LessThan_default()); } - -template -void sort(T* array, int size, LessThan lt) -{ - if (size <= 15) - selectionSort(array, size, lt); - - else{ - T pivot = array[size / 2]; - T tmp; - int i = -1; - int j = size; - - for(;;){ - do i++; while(lt(array[i], pivot)); - do j--; while(lt(pivot, array[j])); - - if (i >= j) break; - - tmp = array[i]; array[i] = array[j]; array[j] = tmp; - } - - sort(array , i , lt); - sort(&array[i], size-i, lt); - } -} -template static inline void sort(T* array, int size) { - sort(array, size, LessThan_default()); } - - -//================================================================================================= -// For 'vec's: - - -template void sort(vec& v, LessThan lt) { - sort((T*)v, v.size(), lt); } -template void sort(vec& v) { - sort(v, LessThan_default()); } - - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/System.cc b/yosys/libs/minisat/System.cc deleted file mode 100644 index 1921a1d71..000000000 --- a/yosys/libs/minisat/System.cc +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif -/***************************************************************************************[System.cc] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include -#include - -#include "System.h" - -#if defined(__linux__) - -#include - -using namespace Minisat; - -static inline int memReadStat(int field) -{ - char name[256]; - pid_t pid = getpid(); - int value; - - sprintf(name, "/proc/%d/statm", pid); - FILE* in = fopen(name, "rb"); - if (in == NULL) return 0; - - for (; field >= 0; field--) - if (fscanf(in, "%d", &value) != 1) - printf("ERROR! Failed to parse memory statistics from \"/proc\".\n"), exit(1); - fclose(in); - return value; -} - - -static inline int memReadPeak(void) -{ - char name[256]; - pid_t pid = getpid(); - - sprintf(name, "/proc/%d/status", pid); - FILE* in = fopen(name, "rb"); - if (in == NULL) return 0; - - // Find the correct line, beginning with "VmPeak:": - int peak_kb = 0; - while (!feof(in) && fscanf(in, "VmPeak: %d kB", &peak_kb) != 1) - while (!feof(in) && fgetc(in) != '\n') - ; - fclose(in); - - return peak_kb; -} - -double Minisat::memUsed() { return (double)memReadStat(0) * (double)getpagesize() / (1024*1024); } -double Minisat::memUsedPeak(bool strictlyPeak) { - double peak = memReadPeak() / (double)1024; - return peak == 0 && !strictlyPeak ? memUsed() : peak; } - -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__gnu_hurd__) - -double Minisat::memUsed() { - struct rusage ru; - getrusage(RUSAGE_SELF, &ru); - return (double)ru.ru_maxrss / 1024; } -double Minisat::memUsedPeak(bool) { return memUsed(); } - - -#elif defined(__APPLE__) -#include - -double Minisat::memUsed() { - malloc_statistics_t t; - malloc_zone_statistics(NULL, &t); - return (double)t.max_size_in_use / (1024*1024); } -double Minisat::memUsedPeak(bool) { return memUsed(); } - -#else -double Minisat::memUsed() { return 0; } -double Minisat::memUsedPeak(bool) { return 0; } -#endif - - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -void Minisat::limitMemory(uint64_t max_mem_mb) -{ -// FIXME: OpenBSD does not support RLIMIT_AS. Not sure how well RLIMIT_DATA works instead. -#if defined(__OpenBSD__) -#define RLIMIT_AS RLIMIT_DATA -#endif - - // Set limit on virtual memory: - if (max_mem_mb != 0){ - rlim_t new_mem_lim = (rlim_t)max_mem_mb * 1024*1024; - rlimit rl; - getrlimit(RLIMIT_AS, &rl); - if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){ - rl.rlim_cur = new_mem_lim; - if (setrlimit(RLIMIT_AS, &rl) == -1) - printf("WARNING! Could not set resource limit: Virtual memory.\n"); - } - } - -#if defined(__OpenBSD__) -#undef RLIMIT_AS -#endif -} -#else -void Minisat::limitMemory(uint64_t /*max_mem_mb*/) -{ - printf("WARNING! Memory limit not supported on this architecture.\n"); -} -#endif - - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -void Minisat::limitTime(uint32_t max_cpu_time) -{ - if (max_cpu_time != 0){ - rlimit rl; - getrlimit(RLIMIT_CPU, &rl); - if (rl.rlim_max == RLIM_INFINITY || (rlim_t)max_cpu_time < rl.rlim_max){ - rl.rlim_cur = max_cpu_time; - if (setrlimit(RLIMIT_CPU, &rl) == -1) - printf("WARNING! Could not set resource limit: CPU-time.\n"); - } - } -} -#else -void Minisat::limitTime(uint32_t /*max_cpu_time*/) -{ - printf("WARNING! CPU-time limit not supported on this architecture.\n"); -} -#endif - - -void Minisat::sigTerm(void handler(int)) -{ - signal(SIGINT, handler); - signal(SIGTERM,handler); -#ifdef SIGXCPU - signal(SIGXCPU,handler); -#endif -} diff --git a/yosys/libs/minisat/System.h b/yosys/libs/minisat/System.h deleted file mode 100644 index cd9d020c7..000000000 --- a/yosys/libs/minisat/System.h +++ /dev/null @@ -1,65 +0,0 @@ -/****************************************************************************************[System.h] -Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_System_h -#define Minisat_System_h - -#include "IntTypes.h" - -//------------------------------------------------------------------------------------------------- - -namespace Minisat { - -static inline double cpuTime(void); // CPU-time in seconds. - -extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures). -extern double memUsedPeak(bool strictlyPeak = false); // Peak-memory in mega bytes (returns 0 for unsupported architectures). - -extern void limitMemory(uint64_t max_mem_mb); // Set a limit on total memory usage. The exact - // semantics varies depending on architecture. - -extern void limitTime(uint32_t max_cpu_time); // Set a limit on maximum CPU time. The exact - // semantics varies depending on architecture. - -extern void sigTerm(void handler(int)); // Set up handling of available termination signals. - -} - -//------------------------------------------------------------------------------------------------- -// Implementation of inline functions: - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include - -static inline double Minisat::cpuTime(void) { return (double)clock() / CLOCKS_PER_SEC; } - -#else -#include -#include -#include - -static inline double Minisat::cpuTime(void) { - struct rusage ru; - getrusage(RUSAGE_SELF, &ru); - return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; } - -#endif - -#endif diff --git a/yosys/libs/minisat/Vec.h b/yosys/libs/minisat/Vec.h deleted file mode 100644 index 6e398801f..000000000 --- a/yosys/libs/minisat/Vec.h +++ /dev/null @@ -1,134 +0,0 @@ -/*******************************************************************************************[Vec.h] -Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#ifndef Minisat_Vec_h -#define Minisat_Vec_h - -#include -#include -#include - -#include "IntTypes.h" -#include "XAlloc.h" - -namespace Minisat { - -//================================================================================================= -// Automatically resizable arrays -// -// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc) - -template -class vec { -public: - typedef _Size Size; -private: - T* data; - Size sz; - Size cap; - - // Don't allow copying (error prone): - vec& operator=(vec& other); - vec (vec& other); - - static inline Size max(Size x, Size y){ return (x > y) ? x : y; } - -public: - // Constructors: - vec() : data(NULL), sz(0), cap(0) { } - explicit vec(Size size) : data(NULL), sz(0), cap(0) { growTo(size); } - vec(Size size, const T& pad) : data(NULL), sz(0), cap(0) { growTo(size, pad); } - ~vec() { clear(true); } - - // Pointer to first element: - operator T* (void) { return data; } - - // Size operations: - Size size (void) const { return sz; } - void shrink (Size nelems) { assert(nelems <= sz); for (Size i = 0; i < nelems; i++) sz--, data[sz].~T(); } - void shrink_ (Size nelems) { assert(nelems <= sz); sz -= nelems; } - int capacity (void) const { return cap; } - void capacity (Size min_cap); - void growTo (Size size); - void growTo (Size size, const T& pad); - void clear (bool dealloc = false); - - // Stack interface: - void push (void) { if (sz == cap) capacity(sz+1); new (&data[sz]) T(); sz++; } - //void push (const T& elem) { if (sz == cap) capacity(sz+1); data[sz++] = elem; } - void push (const T& elem) { if (sz == cap) capacity(sz+1); new (&data[sz++]) T(elem); } - void push_ (const T& elem) { assert(sz < cap); data[sz++] = elem; } - void pop (void) { assert(sz > 0); sz--, data[sz].~T(); } - // NOTE: it seems possible that overflow can happen in the 'sz+1' expression of 'push()', but - // in fact it can not since it requires that 'cap' is equal to INT_MAX. This in turn can not - // happen given the way capacities are calculated (below). Essentially, all capacities are - // even, but INT_MAX is odd. - - const T& last (void) const { return data[sz-1]; } - T& last (void) { return data[sz-1]; } - - // Vector interface: - const T& operator [] (Size index) const { return data[index]; } - T& operator [] (Size index) { return data[index]; } - - // Duplicatation (preferred instead): - void copyTo(vec& copy) const { copy.clear(); copy.growTo(sz); for (Size i = 0; i < sz; i++) copy[i] = data[i]; } - void moveTo(vec& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; } -}; - - -template -void vec::capacity(Size min_cap) { - if (cap >= min_cap) return; - Size add = max((min_cap - cap + 1) & ~1, ((cap >> 1) + 2) & ~1); // NOTE: grow by approximately 3/2 - const Size size_max = std::numeric_limits::max(); - if ( ((size_max <= std::numeric_limits::max()) && (add > size_max - cap)) - || (((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM) ) - throw OutOfMemoryException(); - } - - -template -void vec::growTo(Size size, const T& pad) { - if (sz >= size) return; - capacity(size); - for (Size i = sz; i < size; i++) data[i] = pad; - sz = size; } - - -template -void vec::growTo(Size size) { - if (sz >= size) return; - capacity(size); - for (Size i = sz; i < size; i++) new (&data[i]) T(); - sz = size; } - - -template -void vec::clear(bool dealloc) { - if (data != NULL){ - for (Size i = 0; i < sz; i++) data[i].~T(); - sz = 0; - if (dealloc) free(data), data = NULL, cap = 0; } } - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/minisat/XAlloc.h b/yosys/libs/minisat/XAlloc.h deleted file mode 100644 index 1da176028..000000000 --- a/yosys/libs/minisat/XAlloc.h +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************************[XAlloc.h] -Copyright (c) 2009-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - - -#ifndef Minisat_XAlloc_h -#define Minisat_XAlloc_h - -#include -#include - -namespace Minisat { - -//================================================================================================= -// Simple layer on top of malloc/realloc to catch out-of-memory situtaions and provide some typing: - -class OutOfMemoryException{}; -static inline void* xrealloc(void *ptr, size_t size) -{ - void* mem = realloc(ptr, size); - if (mem == NULL && errno == ENOMEM){ - throw OutOfMemoryException(); - }else - return mem; -} - -//================================================================================================= -} - -#endif diff --git a/yosys/libs/sha1/sha1.cpp b/yosys/libs/sha1/sha1.cpp deleted file mode 100644 index 51bbd85c8..000000000 --- a/yosys/libs/sha1/sha1.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* - sha1.cpp - source code of - - ============ - SHA-1 in C++ - ============ - - 100% Public Domain. - - Original C Code - -- Steve Reid - Small changes to fit into bglibs - -- Bruce Guenter - Translation to simpler C++ Code - -- Volker Grabsch - Fixing bugs and improving style - -- Eugene Hopkinson -*/ - -#include "sha1.h" -#include -#include -#include - -/* Help macros */ -#define SHA1_ROL(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits)))) -#define SHA1_BLK(i) (block[i&15] = SHA1_ROL(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define SHA1_R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + block[i] + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); -#define SHA1_R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + SHA1_BLK(i) + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); -#define SHA1_R2(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0x6ed9eba1 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); -#define SHA1_R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + SHA1_BLK(i) + 0x8f1bbcdc + SHA1_ROL(v,5); w=SHA1_ROL(w,30); -#define SHA1_R4(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0xca62c1d6 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); - -SHA1::SHA1() -{ - reset(); -} - - -void SHA1::update(const std::string &s) -{ - std::istringstream is(s); - update(is); -} - - -void SHA1::update(std::istream &is) -{ - std::string rest_of_buffer; - read(is, rest_of_buffer, BLOCK_BYTES - buffer.size()); - buffer += rest_of_buffer; - - while (is) - { - uint32_t block[BLOCK_INTS]; - buffer_to_block(buffer, block); - transform(block); - read(is, buffer, BLOCK_BYTES); - } -} - - -/* - * Add padding and return the message digest. - */ - -std::string SHA1::final() -{ - /* Total number of hashed bits */ - uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8; - - /* Padding */ - buffer += 0x80; - unsigned int orig_size = buffer.size(); - while (buffer.size() < BLOCK_BYTES) - { - buffer += (char)0x00; - } - - uint32_t block[BLOCK_INTS]; - buffer_to_block(buffer, block); - - if (orig_size > BLOCK_BYTES - 8) - { - transform(block); - for (unsigned int i = 0; i < BLOCK_INTS - 2; i++) - { - block[i] = 0; - } - } - - /* Append total_bits, split this uint64_t into two uint32_t */ - block[BLOCK_INTS - 1] = total_bits; - block[BLOCK_INTS - 2] = (total_bits >> 32); - transform(block); - - /* Hex std::string */ - std::ostringstream result; - for (unsigned int i = 0; i < DIGEST_INTS; i++) - { - result << std::hex << std::setfill('0') << std::setw(8); - result << (digest[i] & 0xffffffff); - } - - /* Reset for next run */ - reset(); - - return result.str(); -} - - -std::string SHA1::from_file(const std::string &filename) -{ - std::ifstream stream(filename.c_str(), std::ios::binary); - SHA1 checksum; - checksum.update(stream); - return checksum.final(); -} - - -void SHA1::reset() -{ - /* SHA1 initialization constants */ - digest[0] = 0x67452301; - digest[1] = 0xefcdab89; - digest[2] = 0x98badcfe; - digest[3] = 0x10325476; - digest[4] = 0xc3d2e1f0; - - /* Reset counters */ - transforms = 0; - buffer = ""; -} - - -/* - * Hash a single 512-bit block. This is the core of the algorithm. - */ - -void SHA1::transform(uint32_t block[BLOCK_BYTES]) -{ - /* Copy digest[] to working vars */ - uint32_t a = digest[0]; - uint32_t b = digest[1]; - uint32_t c = digest[2]; - uint32_t d = digest[3]; - uint32_t e = digest[4]; - - - /* 4 rounds of 20 operations each. Loop unrolled. */ - SHA1_R0(a,b,c,d,e, 0); - SHA1_R0(e,a,b,c,d, 1); - SHA1_R0(d,e,a,b,c, 2); - SHA1_R0(c,d,e,a,b, 3); - SHA1_R0(b,c,d,e,a, 4); - SHA1_R0(a,b,c,d,e, 5); - SHA1_R0(e,a,b,c,d, 6); - SHA1_R0(d,e,a,b,c, 7); - SHA1_R0(c,d,e,a,b, 8); - SHA1_R0(b,c,d,e,a, 9); - SHA1_R0(a,b,c,d,e,10); - SHA1_R0(e,a,b,c,d,11); - SHA1_R0(d,e,a,b,c,12); - SHA1_R0(c,d,e,a,b,13); - SHA1_R0(b,c,d,e,a,14); - SHA1_R0(a,b,c,d,e,15); - SHA1_R1(e,a,b,c,d,16); - SHA1_R1(d,e,a,b,c,17); - SHA1_R1(c,d,e,a,b,18); - SHA1_R1(b,c,d,e,a,19); - SHA1_R2(a,b,c,d,e,20); - SHA1_R2(e,a,b,c,d,21); - SHA1_R2(d,e,a,b,c,22); - SHA1_R2(c,d,e,a,b,23); - SHA1_R2(b,c,d,e,a,24); - SHA1_R2(a,b,c,d,e,25); - SHA1_R2(e,a,b,c,d,26); - SHA1_R2(d,e,a,b,c,27); - SHA1_R2(c,d,e,a,b,28); - SHA1_R2(b,c,d,e,a,29); - SHA1_R2(a,b,c,d,e,30); - SHA1_R2(e,a,b,c,d,31); - SHA1_R2(d,e,a,b,c,32); - SHA1_R2(c,d,e,a,b,33); - SHA1_R2(b,c,d,e,a,34); - SHA1_R2(a,b,c,d,e,35); - SHA1_R2(e,a,b,c,d,36); - SHA1_R2(d,e,a,b,c,37); - SHA1_R2(c,d,e,a,b,38); - SHA1_R2(b,c,d,e,a,39); - SHA1_R3(a,b,c,d,e,40); - SHA1_R3(e,a,b,c,d,41); - SHA1_R3(d,e,a,b,c,42); - SHA1_R3(c,d,e,a,b,43); - SHA1_R3(b,c,d,e,a,44); - SHA1_R3(a,b,c,d,e,45); - SHA1_R3(e,a,b,c,d,46); - SHA1_R3(d,e,a,b,c,47); - SHA1_R3(c,d,e,a,b,48); - SHA1_R3(b,c,d,e,a,49); - SHA1_R3(a,b,c,d,e,50); - SHA1_R3(e,a,b,c,d,51); - SHA1_R3(d,e,a,b,c,52); - SHA1_R3(c,d,e,a,b,53); - SHA1_R3(b,c,d,e,a,54); - SHA1_R3(a,b,c,d,e,55); - SHA1_R3(e,a,b,c,d,56); - SHA1_R3(d,e,a,b,c,57); - SHA1_R3(c,d,e,a,b,58); - SHA1_R3(b,c,d,e,a,59); - SHA1_R4(a,b,c,d,e,60); - SHA1_R4(e,a,b,c,d,61); - SHA1_R4(d,e,a,b,c,62); - SHA1_R4(c,d,e,a,b,63); - SHA1_R4(b,c,d,e,a,64); - SHA1_R4(a,b,c,d,e,65); - SHA1_R4(e,a,b,c,d,66); - SHA1_R4(d,e,a,b,c,67); - SHA1_R4(c,d,e,a,b,68); - SHA1_R4(b,c,d,e,a,69); - SHA1_R4(a,b,c,d,e,70); - SHA1_R4(e,a,b,c,d,71); - SHA1_R4(d,e,a,b,c,72); - SHA1_R4(c,d,e,a,b,73); - SHA1_R4(b,c,d,e,a,74); - SHA1_R4(a,b,c,d,e,75); - SHA1_R4(e,a,b,c,d,76); - SHA1_R4(d,e,a,b,c,77); - SHA1_R4(c,d,e,a,b,78); - SHA1_R4(b,c,d,e,a,79); - - /* Add the working vars back into digest[] */ - digest[0] += a; - digest[1] += b; - digest[2] += c; - digest[3] += d; - digest[4] += e; - - /* Count the number of transformations */ - transforms++; -} - - -void SHA1::buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]) -{ - /* Convert the std::string (byte buffer) to a uint32_t array (MSB) */ - for (unsigned int i = 0; i < BLOCK_INTS; i++) - { - block[i] = (buffer[4*i+3] & 0xff) - | (buffer[4*i+2] & 0xff)<<8 - | (buffer[4*i+1] & 0xff)<<16 - | (buffer[4*i+0] & 0xff)<<24; - } -} - - -void SHA1::read(std::istream &is, std::string &s, size_t max) -{ - char* sbuf = new char[max]; - - is.read(sbuf, max); - s.assign(sbuf, is.gcount()); - - delete[] sbuf; -} - - -std::string sha1(const std::string &string) -{ - SHA1 checksum; - checksum.update(string); - return checksum.final(); -} diff --git a/yosys/libs/sha1/sha1.h b/yosys/libs/sha1/sha1.h deleted file mode 100644 index 9f526376e..000000000 --- a/yosys/libs/sha1/sha1.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - sha1.h - header of - - ============ - SHA-1 in C++ - ============ - - 100% Public Domain. - - Original C Code - -- Steve Reid - Small changes to fit into bglibs - -- Bruce Guenter - Translation to simpler C++ Code - -- Volker Grabsch - Fixing bugs and improving style - -- Eugene Hopkinson -*/ - -#ifndef SHA1_HPP -#define SHA1_HPP - - -#include -#include -#include - -class SHA1 -{ -public: - SHA1(); - void update(const std::string &s); - void update(std::istream &is); - std::string final(); - static std::string from_file(const std::string &filename); - -private: - static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */ - static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */ - static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4; - - uint32_t digest[DIGEST_INTS]; - std::string buffer; - uint64_t transforms; - - void reset(); - void transform(uint32_t block[BLOCK_BYTES]); - - static void read(std::istream &is, std::string &s, size_t max); - static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]); -}; - -std::string sha1(const std::string &string); - - - -#endif /* SHA1_HPP */ diff --git a/yosys/libs/subcircuit/.gitignore b/yosys/libs/subcircuit/.gitignore deleted file mode 100644 index 9f1eb4e8f..000000000 --- a/yosys/libs/subcircuit/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -demo -scshell diff --git a/yosys/libs/subcircuit/Makefile b/yosys/libs/subcircuit/Makefile deleted file mode 100644 index f81085b5b..000000000 --- a/yosys/libs/subcircuit/Makefile +++ /dev/null @@ -1,53 +0,0 @@ - -CONFIG := clang-debug -# CONFIG := gcc-debug -# CONFIG := profile -# CONFIG := release - -CC = clang -CXX = clang -CXXFLAGS = -MD -Wall -Wextra -ggdb -LDLIBS = -lstdc++ - -ifeq ($(CONFIG),clang-debug) -CXXFLAGS += -std=c++11 -O0 -endif - -ifeq ($(CONFIG),gcc-debug) -CC = gcc -CXX = gcc -CXXFLAGS += -std=gnu++0x -O0 -endif - -ifeq ($(CONFIG),profile) -CC = gcc -CXX = gcc -CXXFLAGS += -std=gnu++0x -Os -DNDEBUG -endif - -ifeq ($(CONFIG),release) -CC = gcc -CXX = gcc -CXXFLAGS += -std=gnu++0x -march=native -O3 -DNDEBUG -endif - -all: demo scshell - -demo: demo.o subcircuit.o - -scshell: scshell.o subcircuit.o - -test: scshell - ./scshell < test_macc22.txt - ./scshell < test_mine.txt - perl test_perm.pl | ./scshell - splrun test_shorts.spl | ./scshell - splrun test_large.spl | ./scshell - -clean: - rm -f demo scshell *.o *.d - -.PHONY: all test clean - --include *.d - diff --git a/yosys/libs/subcircuit/README b/yosys/libs/subcircuit/README deleted file mode 100644 index ecaa987db..000000000 --- a/yosys/libs/subcircuit/README +++ /dev/null @@ -1,466 +0,0 @@ - - ************************************************************************** - * * - * The SubCircuit C++11 library * - * * - * An implementation of a modified Ullmann Subgraph Isomorphism Algorithm * - * for coarse grain logic networks. by Clifford Wolf * - * * - ************************************************************************** - -============ -Introduction -============ - -This is a library that implements a modified Ullmann Subgraph Isomorphism -Algorithm with additional features aimed at working with coarse grain logic -networks. It also contains a simple frequent subcircuit mining algorithm. - -A simple command line tool that exposes the features of the library is also -included. - - -C++11 Warning -------------- - -This project is written in C++11. Use appropriate compiler switches to compile -it. Tested with clang version 3.0 and option -std=c++11. Also tested with gcc -version 4.6.3 and option -std=c++0x. - - -======== -Features -======== - -The input is two graphs (needle and haystack) that represent coarse grain -logic networks. The algorithm identifies all subgraphs of haystack that are -isomorphic to needle. - -The following additional features over the regular Ullmann Subgraph Isomorphism -Algorithm are provided by the library. - - * The graphs are attributed hypergraphs capable of representing netlists: - - - Nodes represent the logic cells: - - Nodes have types and only match compatible types - - Nodes have ports with variable bit-width - - - Hyperedges represent the signals: - - Each hyperedge connects one to many bits on ports on nodes - - - Callback functions for advanced attributes and compatibility rules: - Any set of node-node compatibility rules and edge-edge - compatibility rules can be implemented by providing - the necessary callback functions. - - * The algorithm is very efficient when all or many bits of one port are - connected to bits of the same other port. This is usually the case - in coarse grain logic networks. But the algorithm does not add any - restrictions in this area; it is just optimized for this scenario. - - * The algorithm can be configured to allow larger ports in needle cells to - match smaller ports in haystack cells in certain situations. This way it - is possible to e.g. have a 32-bit adder cell in the needle match a - 16-bit adder cell in the haystack. - - * The algorithm can be configured to perform port-swapping on certain - ports on certain cell types to match commutative operations properly. - - This is, however, not implemented very efficiently when a larger number - of permutations is possible on a cell type. Therefore it is recommended - to only use swap groups with only a few members and a few such groups - on one cell type type. - - Also note, that the algorithm can not resolve complex dependencies - between the port swappings of different cells. Therefore it is - recommended to only use port swapping on input pins of commutative - operations, where such complex dependencies can not emerge. - - * The algorithm can be configured to distinguish between internal signals - of the needle and externally visible signals. The needle will only - match a subgraph of the haystack if that subgraph does not expose the - internal signal to nodes in the haystack outside the matching subgraph. - - * The algorithm can recognize a subcircuit even if some or all of its - inputs and/or outputs are shorted together. - - * Explicit fast support for constant signals without extra nodes for - constant drivers. - - * Support for finding only non-overlapping matches. - - * A simple miner for frequent subcircuts that operates on the same circuit - description format. - - * The public API of the library is using std::string identifiers for - nodes, node types and ports. Internally the costly part of the - algorithm is only using integer values, thus speeding up the - algorithm without exposing complex internal encodings to the caller. - - -================= -API Documentation -================= - -This section gives a brief overview of the API. For a working example, have a -look at the demo.cc example program in this directory. - - -Setting up graphs ------------------ - -Instantiate the SubCircuit::Graph class and use the methods of this class to -set up the circuit. - - SubCircuit::Graph myGraph; - -For each node in the circuit call the createNode() method. Specify the -identifier for the node and also the type of function implemented by the node. -Then call createPort() for each port of this node. - -E.g. the following code adds a node "myAdder" of type "add" with three 32 bit -wide ports "A", "B" and "Y". Note that SubCircuit does not care which port is -an input and which port is an output. The last (and optional) argument to -createPort() specifies the minimum number of bits required for this port in the -haystack (this field is only used in the needle graph). So in this example the -node would e.g. also match any adder with a bit width smaller 32. - - myGraph.createNode("myAdder", "add"); - myGraph.createPort("myAdder", "A", 32, 1); - myGraph.createPort("myAdder", "B", 32, 1); - myGraph.createPort("myAdder", "Y", 32, 1); - -The createConnection() method can be used to connect the nodes. It internally -creates a hypergraph. So the following code does not only connect cell1.Y with -cell2.A and cell3.A but also implicitly cell2.A with cell3.A. - - myGraph.createConnection("cell1", "Y", "cell2", "A"); - myGraph.createConnection("cell1", "Y", "cell3", "A"); - -Redundent calls to createConnection() are ignored. As long as the method is -called after the relevant nodes and ports are created, the order in which the -createConnection() calls are performed is irrelevant. - -The createConnection() method can also be used to connect single bit signals. -In this case the start bit for both ports must be provided as well as an -optional width (which defaults to 1). E.g. the following calls can be used to -connect the 32 bit port cell4.Y to the 32 bit port cell5.A with a one bit left -rotate shift, - - myGraph.createConnection("cell4", "Y", 0, "cell5", "A", 1, 31); - myGraph.createConnection("cell4", "Y", 31, "cell5", "A", 0); - -The method createConstant() can be used to add a constant driver to a signal. -The signal value is encoded as one char by bit, allowing for multi-valued -logic matching. The following command sets the lowest bit of cell6.A to a -logic 1: - - myGraph.createConnection("cell6", "A", 0, '1'); - -It is also possible to set an entire port to a integer value, using the -encodings '0' and '1' for the binary digits: - - myGraph.createConnection("cell6", "A", 42); - -The method markExtern() can be used to mark a signal as externally visible. In -a needle graph this means, this signal may match a signal in the haystack that -is used outside the matching subgraph. In a haystack graph this means, this -signal is used outside the haystack graph. I.e. an internal signal of the -needle won't match an external signal of the haystack regardless where the -signal is used in the haystack. - -In some application one may disable this extern/intern checks. This can easily -be achieved by marking all signals in the needle as extern. This can be done -using the Graph::markAllExtern() method. - - -Setting up and running solvers ------------------------------- - -To actually run the subgraph isomorphism algorithm, an instance of -SubCircuit::Solver must be created. - - SubCircuit::Solver mySolver; - -The addGraph() method can be used to register graphs with the solver: - - mySolver.addGraph("graph1", myGraph); - mySolver.addGraph("graph2", myOtherGraph); - -Usually nodes in the needle and the haystack must have the same type identifier -to match each other. Additionally pairs of compatible needle and haystack node -pairs can be registered using the addCompatibleTypes() method: - - mySolver.addCompatibleTypes("alu", "add"); - mySolver.addCompatibleTypes("alu", "sub"); - mySolver.addCompatibleTypes("alu", "and"); - mySolver.addCompatibleTypes("alu", "or"); - mySolver.addCompatibleTypes("alu", "xor"); - -Note that nodes in needle and haystack must also use the same naming convention -for their ports in order to be considered compatible by the algorithm. - -Similarly the method addCompatibleConstants() can be used the specify which -constant values in the needle should match which constant value in the haystack. -Equal values always do match. - - mySolver.addCompatibleConstants('x', '0'); - mySolver.addCompatibleConstants('x', '1'); - -Some cells implement commutative operations that don't care if their input -operands are swapped. For this cell types it is possible to register groups -of swappable ports. Let's consider a cell "macc23" that implements the -function Y = (A * B) + (C * D * E): - - mySolver.addSwappablePorts("macc23", "A", "B"); - mySolver.addSwappablePorts("macc23", "C", "D", "E"); - -Sometimes the rules for port swapping are a more complicated and the swapping -of one port is related to the swapping of another port. Let's consider a cell -"macc22" that implements the function Y = (A * B) + (C * D): - - mySolver.addSwappablePorts("macc22", "A", "B"); - mySolver.addSwappablePorts("macc22", "C", "D"); - - std::map portMapping; - portMapping["A"] = "C"; - portMapping["B"] = "D"; - portMapping["C"] = "A"; - portMapping["D"] = "B"; - mySolver.addSwappablePortsPermutation("macc22", portMapping); - -I.e. the method mySolver.addSwappablePortsPermutation() can be used to register -additional permutations for a node type of which one or none is applied on top -of the permutations yielded by the permutations generated by the swap groups. - -Note that two solutions that differ only in the applied port swapping are not -reported as separate solutions. Instead only one of them is selected (in most -cases the one with less port swapping as it is usually identified first). - -Once everything has been set up, the solve() method can be used to actually -search for isomorphic subgraphs. The first argument to solve() is an -std::vector objects to which all found solutions -are appended. The second argument is the identifier under which the needle -graph has been registered and the third argument is the identifier under which -the haystack graph has been registered: - - std::vector results; - mySolver.solve(results, "graph1", "graph2"); - -The SubCircuit::Solver::Result object is a simple data structure that contains -the mappings between needle and haystack nodes, port mappings after the port -swapping and some additional metadata. See "subcircuit.h" and "demo.cc" for -details. - -The solve() method has a third optional boolean argument. If it is set to -false, solve will not return any solutions that contain haystack nodes that -have been part of a previously found solution. This way it is e.g. easy -to implement a greedy macro cell matching algorithm: - - std::vector results; - mySolver.solve(results, "macroCell1", "circuit", false); - mySolver.solve(results, "macroCell2", "circuit", false); - mySolver.solve(results, "macroCell3", "circuit", false); - -After this code has been executed, the results vector contains all -non-overlapping matches of the three macrocells. The method -clearOverlapHistory() can be used to reset the internal state used -for this feature. The default value for the third argument to solve() -is true (allow overlapping). The optional boolean fourth argument to the -Graph::createNode() method can be used to mark a node as shareable even -in non-overlapping solver mode. - -The solve() method also has a fourth optional integer argument. If it is set to -a positive integer, this integer specifies the maximum number of solutions to -be appended to the results vector, i.e. to terminate the algorithm early when -the set number of matches is found. When this fourth argument is negative or -omitted all matches are found and appended. - -An alternative version of the solve() method supports an additional argument -after they haystack graph identifier that specifies initial mappings for -the algorithm. In the following example only the haystack nodes cell_1 and -cell_2 are considered as mappings for the needle node cell_A: - - std::map> initialMappings; - initialMappings["cell_A"].insert("cell_1"); - initialMappings["cell_A"].insert("cell_2"); - - std::vector results; - mySolver.solve(results, "graph1", "graph2", initialMappings); - -The clearConfig() method can be used to clear all data registered using -addCompatibleTypes(), addCompatibleConstants(), addSwappablePorts() and -addSwappablePortsPermutation() but retaining the graphs and the overlap state. - - -Using user callback function ----------------------------- - -For more complex tasks it is possible to derive a class from SubCircuit::Solver -that overloads one or more of the following virtual methods. The userData -arguments to the following methods are void pointers that can be passed as -third argument to Graph::createNode() and are simly passed thru to the user -callback functions together with the node id whenever a node is referenced. - -bool userCompareNodes(needleGraphId, needleNodeId, needleUserData, haystackGraphId, haystackNodeId, haystackUserData): - - Perform additional checks on a pair of nodes (one from the needle, one - from the haystack) to determine if the nodes are compatible. The default - implementation always returns true. - - -bool userCompareEdge(needleGraphId, needleFromNodeId, needleFromUserData, needleToNodeId, needleToUserData, - haystackGraphId, haystackFromNodeId, haystackFromUserData, haystackToNodeId, haystackToUserData): - - Perform additional checks on a pair of a pair of adjacent nodes (one - adjacent pair from the needle and one adjacent pair from the haystack) - to determine whether this edge from the needle is compatible with - that edge from the haystack. The default implementation always - returns true. - -bool userCheckSolution(result): - - Perform additional checks on a solution before appending it to the - results vector. When this function returns false, the solution is - ignored. The default implementation always returns true. - - -Mining for frequent SubCircuits -------------------------------- - -The solver also contains a miner for frequent subcircuits. The following code -fragment will find all frequent subcircuits with at least minNodes nodes and -at most maxNodes nodes that occurs at least minMatches times: - - std::vector results; - mySolver.mine(results, minNodes, maxNodes, minMatches); - -The mine() method has an optional fifth parameter that limits the number of -matches counted in one graph. This can be useful when mining for circuits that -are found in at least a number of graphs. E.g. the following call would find -all subcircuits with 5 nodes that are found in at least 7 of the registered -graphs: - - mySolver.mine(results, 5, 5, 7, 1); - -Note that this miner is not very efficient and therefore its use is not -recommended for large circuits. Also note that the miner is working under the -assumption that subgraph isomorphism is bidirectional. This is not the case in -circuits with gates with shorted pins. This can result in undetected frequent -subcircuits in some corner cases. - - -Debugging ---------- - -For debugging purposes the SubCircuit::Solver class implements a setVerbose() -method. When called once, all further calls to the solve() method cause the -algorithm to dump out a lot of debug information to stdout. - -In conjunction with setVerbose() one can also overload the userAnnotateEdge() -method in order to add additional information about the edges to the debug -output. - - -=================== -Shell Documentation -=================== - -This package also contains a small command-line tool called "scshell" that can -be used for experimentation with the algorithm. This program reads a series of -commands from stdin and reports its findings to stdout on exit. - - $ ./scshell < test_macc22.txt - - ... - - Match #3: (macc22 in macc4x2) - add_1 -> add_2 A:B B:A Y:Y - mul_1 -> mul_4 A:A B:B Y:Y - mul_2 -> mul_3 A:A B:B Y:Y - -The following commands can be used in scshell to specify graphs: - - graph - ... - endgraph - - Used to specify a graph with the given name. Only the commands - "node", "connect" and "extern" may be used within the graph ... - endgraph block. - - node [ [ []]]+ - - Used to create a node and ports. This command is a direct frontend - to the Graph::createNode() and Graph::createPort() methods. - - connect - connect - connect - - Used to connect the nodes in the graph via Graph::createConnection(). - - constant [] - - Call Graph::createConstant(). - - extern [ []]+ - - Mark signals as extern via Graph::markExtern(). - - allextern - - Mark all signals as extern via Graph::markAllExtern(). - -The following commands can be used in scshell outside a graph ... endgraph block: - - compatible - - Call Solver::addCompatibleTypes(). - - constcompat - - Call Solver::addCompatibleConstants(). - - swapgroup + - - Call Solver::addSwappablePorts(). - - swapperm + : + - - Call Solver::addSwappablePortsPermutation(). Both port lists must - have the same length and the second one must be a permutation of the - first one. - - initmap + - - Add an entry to the initial mappings for the next solve command. - This mappings are automatically reset after the solve command. - - solve [ []] - - Call Solver::solve(). The must be "1" or "true" - for true and "0" or "false" for false. - - mine [] - - Call Solver::mine(). - - expect - - Print all results so far since the last call to expect. Expect - results and exit with error code 1 if a different number - of results have been found. - - clearoverlap - - Call Solver::clearOverlapHistory(). - - clearconfig - - Call Solver::clearConfig(). - - verbose - - Call Solver::setVerbose(). - diff --git a/yosys/libs/subcircuit/demo.cc b/yosys/libs/subcircuit/demo.cc deleted file mode 100644 index 149dc6aa0..000000000 --- a/yosys/libs/subcircuit/demo.cc +++ /dev/null @@ -1,134 +0,0 @@ -#include "subcircuit.h" -#include - -#define VERBOSE - -int main() -{ - SubCircuit::Graph needle, haystack; - - // create needle graph - - needle.createNode("mul_1", "product"); - needle.createPort("mul_1", "A", 4); - needle.createPort("mul_1", "B", 4); - needle.createPort("mul_1", "Y", 4); - needle.markExtern("mul_1", "A"); - needle.markExtern("mul_1", "B"); - - needle.createNode("mul_2", "product"); - needle.createPort("mul_2", "A", 4); - needle.createPort("mul_2", "B", 4); - needle.createPort("mul_2", "Y", 4); - needle.markExtern("mul_2", "A"); - needle.markExtern("mul_2", "B"); - - needle.createNode("add_1", "sum"); - needle.createPort("add_1", "A", 4); - needle.createPort("add_1", "B", 4); - needle.createPort("add_1", "Y", 4); - needle.markExtern("add_1", "Y"); - - needle.createConnection("mul_1", "Y", "add_1", "A"); - needle.createConnection("mul_2", "Y", "add_1", "B"); - -#ifdef VERBOSE - printf("\n"); - needle.print(); -#endif - - // create haystack graph - -#if 0 - for (int i = 0; i < 4; i++) { - char id[100]; - snprintf(id, 100, "mul_%d", i); - haystack.createNode(id, "mul"); - haystack.createPort(id, "A", 4); - haystack.createPort(id, "B", 4); - haystack.createPort(id, "Y", 4); - haystack.markExtern(id, "A"); - haystack.markExtern(id, "B"); - } - - for (int i = 0; i < 3; i++) { - char id[100]; - snprintf(id, 100, "add_%d", i); - haystack.createNode(id, "add"); - haystack.createPort(id, "A", 4); - haystack.createPort(id, "B", 4); - haystack.createPort(id, "Y", 4); - } - - haystack.createConnection("mul_0", "Y", "add_0", "A"); - haystack.createConnection("mul_1", "Y", "add_0", "B"); - - haystack.createConnection("mul_2", "Y", "add_1", "A"); - haystack.createConnection("mul_3", "Y", "add_1", "B"); - - haystack.createConnection("add_0", "Y", "add_2", "A"); - haystack.createConnection("add_1", "Y", "add_2", "B"); - haystack.markExtern("add_2", "Y"); -#else - std::vector cellIds; - srand48(12345); - - for (int i = 0; i < 45; i++) { - char id[100]; - snprintf(id, 100, "cell_%02d", i); - haystack.createNode(id, i < 30 ? "mul" : "add"); - haystack.createPort(id, "A", 4); - haystack.createPort(id, "B", 4); - haystack.createPort(id, "Y", 4); - cellIds.push_back(id); - } - - for (int i = 0; i < int(cellIds.size()); i++) { - if (lrand48() % (i < 20 ? 3 : 2) != 0) - continue; - const std::string &id = cellIds[i]; - const std::string &id_left = cellIds[lrand48() % cellIds.size()]; - const std::string &id_right = cellIds[lrand48() % cellIds.size()]; - haystack.createConnection(id_left, "Y", id, "A"); - haystack.createConnection(id_right, "Y", id, "B"); - } -#endif - -#ifdef VERBOSE - printf("\n"); - haystack.print(); -#endif - - // search needle in haystack - - SubCircuit::Solver solver; - std::vector results; - -#ifdef VERBOSE - solver.setVerbose(); -#endif - - solver.addCompatibleTypes("product", "mul"); - solver.addCompatibleTypes("sum", "add"); - - solver.addSwappablePorts("product", "A", "B"); - solver.addSwappablePorts("sum", "A", "B"); - - solver.addGraph("needle", needle); - solver.addGraph("haystack", haystack); - solver.solve(results, "needle", "haystack"); - - for (int i = 0; i < int(results.size()); i++) { - printf("\nMatch #%d: (%s in %s)\n", i, results[i].needleGraphId.c_str(), results[i].haystackGraphId.c_str()); - for (const auto &it : results[i].mappings) { - printf(" %s -> %s", it.first.c_str(), it.second.haystackNodeId.c_str()); - for (const auto &it2 : it.second.portMapping) - printf(" %s:%s", it2.first.c_str(), it2.second.c_str()); - printf("\n"); - } - } - - printf("\n"); - return 0; -} - diff --git a/yosys/libs/subcircuit/scshell.cc b/yosys/libs/subcircuit/scshell.cc deleted file mode 100644 index c4b37a4de..000000000 --- a/yosys/libs/subcircuit/scshell.cc +++ /dev/null @@ -1,261 +0,0 @@ -#include "subcircuit.h" -#include -#include -#include - -std::vector readLine() -{ - char buffer[4096]; - std::vector tokenList; - - while (tokenList.size() == 0 && fgets(buffer, sizeof(buffer), stdin) != NULL) { - for (char *p = buffer; char *tok = strtok(p, " \t\r\n"); p = NULL) { - if (p != NULL && tok[0] == '#') - break; - tokenList.push_back(tok); - } - } - - return tokenList; -} - -int main() -{ - std::string graphId; - SubCircuit::Graph *graph = NULL; - SubCircuit::Solver solver; - std::map> initialMappings; - std::vector results; - std::vector mineResults; - std::vector cmdBuffer; - bool lastCommandExpect = false; - - while (1) - { - cmdBuffer = readLine(); - if (cmdBuffer.empty()) - break; - - printf(graph == NULL || cmdBuffer[0] == "endgraph" ? ">" : "> "); - for (const auto &tok : cmdBuffer) - printf(" %s", tok.c_str()); - printf("\n"); - - lastCommandExpect = false; - - if (graph != NULL) - { - if (cmdBuffer[0] == "node" && cmdBuffer.size() >= 3) { - graph->createNode(cmdBuffer[1], cmdBuffer[2]); - for (int i = 3; i < int(cmdBuffer.size()); i++) { - std::string portId = cmdBuffer[i]; - int width = 1, minWidth = -1; - if (i+1 < int(cmdBuffer.size()) && '0' <= cmdBuffer[i+1][0] && cmdBuffer[i+1][0] <= '9') - width = atoi(cmdBuffer[++i].c_str()); - if (i+1 < int(cmdBuffer.size()) && '0' <= cmdBuffer[i+1][0] && cmdBuffer[i+1][0] <= '9') - minWidth = atoi(cmdBuffer[++i].c_str()); - graph->createPort(cmdBuffer[1], portId, width, minWidth); - } - continue; - } - - if (cmdBuffer[0] == "connect" && cmdBuffer.size() == 5) { - graph->createConnection(cmdBuffer[1], cmdBuffer[2], cmdBuffer[3], cmdBuffer[4]); - continue; - } - - if (cmdBuffer[0] == "connect" && cmdBuffer.size() == 7) { - graph->createConnection(cmdBuffer[1], cmdBuffer[2], atoi(cmdBuffer[3].c_str()), cmdBuffer[4], cmdBuffer[5], atoi(cmdBuffer[6].c_str())); - continue; - } - - if (cmdBuffer[0] == "connect" && cmdBuffer.size() == 8) { - graph->createConnection(cmdBuffer[1], cmdBuffer[2], atoi(cmdBuffer[3].c_str()), cmdBuffer[4], cmdBuffer[5], atoi(cmdBuffer[6].c_str()), atoi(cmdBuffer[7].c_str())); - continue; - } - - if (cmdBuffer[0] == "constant" && cmdBuffer.size() == 5) { - int constValue = cmdBuffer[4].size() > 1 && cmdBuffer[4][0] == '#' ? atoi(cmdBuffer[4].c_str()+1) : cmdBuffer[4][0]; - graph->createConstant(cmdBuffer[1], cmdBuffer[2], atoi(cmdBuffer[3].c_str()), constValue); - continue; - } - - if (cmdBuffer[0] == "constant" && cmdBuffer.size() == 4) { - graph->createConstant(cmdBuffer[1], cmdBuffer[2], atoi(cmdBuffer[3].c_str())); - continue; - } - - if (cmdBuffer[0] == "extern" && cmdBuffer.size() >= 3) { - for (int i = 2; i < int(cmdBuffer.size()); i++) { - std::string portId = cmdBuffer[i]; - int bit = -1; - if (i+1 < int(cmdBuffer.size()) && '0' <= cmdBuffer[i+1][0] && cmdBuffer[i+1][0] <= '9') - bit = atoi(cmdBuffer[++i].c_str()); - graph->markExtern(cmdBuffer[1], portId, bit); - } - continue; - } - - if (cmdBuffer[0] == "allextern" && cmdBuffer.size() == 1) { - graph->markAllExtern(); - continue; - } - - if (cmdBuffer[0] == "endgraph" && cmdBuffer.size() == 1) { - solver.addGraph(graphId, *graph); - delete graph; - graph = NULL; - continue; - } - } - else - { - if (cmdBuffer[0] == "graph" && cmdBuffer.size() == 2) { - graph = new SubCircuit::Graph; - graphId = cmdBuffer[1]; - continue; - } - - if (cmdBuffer[0] == "compatible" && cmdBuffer.size() == 3) { - solver.addCompatibleTypes(cmdBuffer[1], cmdBuffer[2]); - continue; - } - - if (cmdBuffer[0] == "constcompat" && cmdBuffer.size() == 3) { - int needleConstValue = cmdBuffer[1].size() > 1 && cmdBuffer[1][0] == '#' ? atoi(cmdBuffer[1].c_str()+1) : cmdBuffer[1][0]; - int haystackConstValue = cmdBuffer[2].size() > 1 && cmdBuffer[2][0] == '#' ? atoi(cmdBuffer[2].c_str()+1) : cmdBuffer[2][0]; - solver.addCompatibleConstants(needleConstValue, haystackConstValue); - continue; - } - - if (cmdBuffer[0] == "swapgroup" && cmdBuffer.size() >= 4) { - std::set ports; - for (int i = 2; i < int(cmdBuffer.size()); i++) - ports.insert(cmdBuffer[i]); - solver.addSwappablePorts(cmdBuffer[1], ports); - continue; - } - - if (cmdBuffer[0] == "swapperm" && cmdBuffer.size() >= 4 && cmdBuffer.size() % 2 == 1 && cmdBuffer[cmdBuffer.size()/2 + 1] == ":") { - std::map portMapping; - int n = (cmdBuffer.size()-3) / 2; - for (int i = 0; i < n; i++) - portMapping[cmdBuffer[i+2]] = cmdBuffer[i+3+n]; - solver.addSwappablePortsPermutation(cmdBuffer[1], portMapping); - continue; - } - - if (cmdBuffer[0] == "initmap" && cmdBuffer.size() >= 4) { - for (int i = 2; i < int(cmdBuffer.size()); i++) - initialMappings[cmdBuffer[1]].insert(cmdBuffer[i]); - continue; - } - - if (cmdBuffer[0] == "solve" && 3 <= cmdBuffer.size() && cmdBuffer.size() <= 5) { - bool allowOverlap = true; - int maxSolutions = -1; - if (cmdBuffer.size() >= 4) - allowOverlap = cmdBuffer[3] == "true" || atoi(cmdBuffer[3].c_str()) ? true : false; - if (cmdBuffer.size() >= 5) - maxSolutions = atoi(cmdBuffer[4].c_str()); - solver.solve(results, cmdBuffer[1], cmdBuffer[2], initialMappings, allowOverlap, maxSolutions); - initialMappings.clear(); - continue; - } - - if (cmdBuffer[0] == "mine" && 4 <= cmdBuffer.size() && cmdBuffer.size() <= 5) { - solver.mine(mineResults, atoi(cmdBuffer[1].c_str()), atoi(cmdBuffer[2].c_str()), - atoi(cmdBuffer[3].c_str()), cmdBuffer.size() == 5 ? atoi(cmdBuffer[4].c_str()) : -1); - continue; - } - - if (cmdBuffer[0] == "clearoverlap" && cmdBuffer.size() == 1) { - solver.clearOverlapHistory(); - continue; - } - - if (cmdBuffer[0] == "clearconfig" && cmdBuffer.size() == 1) { - solver.clearConfig(); - continue; - } - - if (cmdBuffer[0] == "verbose" && cmdBuffer.size() == 1) { - solver.setVerbose(); - continue; - } - - if (cmdBuffer[0] == "expect" && cmdBuffer.size() == 2) { - int expected = atoi(cmdBuffer[1].c_str()); - printf("\n-- Expected %d, Got %d --\n", expected, int(results.size()) + int(mineResults.size())); - for (int i = 0; i < int(results.size()); i++) { - printf("\nMatch #%d: (%s in %s)\n", i, results[i].needleGraphId.c_str(), results[i].haystackGraphId.c_str()); - for (const auto &it : results[i].mappings) { - printf(" %s -> %s", it.first.c_str(), it.second.haystackNodeId.c_str()); - for (const auto &it2 : it.second.portMapping) - printf(" %s:%s", it2.first.c_str(), it2.second.c_str()); - printf("\n"); - } - } - for (auto &result : mineResults) { - printf("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits); - printf(" primary match in %s:", result.graphId.c_str()); - for (auto &node : result.nodes) - printf(" %s", node.nodeId.c_str()); - printf("\n"); - for (auto &it : result.matchesPerGraph) - printf(" matches in %s: %d\n", it.first.c_str(), it.second); - } - printf("\n"); - if (expected != int(results.size()) + int(mineResults.size())) { - printf("^^ expected %d, Got %d ^^\n\n", expected, int(results.size()) + int(mineResults.size())); - printf(" +----------------+\n"); - printf(" | \\|/ ____ \\|/ |\n"); - printf(" | \"@'/ ,. \\`@\" |\n"); - printf(" | /_| \\__/ |_\\ |\n"); - printf(" | \\__U_/ |\n"); - printf(" | | | |\n"); - printf(" +----------------+\n\n"); - return 1; - } - results.clear(); - mineResults.clear(); - lastCommandExpect = true; - continue; - } - } - - printf("Invalid input command!\n"); - return 1; - } - - if (graph) - delete graph; - - if (!lastCommandExpect) { - printf("\n-- Got %d --\n", int(results.size()) + int(mineResults.size())); - for (int i = 0; i < int(results.size()); i++) { - printf("\nMatch #%d: (%s in %s)\n", i, results[i].needleGraphId.c_str(), results[i].haystackGraphId.c_str()); - for (const auto &it : results[i].mappings) { - printf(" %s -> %s", it.first.c_str(), it.second.haystackNodeId.c_str()); - for (const auto &it2 : it.second.portMapping) - printf(" %s:%s", it2.first.c_str(), it2.second.c_str()); - printf("\n"); - } - } - for (auto &result : mineResults) { - printf("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits); - printf(" primary match in %s:", result.graphId.c_str()); - for (auto &node : result.nodes) - printf(" %s", node.nodeId.c_str()); - printf("\n"); - for (auto &it : result.matchesPerGraph) - printf(" matches in %s: %d\n", it.first.c_str(), it.second); - } - } else - printf("PASSED.\n"); - - printf("\n"); - - return 0; -} - diff --git a/yosys/libs/subcircuit/subcircuit.cc b/yosys/libs/subcircuit/subcircuit.cc deleted file mode 100644 index e8361a67e..000000000 --- a/yosys/libs/subcircuit/subcircuit.cc +++ /dev/null @@ -1,1692 +0,0 @@ -/* - * SubCircuit -- An implementation of the Ullmann Subgraph Isomorphism - * algorithm for coarse grain logic networks - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "subcircuit.h" - -#include -#include -#include -#include - -#ifdef _YOSYS_ -# include "kernel/yosys.h" -# define my_printf YOSYS_NAMESPACE_PREFIX log -#else -# define my_printf printf -#endif - -using namespace SubCircuit; - -#ifndef _YOSYS_ -static std::string my_stringf(const char *fmt, ...) -{ - std::string string; - char *str = NULL; - va_list ap; - - va_start(ap, fmt); - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; - va_end(ap); - - if (str != NULL) { - string = str; - free(str); - } - - return string; -} -#else -# define my_stringf YOSYS_NAMESPACE_PREFIX stringf -#endif - -SubCircuit::Graph::Graph(const Graph &other, const std::vector &otherNodes) -{ - allExtern = other.allExtern; - - std::map other2this; - for (int i = 0; i < int(otherNodes.size()); i++) { - assert(other.nodeMap.count(otherNodes[i]) > 0); - other2this[other.nodeMap.at(otherNodes[i])] = i; - nodeMap[otherNodes[i]] = i; - } - - std::map edges2this; - for (auto &i1 : other2this) - for (auto &i2 : other.nodes[i1.first].ports) - for (auto &i3 : i2.bits) - if (edges2this.count(i3.edgeIdx) == 0) { - int next_idx = edges2this.size(); - edges2this[i3.edgeIdx] = next_idx; - } - - edges.resize(edges2this.size()); - for (auto &it : edges2this) { - for (auto &bit : other.edges[it.first].portBits) - if (other2this.count(bit.nodeIdx) > 0) - edges[it.second].portBits.insert(BitRef(other2this[bit.nodeIdx], bit.portIdx, bit.bitIdx)); - edges[it.second].constValue = other.edges[it.first].constValue; - edges[it.second].isExtern = other.edges[it.first].isExtern; - } - - nodes.resize(other2this.size()); - for (auto &it : other2this) { - nodes[it.second] = other.nodes[it.first]; - for (auto &i2 : nodes[it.second].ports) - for (auto &i3 : i2.bits) - i3.edgeIdx = edges2this.at(i3.edgeIdx); - } -} - -bool SubCircuit::Graph::BitRef::operator < (const BitRef &other) const -{ - if (nodeIdx != other.nodeIdx) - return nodeIdx < other.nodeIdx; - if (portIdx != other.portIdx) - return portIdx < other.portIdx; - return bitIdx < other.bitIdx; -} - -void SubCircuit::Graph::createNode(std::string nodeId, std::string typeId, void *userData, bool shared) -{ - assert(nodeMap.count(nodeId) == 0); - nodeMap[nodeId] = nodes.size(); - nodes.push_back(Node()); - - Node &newNode = nodes.back(); - newNode.nodeId = nodeId; - newNode.typeId = typeId; - newNode.userData = userData; - newNode.shared = shared; -} - -void SubCircuit::Graph::createPort(std::string nodeId, std::string portId, int width, int minWidth) -{ - assert(nodeMap.count(nodeId) != 0); - int nodeIdx = nodeMap[nodeId]; - Node &node = nodes[nodeIdx]; - - assert(node.portMap.count(portId) == 0); - - int portIdx = node.ports.size(); - node.portMap[portId] = portIdx; - node.ports.push_back(Port()); - Port &port = node.ports.back(); - - port.portId = portId; - port.minWidth = minWidth < 0 ? width : minWidth; - port.bits.insert(port.bits.end(), width, PortBit()); - - for (int i = 0; i < width; i++) { - port.bits[i].edgeIdx = edges.size(); - edges.push_back(Edge()); - edges.back().portBits.insert(BitRef(nodeIdx, portIdx, i)); - } -} - -void SubCircuit::Graph::createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width) -{ - assert(nodeMap.count(fromNodeId) != 0); - assert(nodeMap.count(toNodeId) != 0); - - int fromNodeIdx = nodeMap[fromNodeId]; - Node &fromNode = nodes[fromNodeIdx]; - - int toNodeIdx = nodeMap[toNodeId]; - Node &toNode = nodes[toNodeIdx]; - - assert(fromNode.portMap.count(fromPortId) != 0); - assert(toNode.portMap.count(toPortId) != 0); - - int fromPortIdx = fromNode.portMap[fromPortId]; - Port &fromPort = fromNode.ports[fromPortIdx]; - - int toPortIdx = toNode.portMap[toPortId]; - Port &toPort = toNode.ports[toPortIdx]; - - if (width < 0) { - assert(fromBit == 0 && toBit == 0); - assert(fromPort.bits.size() == toPort.bits.size()); - width = fromPort.bits.size(); - } - - assert(fromBit >= 0 && toBit >= 0); - for (int i = 0; i < width; i++) - { - assert(fromBit + i < int(fromPort.bits.size())); - assert(toBit + i < int(toPort.bits.size())); - - int fromEdgeIdx = fromPort.bits[fromBit + i].edgeIdx; - int toEdgeIdx = toPort.bits[toBit + i].edgeIdx; - - if (fromEdgeIdx == toEdgeIdx) - continue; - - // merge toEdge into fromEdge - if (edges[toEdgeIdx].isExtern) - edges[fromEdgeIdx].isExtern = true; - if (edges[toEdgeIdx].constValue) { - assert(edges[fromEdgeIdx].constValue == 0); - edges[fromEdgeIdx].constValue = edges[toEdgeIdx].constValue; - } - for (const auto &ref : edges[toEdgeIdx].portBits) { - edges[fromEdgeIdx].portBits.insert(ref); - nodes[ref.nodeIdx].ports[ref.portIdx].bits[ref.bitIdx].edgeIdx = fromEdgeIdx; - } - - // remove toEdge (move last edge over toEdge if needed) - if (toEdgeIdx+1 != int(edges.size())) { - edges[toEdgeIdx] = edges.back(); - for (const auto &ref : edges[toEdgeIdx].portBits) - nodes[ref.nodeIdx].ports[ref.portIdx].bits[ref.bitIdx].edgeIdx = toEdgeIdx; - } - edges.pop_back(); - } -} - -void SubCircuit::Graph::createConnection(std::string fromNodeId, std::string fromPortId, std::string toNodeId, std::string toPortId) -{ - createConnection(fromNodeId, fromPortId, 0, toNodeId, toPortId, 0, -1); -} - -void SubCircuit::Graph::createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue) -{ - assert(nodeMap.count(toNodeId) != 0); - int toNodeIdx = nodeMap[toNodeId]; - Node &toNode = nodes[toNodeIdx]; - - assert(toNode.portMap.count(toPortId) != 0); - int toPortIdx = toNode.portMap[toPortId]; - Port &toPort = toNode.ports[toPortIdx]; - - assert(toBit >= 0 && toBit < int(toPort.bits.size())); - int toEdgeIdx = toPort.bits[toBit].edgeIdx; - - assert(edges[toEdgeIdx].constValue == 0); - edges[toEdgeIdx].constValue = constValue; -} - -void SubCircuit::Graph::createConstant(std::string toNodeId, std::string toPortId, int constValue) -{ - assert(nodeMap.count(toNodeId) != 0); - int toNodeIdx = nodeMap[toNodeId]; - Node &toNode = nodes[toNodeIdx]; - - assert(toNode.portMap.count(toPortId) != 0); - int toPortIdx = toNode.portMap[toPortId]; - Port &toPort = toNode.ports[toPortIdx]; - - for (int i = 0; i < int(toPort.bits.size()); i++) { - int toEdgeIdx = toPort.bits[i].edgeIdx; - assert(edges[toEdgeIdx].constValue == 0); - edges[toEdgeIdx].constValue = constValue % 2 ? '1' : '0'; - constValue = constValue >> 1; - } -} - -void SubCircuit::Graph::markExtern(std::string nodeId, std::string portId, int bit) -{ - assert(nodeMap.count(nodeId) != 0); - Node &node = nodes[nodeMap[nodeId]]; - - assert(node.portMap.count(portId) != 0); - Port &port = node.ports[node.portMap[portId]]; - - if (bit < 0) { - for (const auto portBit : port.bits) - edges[portBit.edgeIdx].isExtern = true; - } else { - assert(bit < int(port.bits.size())); - edges[port.bits[bit].edgeIdx].isExtern = true; - } -} - -void SubCircuit::Graph::markAllExtern() -{ - allExtern = true; -} - -void SubCircuit::Graph::print() -{ - for (int i = 0; i < int(nodes.size()); i++) { - const Node &node = nodes[i]; - my_printf("NODE %d: %s (%s)\n", i, node.nodeId.c_str(), node.typeId.c_str()); - for (int j = 0; j < int(node.ports.size()); j++) { - const Port &port = node.ports[j]; - my_printf(" PORT %d: %s (%d/%d)\n", j, port.portId.c_str(), port.minWidth, int(port.bits.size())); - for (int k = 0; k < int(port.bits.size()); k++) { - int edgeIdx = port.bits[k].edgeIdx; - my_printf(" BIT %d (%d):", k, edgeIdx); - for (const auto &ref : edges[edgeIdx].portBits) - my_printf(" %d.%d.%d", ref.nodeIdx, ref.portIdx, ref.bitIdx); - if (edges[edgeIdx].isExtern) - my_printf(" [extern]"); - my_printf("\n"); - } - } - } -} - -class SubCircuit::SolverWorker -{ - // basic internal data structures - - typedef std::vector> adjMatrix_t; - - struct GraphData { - std::string graphId; - Graph graph; - adjMatrix_t adjMatrix; - std::vector usedNodes; - }; - - static void printAdjMatrix(const adjMatrix_t &matrix) - { - my_printf("%7s", ""); - for (int i = 0; i < int(matrix.size()); i++) - my_printf("%4d:", i); - my_printf("\n"); - for (int i = 0; i < int(matrix.size()); i++) { - my_printf("%5d:", i); - for (int j = 0; j < int(matrix.size()); j++) - if (matrix.at(i).count(j) == 0) - my_printf("%5s", "-"); - else - my_printf("%5d", matrix.at(i).at(j)); - my_printf("\n"); - } - } - - // helper functions for handling permutations - - static const int maxPermutationsLimit = 1000000; - - static int numberOfPermutations(const std::vector &list) - { - constexpr size_t mappedPermutationsSize = 10; - constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; - assert(list.size() < mappedPermutationsSize); - return mappedPermutations[list.size()]; - } - - static void permutateVectorToMap(std::map &map, const std::vector &list, int idx) - { - // convert idx to a list.size() digits factoradic number - - std::vector factoradicDigits; - for (int i = 0; i < int(list.size()); i++) { - factoradicDigits.push_back(idx % (i+1)); - idx = idx / (i+1); - } - - // construct permutation - - std::vector pool = list; - std::vector permutation; - - while (!factoradicDigits.empty()) { - int i = factoradicDigits.back(); - factoradicDigits.pop_back(); - permutation.push_back(pool[i]); - pool.erase(pool.begin() + i); - } - - // update map - - for (int i = 0; i < int(list.size()); i++) - map[list[i]] = permutation[i]; - } - - static int numberOfPermutationsArray(const std::vector> &list) - { - int numPermutations = 1; - for (const auto &it : list) { - int thisPermutations = numberOfPermutations(it); - assert(float(numPermutations) * float(thisPermutations) < maxPermutationsLimit); - numPermutations *= thisPermutations; - } - return numPermutations; - } - - static void permutateVectorToMapArray(std::map &map, const std::vector> &list, int idx) - { - for (const auto &it : list) { - int thisPermutations = numberOfPermutations(it); - int thisIdx = idx % thisPermutations; - permutateVectorToMap(map, it, thisIdx); - idx /= thisPermutations; - } - } - - static void applyPermutation(std::map &map, const std::map &permutation) - { - std::vector> changeLog; - for (const auto &it : permutation) - if (map.count(it.second)) - changeLog.push_back(std::pair(it.first, map.at(it.second))); - else - changeLog.push_back(std::pair(it.first, it.second)); - for (const auto &it : changeLog) - map[it.first] = it.second; - } - - // classes for internal digraph representation - - struct DiBit - { - std::string fromPort, toPort; - int fromBit, toBit; - - DiBit() : fromPort(), toPort(), fromBit(-1), toBit(-1) { } - DiBit(std::string fromPort, int fromBit, std::string toPort, int toBit) : fromPort(fromPort), toPort(toPort), fromBit(fromBit), toBit(toBit) { } - - bool operator < (const DiBit &other) const - { - if (fromPort != other.fromPort) - return fromPort < other.fromPort; - if (toPort != other.toPort) - return toPort < other.toPort; - if (fromBit != other.fromBit) - return fromBit < other.fromBit; - return toBit < other.toBit; - } - - std::string toString() const - { - return my_stringf("%s[%d]:%s[%d]", fromPort.c_str(), fromBit, toPort.c_str(), toBit); - } - }; - - struct DiNode - { - std::string typeId; - std::map portSizes; - - DiNode() - { - } - - DiNode(const Graph &graph, int nodeIdx) - { - const Graph::Node &node = graph.nodes.at(nodeIdx); - typeId = node.typeId; - for (const auto &port : node.ports) - portSizes[port.portId] = port.bits.size(); - } - - bool operator < (const DiNode &other) const - { - if (typeId != other.typeId) - return typeId < other.typeId; - return portSizes < other.portSizes; - } - - std::string toString() const - { - std::string str; - bool firstPort = true; - for (const auto &it : portSizes) { - str += my_stringf("%s%s[%d]", firstPort ? "" : ",", it.first.c_str(), it.second); - firstPort = false; - } - return typeId + "(" + str + ")"; - } - }; - - struct DiEdge - { - DiNode fromNode, toNode; - std::set bits; - std::string userAnnotation; - - bool operator < (const DiEdge &other) const - { - if (fromNode < other.fromNode || other.fromNode < fromNode) - return fromNode < other.fromNode; - if (toNode < other.toNode || other.toNode < toNode) - return toNode < other.toNode; - if (bits < other.bits || other.bits < bits) - return bits < other.bits; - return userAnnotation < other.userAnnotation; - } - - bool compare(const DiEdge &other, const std::map &mapFromPorts, const std::map &mapToPorts) const - { - // Rules for matching edges: - // - // For all bits in the needle edge: - // - ignore if needle ports don't exist in haystack edge - // - otherwise: matching bit in haystack edge must exist - // - // There is no need to check in the other direction, as checking - // of the isExtern properties is already performed in node matching. - // - // Note: "this" is needle, "other" is haystack - - for (auto bit : bits) - { - if (mapFromPorts.count(bit.fromPort) > 0) - bit.fromPort = mapFromPorts.at(bit.fromPort); - if (mapToPorts.count(bit.toPort) > 0) - bit.toPort = mapToPorts.at(bit.toPort); - - if (other.fromNode.portSizes.count(bit.fromPort) == 0) - continue; - if (other.toNode.portSizes.count(bit.toPort) == 0) - continue; - - if (bit.fromBit >= other.fromNode.portSizes.at(bit.fromPort)) - continue; - if (bit.toBit >= other.toNode.portSizes.at(bit.toPort)) - continue; - - if (other.bits.count(bit) == 0) - return false; - } - - return true; - } - - bool compareWithFromAndToPermutations(const DiEdge &other, const std::map &mapFromPorts, const std::map &mapToPorts, - const std::map>> &swapPermutations) const - { - if (swapPermutations.count(fromNode.typeId) > 0) - for (const auto &permutation : swapPermutations.at(fromNode.typeId)) { - std::map thisMapFromPorts = mapFromPorts; - applyPermutation(thisMapFromPorts, permutation); - if (compareWithToPermutations(other, thisMapFromPorts, mapToPorts, swapPermutations)) - return true; - } - return compareWithToPermutations(other, mapFromPorts, mapToPorts, swapPermutations); - } - - bool compareWithToPermutations(const DiEdge &other, const std::map &mapFromPorts, const std::map &mapToPorts, - const std::map>> &swapPermutations) const - { - if (swapPermutations.count(toNode.typeId) > 0) - for (const auto &permutation : swapPermutations.at(toNode.typeId)) { - std::map thisMapToPorts = mapToPorts; - applyPermutation(thisMapToPorts, permutation); - if (compare(other, mapFromPorts, thisMapToPorts)) - return true; - } - return compare(other, mapFromPorts, mapToPorts); - } - - bool compare(const DiEdge &other, const std::map>> &swapPorts, - const std::map>> &swapPermutations) const - { - // brute force method for port swapping: try all variations - - std::vector> swapFromPorts; - std::vector> swapToPorts; - - // only use groups that are relevant for this edge - - if (swapPorts.count(fromNode.typeId) > 0) - for (const auto &ports : swapPorts.at(fromNode.typeId)) { - for (const auto &bit : bits) - if (ports.count(bit.fromPort)) - goto foundFromPortMatch; - if (0) { - foundFromPortMatch: - std::vector portsVector; - for (const auto &port : ports) - portsVector.push_back(port); - swapFromPorts.push_back(portsVector); - } - } - - if (swapPorts.count(toNode.typeId) > 0) - for (const auto &ports : swapPorts.at(toNode.typeId)) { - for (const auto &bit : bits) - if (ports.count(bit.toPort)) - goto foundToPortMatch; - if (0) { - foundToPortMatch: - std::vector portsVector; - for (const auto &port : ports) - portsVector.push_back(port); - swapToPorts.push_back(portsVector); - } - } - - // try all permutations - - std::map mapFromPorts, mapToPorts; - int fromPortsPermutations = numberOfPermutationsArray(swapFromPorts); - int toPortsPermutations = numberOfPermutationsArray(swapToPorts); - - for (int i = 0; i < fromPortsPermutations; i++) - { - permutateVectorToMapArray(mapFromPorts, swapFromPorts, i); - - for (int j = 0; j < toPortsPermutations; j++) { - permutateVectorToMapArray(mapToPorts, swapToPorts, j); - if (compareWithFromAndToPermutations(other, mapFromPorts, mapToPorts, swapPermutations)) - return true; - } - } - - return false; - } - - bool compare(const DiEdge &other, const std::map &mapFromPorts, const std::map>> &swapPorts, - const std::map>> &swapPermutations) const - { - // strip-down version of the last function: only try permutations for mapToPorts, mapFromPorts is already provided by the caller - - std::vector> swapToPorts; - - if (swapPorts.count(toNode.typeId) > 0) - for (const auto &ports : swapPorts.at(toNode.typeId)) { - for (const auto &bit : bits) - if (ports.count(bit.toPort)) - goto foundToPortMatch; - if (0) { - foundToPortMatch: - std::vector portsVector; - for (const auto &port : ports) - portsVector.push_back(port); - swapToPorts.push_back(portsVector); - } - } - - std::map mapToPorts; - int toPortsPermutations = numberOfPermutationsArray(swapToPorts); - - for (int j = 0; j < toPortsPermutations; j++) { - permutateVectorToMapArray(mapToPorts, swapToPorts, j); - if (compareWithToPermutations(other, mapFromPorts, mapToPorts, swapPermutations)) - return true; - } - - return false; - } - - std::string toString() const - { - std::string buffer = fromNode.toString() + " " + toNode.toString(); - for (const auto &bit : bits) - buffer += " " + bit.toString(); - if (!userAnnotation.empty()) - buffer += " " + userAnnotation; - return buffer; - } - - static void findEdgesInGraph(const Graph &graph, std::map, DiEdge> &edges) - { - edges.clear(); - for (const auto &edge : graph.edges) { - if (edge.constValue != 0) - continue; - for (const auto &fromBit : edge.portBits) - for (const auto &toBit : edge.portBits) - if (&fromBit != &toBit) { - DiEdge &de = edges[std::pair(fromBit.nodeIdx, toBit.nodeIdx)]; - de.fromNode = DiNode(graph, fromBit.nodeIdx); - de.toNode = DiNode(graph, toBit.nodeIdx); - std::string fromPortId = graph.nodes[fromBit.nodeIdx].ports[fromBit.portIdx].portId; - std::string toPortId = graph.nodes[toBit.nodeIdx].ports[toBit.portIdx].portId; - de.bits.insert(DiBit(fromPortId, fromBit.bitIdx, toPortId, toBit.bitIdx)); - } - } - } - }; - - struct DiCache - { - std::map edgeTypesMap; - std::vector edgeTypes; - std::map, bool> compareCache; - - void add(const Graph &graph, adjMatrix_t &adjMatrix, const std::string &graphId, Solver *userSolver) - { - std::map, DiEdge> edges; - DiEdge::findEdgesInGraph(graph, edges); - - adjMatrix.clear(); - adjMatrix.resize(graph.nodes.size()); - - for (auto &it : edges) { - const Graph::Node &fromNode = graph.nodes[it.first.first]; - const Graph::Node &toNode = graph.nodes[it.first.second]; - it.second.userAnnotation = userSolver->userAnnotateEdge(graphId, fromNode.nodeId, fromNode.userData, toNode.nodeId, toNode.userData); - } - - for (const auto &it : edges) { - if (edgeTypesMap.count(it.second) == 0) { - edgeTypesMap[it.second] = edgeTypes.size(); - edgeTypes.push_back(it.second); - } - adjMatrix[it.first.first][it.first.second] = edgeTypesMap[it.second]; - } - } - - bool compare(int needleEdge, int haystackEdge, const std::map>> &swapPorts, - const std::map>> &swapPermutations) - { - std::pair key(needleEdge, haystackEdge); - if (!compareCache.count(key)) - compareCache[key] = edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), swapPorts, swapPermutations); - return compareCache[key]; - } - - bool compare(int needleEdge, int haystackEdge, const std::map &mapFromPorts, const std::map>> &swapPorts, - const std::map>> &swapPermutations) const - { - return edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), mapFromPorts, swapPorts, swapPermutations); - } - - bool compare(int needleEdge, int haystackEdge, const std::map &mapFromPorts, const std::map &mapToPorts) const - { - return edgeTypes.at(needleEdge).compare(edgeTypes.at(haystackEdge), mapFromPorts, mapToPorts); - } - - void printEdgeTypes() const - { - for (int i = 0; i < int(edgeTypes.size()); i++) - my_printf("%5d: %s\n", i, edgeTypes[i].toString().c_str()); - } - }; - - // solver state variables - - Solver *userSolver; - std::map graphData; - std::map> compatibleTypes; - std::map> compatibleConstants; - std::map>> swapPorts; - std::map>> swapPermutations; - DiCache diCache; - bool verbose; - - // main solver functions - - bool matchNodePorts(const Graph &needle, int needleNodeIdx, const Graph &haystack, int haystackNodeIdx, const std::map &swaps) const - { - const Graph::Node &nn = needle.nodes[needleNodeIdx]; - const Graph::Node &hn = haystack.nodes[haystackNodeIdx]; - assert(nn.ports.size() == hn.ports.size()); - - for (int i = 0; i < int(nn.ports.size()); i++) - { - std::string hnPortId = nn.ports[i].portId; - if (swaps.count(hnPortId) > 0) - hnPortId = swaps.at(hnPortId); - - if (hn.portMap.count(hnPortId) == 0) - return false; - - const Graph::Port &np = nn.ports[i]; - const Graph::Port &hp = hn.ports[hn.portMap.at(hnPortId)]; - - if (int(hp.bits.size()) < np.minWidth || hp.bits.size() > np.bits.size()) - return false; - - for (int j = 0; j < int(hp.bits.size()); j++) - { - const Graph::Edge &ne = needle.edges[np.bits[j].edgeIdx]; - const Graph::Edge &he = haystack.edges[hp.bits[j].edgeIdx]; - - if (ne.constValue || he.constValue) { - if (ne.constValue != he.constValue) - if (compatibleConstants.count(ne.constValue) == 0 || compatibleConstants.at(ne.constValue).count(he.constValue) == 0) - return false; - continue; - } - - if (ne.isExtern || needle.allExtern) { - if (he.portBits.size() < ne.portBits.size()) - return false; - } else { - if (he.portBits.size() != ne.portBits.size()) - return false; - if (he.isExtern || haystack.allExtern) - return false; - } - } - } - - return true; - } - - bool matchNodes(const GraphData &needle, int needleNodeIdx, const GraphData &haystack, int haystackNodeIdx) const - { - // Rules for matching nodes: - // - // 1. their typeId must be identical or compatible - // (this is checked before calling this function) - // - // 2. they must have the same ports and the haystack port - // widths must match the needle port width range - // - // 3. All edges from the needle must match the haystack: - // a) if the needle edge is extern: - // - the haystack edge must have at least as many components as the needle edge - // b) if the needle edge is not extern: - // - the haystack edge must have the same number of components as the needle edge - // - the haystack edge must not be extern - - const Graph::Node &nn = needle.graph.nodes[needleNodeIdx]; - const Graph::Node &hn = haystack.graph.nodes[haystackNodeIdx]; - - assert(nn.typeId == hn.typeId || (compatibleTypes.count(nn.typeId) > 0 && compatibleTypes.at(nn.typeId).count(hn.typeId) > 0)); - - if (nn.ports.size() != hn.ports.size()) - return false; - - std::map currentCandidate; - - for (const auto &port : needle.graph.nodes[needleNodeIdx].ports) - currentCandidate[port.portId] = port.portId; - - if (swapPorts.count(needle.graph.nodes[needleNodeIdx].typeId) == 0) - { - if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) && - userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate)) - return true; - - if (swapPermutations.count(needle.graph.nodes[needleNodeIdx].typeId) > 0) - for (const auto &permutation : swapPermutations.at(needle.graph.nodes[needleNodeIdx].typeId)) { - std::map currentSubCandidate = currentCandidate; - applyPermutation(currentSubCandidate, permutation); - if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) && - userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate)) - return true; - } - } - else - { - std::vector> thisSwapPorts; - for (const auto &ports : swapPorts.at(needle.graph.nodes[needleNodeIdx].typeId)) { - std::vector portsVector; - for (const auto &port : ports) - portsVector.push_back(port); - thisSwapPorts.push_back(portsVector); - } - - int thisPermutations = numberOfPermutationsArray(thisSwapPorts); - for (int i = 0; i < thisPermutations; i++) - { - permutateVectorToMapArray(currentCandidate, thisSwapPorts, i); - - if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) && - userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate)) - return true; - - if (swapPermutations.count(needle.graph.nodes[needleNodeIdx].typeId) > 0) - for (const auto &permutation : swapPermutations.at(needle.graph.nodes[needleNodeIdx].typeId)) { - std::map currentSubCandidate = currentCandidate; - applyPermutation(currentSubCandidate, permutation); - if (matchNodePorts(needle.graph, needleNodeIdx, haystack.graph, haystackNodeIdx, currentCandidate) && - userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate)) - return true; - } - } - } - - return false; - } - - void generateEnumerationMatrix(std::vector> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, const std::map> &initialMappings) const - { - std::map> haystackNodesByTypeId; - for (int i = 0; i < int(haystack.graph.nodes.size()); i++) - haystackNodesByTypeId[haystack.graph.nodes[i].typeId].insert(i); - - enumerationMatrix.clear(); - enumerationMatrix.resize(needle.graph.nodes.size()); - for (int i = 0; i < int(needle.graph.nodes.size()); i++) - { - const Graph::Node &nn = needle.graph.nodes[i]; - - for (int j : haystackNodesByTypeId[nn.typeId]) { - const Graph::Node &hn = haystack.graph.nodes[j]; - if (initialMappings.count(nn.nodeId) > 0 && initialMappings.at(nn.nodeId).count(hn.nodeId) == 0) - continue; - if (!matchNodes(needle, i, haystack, j)) - continue; - enumerationMatrix[i].insert(j); - } - - if (compatibleTypes.count(nn.typeId) > 0) - for (const std::string &compatibleTypeId : compatibleTypes.at(nn.typeId)) - for (int j : haystackNodesByTypeId[compatibleTypeId]) { - const Graph::Node &hn = haystack.graph.nodes[j]; - if (initialMappings.count(nn.nodeId) > 0 && initialMappings.at(nn.nodeId).count(hn.nodeId) == 0) - continue; - if (!matchNodes(needle, i, haystack, j)) - continue; - enumerationMatrix[i].insert(j); - } - } - } - - bool checkEnumerationMatrix(std::vector> &enumerationMatrix, int i, int j, const GraphData &needle, const GraphData &haystack) - { - for (const auto &it_needle : needle.adjMatrix.at(i)) - { - int needleNeighbour = it_needle.first; - int needleEdgeType = it_needle.second; - - for (int haystackNeighbour : enumerationMatrix[needleNeighbour]) - if (haystack.adjMatrix.at(j).count(haystackNeighbour) > 0) { - int haystackEdgeType = haystack.adjMatrix.at(j).at(haystackNeighbour); - if (diCache.compare(needleEdgeType, haystackEdgeType, swapPorts, swapPermutations)) { - const Graph::Node &needleFromNode = needle.graph.nodes[i]; - const Graph::Node &needleToNode = needle.graph.nodes[needleNeighbour]; - const Graph::Node &haystackFromNode = haystack.graph.nodes[j]; - const Graph::Node &haystackToNode = haystack.graph.nodes[haystackNeighbour]; - if (userSolver->userCompareEdge(needle.graphId, needleFromNode.nodeId, needleFromNode.userData, needleToNode.nodeId, needleToNode.userData, - haystack.graphId, haystackFromNode.nodeId, haystackFromNode.userData, haystackToNode.nodeId, haystackToNode.userData)) - goto found_match; - } - } - - return false; - found_match:; - } - - return true; - } - - bool pruneEnumerationMatrix(std::vector> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int &nextRow, bool allowOverlap) - { - bool didSomething = true; - while (didSomething) - { - nextRow = -1; - didSomething = false; - for (int i = 0; i < int(enumerationMatrix.size()); i++) { - std::set newRow; - for (int j : enumerationMatrix[i]) { - if (!checkEnumerationMatrix(enumerationMatrix, i, j, needle, haystack)) - didSomething = true; - else if (!allowOverlap && haystack.usedNodes[j]) - didSomething = true; - else - newRow.insert(j); - } - if (newRow.size() == 0) - return false; - if (newRow.size() >= 2 && (nextRow < 0 || needle.adjMatrix.at(nextRow).size() < needle.adjMatrix.at(i).size())) - nextRow = i; - enumerationMatrix[i].swap(newRow); - } - } - return true; - } - - void printEnumerationMatrix(const std::vector> &enumerationMatrix, int maxHaystackNodeIdx = -1) const - { - if (maxHaystackNodeIdx < 0) { - for (const auto &it : enumerationMatrix) - for (int idx : it) - maxHaystackNodeIdx = std::max(maxHaystackNodeIdx, idx); - } - - my_printf(" "); - for (int j = 0; j < maxHaystackNodeIdx; j += 5) - my_printf("%-6d", j); - my_printf("\n"); - - for (int i = 0; i < int(enumerationMatrix.size()); i++) - { - my_printf("%5d:", i); - for (int j = 0; j < maxHaystackNodeIdx; j++) { - if (j % 5 == 0) - my_printf(" "); - my_printf("%c", enumerationMatrix[i].count(j) > 0 ? '*' : '.'); - } - my_printf("\n"); - } - } - - bool checkPortmapCandidate(const std::vector> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int idx, const std::map ¤tCandidate) - { - assert(enumerationMatrix[idx].size() == 1); - int idxHaystack = *enumerationMatrix[idx].begin(); - - const Graph::Node &nn = needle.graph.nodes[idx]; - const Graph::Node &hn = haystack.graph.nodes[idxHaystack]; - - if (!matchNodePorts(needle.graph, idx, haystack.graph, idxHaystack, currentCandidate) || - !userSolver->userCompareNodes(needle.graphId, nn.nodeId, nn.userData, haystack.graphId, hn.nodeId, hn.userData, currentCandidate)) - return false; - - for (const auto &it_needle : needle.adjMatrix.at(idx)) - { - int needleNeighbour = it_needle.first; - int needleEdgeType = it_needle.second; - - assert(enumerationMatrix[needleNeighbour].size() == 1); - int haystackNeighbour = *enumerationMatrix[needleNeighbour].begin(); - - assert(haystack.adjMatrix.at(idxHaystack).count(haystackNeighbour) > 0); - int haystackEdgeType = haystack.adjMatrix.at(idxHaystack).at(haystackNeighbour); - if (!diCache.compare(needleEdgeType, haystackEdgeType, currentCandidate, swapPorts, swapPermutations)) - return false; - } - - return true; - } - - void generatePortmapCandidates(std::set> &portmapCandidates, const std::vector> &enumerationMatrix, - const GraphData &needle, const GraphData &haystack, int idx) - { - std::map currentCandidate; - - for (const auto &port : needle.graph.nodes[idx].ports) - currentCandidate[port.portId] = port.portId; - - if (swapPorts.count(needle.graph.nodes[idx].typeId) == 0) - { - if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentCandidate)) - portmapCandidates.insert(currentCandidate); - - if (swapPermutations.count(needle.graph.nodes[idx].typeId) > 0) - for (const auto &permutation : swapPermutations.at(needle.graph.nodes[idx].typeId)) { - std::map currentSubCandidate = currentCandidate; - applyPermutation(currentSubCandidate, permutation); - if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentSubCandidate)) - portmapCandidates.insert(currentSubCandidate); - } - } - else - { - std::vector> thisSwapPorts; - for (const auto &ports : swapPorts.at(needle.graph.nodes[idx].typeId)) { - std::vector portsVector; - for (const auto &port : ports) - portsVector.push_back(port); - thisSwapPorts.push_back(portsVector); - } - - int thisPermutations = numberOfPermutationsArray(thisSwapPorts); - for (int i = 0; i < thisPermutations; i++) - { - permutateVectorToMapArray(currentCandidate, thisSwapPorts, i); - - if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentCandidate)) - portmapCandidates.insert(currentCandidate); - - if (swapPermutations.count(needle.graph.nodes[idx].typeId) > 0) - for (const auto &permutation : swapPermutations.at(needle.graph.nodes[idx].typeId)) { - std::map currentSubCandidate = currentCandidate; - applyPermutation(currentSubCandidate, permutation); - if (checkPortmapCandidate(enumerationMatrix, needle, haystack, idx, currentSubCandidate)) - portmapCandidates.insert(currentSubCandidate); - } - } - } - } - - bool prunePortmapCandidates(std::vector>> &portmapCandidates, std::vector> enumerationMatrix, const GraphData &needle, const GraphData &haystack) - { - bool didSomething = false; - - // strategy #1: prune impossible port mappings - - for (int i = 0; i < int(needle.graph.nodes.size()); i++) - { - assert(enumerationMatrix[i].size() == 1); - int j = *enumerationMatrix[i].begin(); - - std::set> thisCandidates; - portmapCandidates[i].swap(thisCandidates); - - for (const auto &testCandidate : thisCandidates) - { - for (const auto &it_needle : needle.adjMatrix.at(i)) - { - int needleNeighbour = it_needle.first; - int needleEdgeType = it_needle.second; - - assert(enumerationMatrix[needleNeighbour].size() == 1); - int haystackNeighbour = *enumerationMatrix[needleNeighbour].begin(); - - assert(haystack.adjMatrix.at(j).count(haystackNeighbour) > 0); - int haystackEdgeType = haystack.adjMatrix.at(j).at(haystackNeighbour); - - std::set> &candidates = - i == needleNeighbour ? thisCandidates : portmapCandidates[needleNeighbour]; - - for (const auto &otherCandidate : candidates) { - if (diCache.compare(needleEdgeType, haystackEdgeType, testCandidate, otherCandidate)) - goto found_match; - } - - didSomething = true; - goto purgeCandidate; - found_match:; - } - - portmapCandidates[i].insert(testCandidate); - purgeCandidate:; - } - - if (portmapCandidates[i].size() == 0) - return false; - } - - if (didSomething) - return true; - - // strategy #2: prune a single random port mapping - - for (int i = 0; i < int(needle.graph.nodes.size()); i++) - if (portmapCandidates[i].size() > 1) { - // remove last mapping. this keeps ports unswapped in don't-care situations - portmapCandidates[i].erase(--portmapCandidates[i].end()); - return true; - } - - return false; - } - - void ullmannRecursion(std::vector &results, std::vector> &enumerationMatrix, int iter, const GraphData &needle, GraphData &haystack, bool allowOverlap, int limitResults) - { - int i = -1; - if (!pruneEnumerationMatrix(enumerationMatrix, needle, haystack, i, allowOverlap)) - return; - - if (i < 0) - { - Solver::Result result; - result.needleGraphId = needle.graphId; - result.haystackGraphId = haystack.graphId; - - std::vector>> portmapCandidates; - portmapCandidates.resize(enumerationMatrix.size()); - - for (int j = 0; j < int(enumerationMatrix.size()); j++) { - Solver::ResultNodeMapping mapping; - mapping.needleNodeId = needle.graph.nodes[j].nodeId; - mapping.needleUserData = needle.graph.nodes[j].userData; - mapping.haystackNodeId = haystack.graph.nodes[*enumerationMatrix[j].begin()].nodeId; - mapping.haystackUserData = haystack.graph.nodes[*enumerationMatrix[j].begin()].userData; - generatePortmapCandidates(portmapCandidates[j], enumerationMatrix, needle, haystack, j); - result.mappings[needle.graph.nodes[j].nodeId] = mapping; - } - - while (prunePortmapCandidates(portmapCandidates, enumerationMatrix, needle, haystack)) { } - - if (verbose) { - my_printf("\nPortmapper results:\n"); - for (int j = 0; j < int(enumerationMatrix.size()); j++) { - my_printf("%5d: %s\n", j, needle.graph.nodes[j].nodeId.c_str()); - int variantCounter = 0; - for (auto &i2 : portmapCandidates.at(j)) { - my_printf("%*s variant %2d:", 6, "", variantCounter++); - int mapCounter = 0; - for (auto &i3 : i2) - my_printf("%s %s -> %s", mapCounter++ ? "," : "", i3.first.c_str(), i3.second.c_str()); - my_printf("\n"); - } - } - } - - for (int j = 0; j < int(enumerationMatrix.size()); j++) { - if (portmapCandidates[j].size() == 0) { - if (verbose) { - my_printf("\nSolution (rejected by portmapper):\n"); - printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size()); - } - return; - } - result.mappings[needle.graph.nodes[j].nodeId].portMapping = *portmapCandidates[j].begin(); - } - - if (!userSolver->userCheckSolution(result)) { - if (verbose) { - my_printf("\nSolution (rejected by userCheckSolution):\n"); - printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size()); - } - return; - } - - for (int j = 0; j < int(enumerationMatrix.size()); j++) - if (!haystack.graph.nodes[*enumerationMatrix[j].begin()].shared) - haystack.usedNodes[*enumerationMatrix[j].begin()] = true; - - if (verbose) { - my_printf("\nSolution:\n"); - printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size()); - } - - results.push_back(result); - return; - } - - if (verbose) { - my_printf("\n"); - my_printf("Enumeration Matrix at recursion level %d (%d):\n", iter, i); - printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size()); - } - - std::set activeRow; - enumerationMatrix[i].swap(activeRow); - - for (int j : activeRow) - { - // found enough? - if (limitResults >= 0 && int(results.size()) >= limitResults) - return; - - // already used by other solution -> try next - if (!allowOverlap && haystack.usedNodes[j]) - continue; - - // create enumeration matrix for child in recursion tree - std::vector> nextEnumerationMatrix = enumerationMatrix; - for (int k = 0; k < int(nextEnumerationMatrix.size()); k++) - nextEnumerationMatrix[k].erase(j); - nextEnumerationMatrix[i].insert(j); - - // recursion - ullmannRecursion(results, nextEnumerationMatrix, iter+1, needle, haystack, allowOverlap, limitResults); - - // we just have found something -> unroll to top recursion level - if (!allowOverlap && haystack.usedNodes[j] && iter > 0) - return; - } - } - - // additional data structes and functions for mining - - struct NodeSet { - std::string graphId; - std::set nodes; - NodeSet(std::string graphId, int node1, int node2) { - this->graphId = graphId; - nodes.insert(node1); - nodes.insert(node2); - } - NodeSet(std::string graphId, const std::vector &nodes) { - this->graphId = graphId; - for (int node : nodes) - this->nodes.insert(node); - } - void extend(const NodeSet &other) { - assert(this->graphId == other.graphId); - for (int node : other.nodes) - nodes.insert(node); - } - int extendCandidate(const NodeSet &other) const { - if (graphId != other.graphId) - return 0; - int newNodes = 0; - bool intersect = false; - for (int node : other.nodes) - if (nodes.count(node) > 0) - intersect = true; - else - newNodes++; - return intersect ? newNodes : 0; - } - bool operator <(const NodeSet &other) const { - if (graphId != other.graphId) - return graphId < other.graphId; - return nodes < other.nodes; - } - std::string to_string() const { - std::string str = graphId + "("; - bool first = true; - for (int node : nodes) { - str += my_stringf("%s%d", first ? "" : " ", node); - first = false; - } - return str + ")"; - } - }; - - void solveForMining(std::vector &results, const GraphData &needle) - { - bool backupVerbose = verbose; - verbose = false; - - for (auto &it : graphData) - { - GraphData &haystack = it.second; - - std::vector> enumerationMatrix; - std::map> initialMappings; - generateEnumerationMatrix(enumerationMatrix, needle, haystack, initialMappings); - - haystack.usedNodes.resize(haystack.graph.nodes.size()); - ullmannRecursion(results, enumerationMatrix, 0, needle, haystack, true, -1); - } - - verbose = backupVerbose; - } - - int testForMining(std::vector &results, std::set &usedSets, std::set &nextPool, NodeSet &testSet, - const std::string &graphId, const Graph &graph, int minNodes, int minMatches, int limitMatchesPerGraph) - { - // my_printf("test: %s\n", testSet.to_string().c_str()); - - GraphData needle; - std::vector needle_nodes; - for (int nodeIdx : testSet.nodes) - needle_nodes.push_back(graph.nodes[nodeIdx].nodeId); - needle.graph = Graph(graph, needle_nodes); - needle.graph.markAllExtern(); - diCache.add(needle.graph, needle.adjMatrix, graphId, userSolver); - - std::vector ullmannResults; - solveForMining(ullmannResults, needle); - - int matches = 0; - std::map matchesPerGraph; - std::set thisNodeSetSet; - - for (auto &it : ullmannResults) - { - std::vector resultNodes; - for (auto &i2 : it.mappings) - resultNodes.push_back(graphData[it.haystackGraphId].graph.nodeMap[i2.second.haystackNodeId]); - NodeSet resultSet(it.haystackGraphId, resultNodes); - - // my_printf("match: %s%s\n", resultSet.to_string().c_str(), usedSets.count(resultSet) > 0 ? " (dup)" : ""); - -#if 0 - if (usedSets.count(resultSet) > 0) { - // Because of shorted pins isomorphisim is not always bidirectional! - // - // This means that the following assert is not true in all cases and subgraph A might - // show up in the matches for subgraph B but not vice versa... This also means that the - // order in which subgraphs are processed has an impact on the results set. - // - assert(thisNodeSetSet.count(resultSet) > 0); - continue; - } -#else - if (thisNodeSetSet.count(resultSet) > 0) - continue; -#endif - - usedSets.insert(resultSet); - thisNodeSetSet.insert(resultSet); - - matchesPerGraph[it.haystackGraphId]++; - if (limitMatchesPerGraph < 0 || matchesPerGraph[it.haystackGraphId] < limitMatchesPerGraph) - matches++; - } - - if (matches < minMatches) - return matches; - - if (minNodes <= int(testSet.nodes.size())) - { - Solver::MineResult result; - result.graphId = graphId; - result.totalMatchesAfterLimits = matches; - result.matchesPerGraph = matchesPerGraph; - for (int nodeIdx : testSet.nodes) { - Solver::MineResultNode resultNode; - resultNode.nodeId = graph.nodes[nodeIdx].nodeId; - resultNode.userData = graph.nodes[nodeIdx].userData; - result.nodes.push_back(resultNode); - } - results.push_back(result); - } - - nextPool.insert(thisNodeSetSet.begin(), thisNodeSetSet.end()); - return matches; - } - - void findNodePairs(std::vector &results, std::set &nodePairs, int minNodes, int minMatches, int limitMatchesPerGraph) - { - int groupCounter = 0; - std::set usedPairs; - nodePairs.clear(); - - if (verbose) - my_printf("\nMining for frequent node pairs:\n"); - - for (auto &graph_it : graphData) - for (int node1 = 0; node1 < int(graph_it.second.graph.nodes.size()); node1++) - for (auto &adj_it : graph_it.second.adjMatrix.at(node1)) - { - const std::string &graphId = graph_it.first; - const auto &graph = graph_it.second.graph; - int node2 = adj_it.first; - - if (node1 == node2) - continue; - - NodeSet pair(graphId, node1, node2); - - if (usedPairs.count(pair) > 0) - continue; - - int matches = testForMining(results, usedPairs, nodePairs, pair, graphId, graph, minNodes, minMatches, limitMatchesPerGraph); - - if (verbose) - my_printf("Pair %s[%s,%s] -> %d%s\n", graphId.c_str(), graph.nodes[node1].nodeId.c_str(), - graph.nodes[node2].nodeId.c_str(), matches, matches < minMatches ? " *purge*" : ""); - - if (minMatches <= matches) - groupCounter++; - } - - if (verbose) - my_printf("Found a total of %d subgraphs in %d groups.\n", int(nodePairs.size()), groupCounter); - } - - void findNextPool(std::vector &results, std::set &pool, - int oldSetSize, int increment, int minNodes, int minMatches, int limitMatchesPerGraph) - { - int groupCounter = 0; - std::map> poolPerGraph; - std::set nextPool; - - for (auto &it : pool) - poolPerGraph[it.graphId].push_back(&it); - - if (verbose) - my_printf("\nMining for frequent subcircuits of size %d using increment %d:\n", oldSetSize+increment, increment); - - int count = 0; - for (auto &it : poolPerGraph) - { - std::map> node2sets; - std::set usedSets; - - for (int idx = 0; idx < int(it.second.size()); idx++) { - for (int node : it.second[idx]->nodes) - node2sets[node].insert(idx); - } - - for (int idx1 = 0; idx1 < int(it.second.size()); idx1++, count++) - { - std::set idx2set; - - for (int node : it.second[idx1]->nodes) - for (int idx2 : node2sets[node]) - if (idx2 > idx1) - idx2set.insert(idx2); - - for (int idx2 : idx2set) - { - if (it.second[idx1]->extendCandidate(*it.second[idx2]) != increment) - continue; - - NodeSet mergedSet = *it.second[idx1]; - mergedSet.extend(*it.second[idx2]); - - if (usedSets.count(mergedSet) > 0) - continue; - - const std::string &graphId = it.first; - const auto &graph = graphData[it.first].graph; - - if (verbose) { - my_printf("<%d%%/%d> Found %s[", int(100*count/pool.size()), oldSetSize+increment, graphId.c_str()); - bool first = true; - for (int nodeIdx : mergedSet.nodes) { - my_printf("%s%s", first ? "" : ",", graph.nodes[nodeIdx].nodeId.c_str()); - first = false; - } - my_printf("] ->"); - } - - int matches = testForMining(results, usedSets, nextPool, mergedSet, graphId, graph, minNodes, minMatches, limitMatchesPerGraph); - - if (verbose) - my_printf(" %d%s\n", matches, matches < minMatches ? " *purge*" : ""); - - if (minMatches <= matches) - groupCounter++; - } - } - } - - pool.swap(nextPool); - - if (verbose) - my_printf("Found a total of %d subgraphs in %d groups.\n", int(pool.size()), groupCounter); - } - - // interface to the public solver class - -protected: - SolverWorker(Solver *userSolver) : userSolver(userSolver), verbose(false) - { - } - - void setVerbose() - { - verbose = true; - } - - void addGraph(std::string graphId, const Graph &graph) - { - assert(graphData.count(graphId) == 0); - - GraphData &gd = graphData[graphId]; - gd.graphId = graphId; - gd.graph = graph; - diCache.add(gd.graph, gd.adjMatrix, graphId, userSolver); - } - - void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId) - { - compatibleTypes[needleTypeId].insert(haystackTypeId); - } - - void addCompatibleConstants(int needleConstant, int haystackConstant) - { - compatibleConstants[needleConstant].insert(haystackConstant); - } - - void addSwappablePorts(std::string needleTypeId, const std::set &ports) - { - swapPorts[needleTypeId].insert(ports); - diCache.compareCache.clear(); - } - - void addSwappablePortsPermutation(std::string needleTypeId, const std::map &portMapping) - { - swapPermutations[needleTypeId].insert(portMapping); - diCache.compareCache.clear(); - } - - void solve(std::vector &results, std::string needleGraphId, std::string haystackGraphId, - const std::map> &initialMappings, bool allowOverlap, int maxSolutions) - { - assert(graphData.count(needleGraphId) > 0); - assert(graphData.count(haystackGraphId) > 0); - - const GraphData &needle = graphData[needleGraphId]; - GraphData &haystack = graphData[haystackGraphId]; - - std::vector> enumerationMatrix; - generateEnumerationMatrix(enumerationMatrix, needle, haystack, initialMappings); - - if (verbose) - { - my_printf("\n"); - my_printf("Needle nodes:\n"); - for (int i = 0; i < int(needle.graph.nodes.size()); i++) - my_printf("%5d: %s (%s)\n", i, needle.graph.nodes[i].nodeId.c_str(), needle.graph.nodes[i].typeId.c_str()); - - my_printf("\n"); - my_printf("Haystack nodes:\n"); - for (int i = 0; i < int(haystack.graph.nodes.size()); i++) - my_printf("%5d: %s (%s)\n", i, haystack.graph.nodes[i].nodeId.c_str(), haystack.graph.nodes[i].typeId.c_str()); - - my_printf("\n"); - my_printf("Needle Adjecency Matrix:\n"); - printAdjMatrix(needle.adjMatrix); - - my_printf("\n"); - my_printf("Haystack Adjecency Matrix:\n"); - printAdjMatrix(haystack.adjMatrix); - - my_printf("\n"); - my_printf("Edge Types:\n"); - diCache.printEdgeTypes(); - - my_printf("\n"); - my_printf("Enumeration Matrix (haystack nodes at column indices):\n"); - printEnumerationMatrix(enumerationMatrix, haystack.graph.nodes.size()); - } - - haystack.usedNodes.resize(haystack.graph.nodes.size()); - ullmannRecursion(results, enumerationMatrix, 0, needle, haystack, allowOverlap, maxSolutions > 0 ? results.size() + maxSolutions : -1); - } - - void mine(std::vector &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph) - { - int nodeSetSize = 2; - std::set pool; - findNodePairs(results, pool, minNodes, minMatches, limitMatchesPerGraph); - - while ((maxNodes < 0 || nodeSetSize < maxNodes) && pool.size() > 0) - { - int increment = nodeSetSize - 1; - if (nodeSetSize + increment >= minNodes) - increment = minNodes - nodeSetSize; - if (nodeSetSize >= minNodes) - increment = 1; - - findNextPool(results, pool, nodeSetSize, increment, minNodes, minMatches, limitMatchesPerGraph); - nodeSetSize += increment; - } - } - - void clearOverlapHistory() - { - for (auto &it : graphData) - it.second.usedNodes.clear(); - } - - void clearConfig() - { - compatibleTypes.clear(); - compatibleConstants.clear(); - swapPorts.clear(); - swapPermutations.clear(); - diCache.compareCache.clear(); - } - - friend class Solver; -}; - -bool Solver::userCompareNodes(const std::string&, const std::string&, void*, const std::string&, const std::string&, void*, const std::map&) -{ - return true; -} - -std::string Solver::userAnnotateEdge(const std::string&, const std::string&, void*, const std::string&, void*) -{ - return std::string(); -} - -bool Solver::userCompareEdge(const std::string&, const std::string&, void*, const std::string&, void*, const std::string&, const std::string&, void*, const std::string&, void*) -{ - return true; -} - -bool Solver::userCheckSolution(const Result&) -{ - return true; -} - -SubCircuit::Solver::Solver() -{ - worker = new SolverWorker(this); -} - -SubCircuit::Solver::~Solver() -{ - delete worker; -} - -void SubCircuit::Solver::setVerbose() -{ - worker->setVerbose(); -} - -void SubCircuit::Solver::addGraph(std::string graphId, const Graph &graph) -{ - worker->addGraph(graphId, graph); -} - -void SubCircuit::Solver::addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId) -{ - worker->addCompatibleTypes(needleTypeId, haystackTypeId); -} - -void SubCircuit::Solver::addCompatibleConstants(int needleConstant, int haystackConstant) -{ - worker->addCompatibleConstants(needleConstant, haystackConstant); -} - -void SubCircuit::Solver::addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3, std::string portId4) -{ - std::set ports; - ports.insert(portId1); - ports.insert(portId2); - ports.insert(portId3); - ports.insert(portId4); - ports.erase(std::string()); - addSwappablePorts(needleTypeId, ports); -} - -void SubCircuit::Solver::addSwappablePorts(std::string needleTypeId, std::set ports) -{ - worker->addSwappablePorts(needleTypeId, ports); -} - -void SubCircuit::Solver::addSwappablePortsPermutation(std::string needleTypeId, std::map portMapping) -{ - worker->addSwappablePortsPermutation(needleTypeId, portMapping); -} - -void SubCircuit::Solver::solve(std::vector &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap, int maxSolutions) -{ - std::map> emptyInitialMapping; - worker->solve(results, needleGraphId, haystackGraphId, emptyInitialMapping, allowOverlap, maxSolutions); -} - -void SubCircuit::Solver::solve(std::vector &results, std::string needleGraphId, std::string haystackGraphId, - const std::map> &initialMappings, bool allowOverlap, int maxSolutions) -{ - worker->solve(results, needleGraphId, haystackGraphId, initialMappings, allowOverlap, maxSolutions); -} - -void SubCircuit::Solver::mine(std::vector &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph) -{ - worker->mine(results, minNodes, maxNodes, minMatches, limitMatchesPerGraph); -} - -void SubCircuit::Solver::clearOverlapHistory() -{ - worker->clearOverlapHistory(); -} - -void SubCircuit::Solver::clearConfig() -{ - worker->clearConfig(); -} - diff --git a/yosys/libs/subcircuit/subcircuit.h b/yosys/libs/subcircuit/subcircuit.h deleted file mode 100644 index 8368efab1..000000000 --- a/yosys/libs/subcircuit/subcircuit.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * SubCircuit -- An implementation of the Ullmann Subgraph Isomorphism - * algorithm for coarse grain logic networks - * - * Copyright (C) 2013 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef SUBCIRCUIT_H -#define SUBCIRCUIT_H - -#include -#include -#include -#include - -namespace SubCircuit -{ - class SolverWorker; - - class Graph - { - protected: - struct BitRef { - int nodeIdx, portIdx, bitIdx; - BitRef(int nodeIdx = -1, int portIdx = -1, int bitIdx = -1) : nodeIdx(nodeIdx), portIdx(portIdx), bitIdx(bitIdx) { }; - bool operator < (const BitRef &other) const; - }; - - struct Edge { - std::set portBits; - int constValue; - bool isExtern; - Edge() : constValue(0), isExtern(false) { }; - }; - - struct PortBit { - int edgeIdx; - PortBit() : edgeIdx(-1) { }; - }; - - struct Port { - std::string portId; - int minWidth; - std::vector bits; - Port() : minWidth(-1) { }; - }; - - struct Node { - std::string nodeId, typeId; - std::map portMap; - std::vector ports; - void *userData; - bool shared; - Node() : userData(NULL), shared(false) { }; - }; - - bool allExtern; - std::map nodeMap; - std::vector nodes; - std::vector edges; - - public: - Graph() : allExtern(false) { }; - Graph(const Graph &other, const std::vector &otherNodes); - - void createNode(std::string nodeId, std::string typeId, void *userData = NULL, bool shared = false); - void createPort(std::string nodeId, std::string portId, int width = 1, int minWidth = -1); - void createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width = 1); - void createConnection(std::string fromNodeId, std::string fromPortId, std::string toNodeId, std::string toPortId); - void createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue); - void createConstant(std::string toNodeId, std::string toPortId, int constValue); - void markExtern(std::string nodeId, std::string portId, int bit = -1); - void markAllExtern(); - void print(); - - friend class SolverWorker; - }; - - class Solver - { - public: - struct ResultNodeMapping { - std::string needleNodeId, haystackNodeId; - void *needleUserData, *haystackUserData; - std::map portMapping; - }; - struct Result { - std::string needleGraphId, haystackGraphId; - std::map mappings; - }; - - struct MineResultNode { - std::string nodeId; - void *userData; - }; - struct MineResult { - std::string graphId; - int totalMatchesAfterLimits; - std::map matchesPerGraph; - std::vector nodes; - }; - - private: - SolverWorker *worker; - - protected: - virtual bool userCompareNodes(const std::string &needleGraphId, const std::string &needleNodeId, void *needleUserData, - const std::string &haystackGraphId, const std::string &haystackNodeId, void *haystackUserData, const std::map &portMapping); - - virtual std::string userAnnotateEdge(const std::string &graphId, const std::string &fromNodeId, void *fromUserData, const std::string &toNodeId, void *toUserData); - - virtual bool userCompareEdge(const std::string &needleGraphId, const std::string &needleFromNodeId, void *needleFromUserData, const std::string &needleToNodeId, void *needleToUserData, - const std::string &haystackGraphId, const std::string &haystackFromNodeId, void *haystackFromUserData, const std::string &haystackToNodeId, void *haystackToUserData); - - virtual bool userCheckSolution(const Result &result); - - friend class SolverWorker; - - public: - Solver(); - virtual ~Solver(); - - void setVerbose(); - void addGraph(std::string graphId, const Graph &graph); - void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId); - void addCompatibleConstants(int needleConstant, int haystackConstant); - void addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3 = std::string(), std::string portId4 = std::string()); - void addSwappablePorts(std::string needleTypeId, std::set ports); - void addSwappablePortsPermutation(std::string needleTypeId, std::map portMapping); - - void solve(std::vector &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap = true, int maxSolutions = -1); - void solve(std::vector &results, std::string needleGraphId, std::string haystackGraphId, - const std::map> &initialMapping, bool allowOverlap = true, int maxSolutions = -1); - - void mine(std::vector &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph = -1); - - void clearOverlapHistory(); - void clearConfig(); - }; -} - -#endif /* SUBCIRCUIT_H */ diff --git a/yosys/libs/subcircuit/test_large.spl b/yosys/libs/subcircuit/test_large.spl deleted file mode 100644 index e33e26985..000000000 --- a/yosys/libs/subcircuit/test_large.spl +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env splrun - -var idx = 0; -var count_nand = 0; -var count_nor = 0; - -function makeNAND(net, id) -{ - count_nand++; - - net["${id}_VDD"] = "${id}_pa S"; - net["${id}_VSS"] = "${id}_nb S"; - - net["${id}_A"] = "${id}_pa G"; - net["${id}_B"] = "${id}_pb G"; - net["${id}_Y"] = "${id}_pb D"; - - return <:> - : node ${id}_pa pmos S 1 D 1 G 1 - : node ${id}_pb pmos S 1 D 1 G 1 - : node ${id}_na nmos S 1 D 1 G 1 - : node ${id}_nb nmos S 1 D 1 G 1 - : connect ${id}_pa S ${id}_pb S - : connect ${id}_pa D ${id}_pb D - : connect ${id}_pa D ${id}_na D - : connect ${id}_na S ${id}_nb D - : connect ${id}_pa G ${id}_na G - : connect ${id}_pb G ${id}_nb G - ; -} - -function makeNOR(net, id) -{ - count_nor++; - - net["${id}_VDD"] = "${id}_pa S"; - net["${id}_VSS"] = "${id}_nb S"; - - net["${id}_A"] = "${id}_pa G"; - net["${id}_B"] = "${id}_pb G"; - net["${id}_Y"] = "${id}_pb D"; - - return <:> - : node ${id}_pa pmos S 1 D 1 G 1 - : node ${id}_pb pmos S 1 D 1 G 1 - : node ${id}_na nmos S 1 D 1 G 1 - : node ${id}_nb nmos S 1 D 1 G 1 - : connect ${id}_pa D ${id}_pb S - : connect ${id}_pb D ${id}_na D - : connect ${id}_pb D ${id}_nb D - : connect ${id}_na S ${id}_nb S - : connect ${id}_pa G ${id}_na G - : connect ${id}_pb G ${id}_nb G - ; -} - -function makeGraph(seed, gates, primaryInputs, primaryOutputs) -{ - srand(seed); - - var code = ""; - var net, vdd, vss, outputs; - var unusedOutpus; - for (var i = 0; i < gates; i++) - { - var id = fmt("G%d", idx++); - if (rand(2) == 0) - code ~= makeNAND(net, id); - else - code ~= makeNOR(net, id); - - if (i == 0) { - vdd = net["${id}_VDD"]; - vss = net["${id}_VSS"]; - } else { - code ~= <:> - : connect $vdd ${net["${id}_VDD"]} - : connect $vss ${net["${id}_VSS"]} - ; - } - - var inIdx1 = rand((elementsof outputs) + 1); - if (inIdx1 < elementsof outputs) { - code ~= " connect ${outputs[inIdx1]} ${net["${id}_A"]}\n"; - delete unusedOutpus[outputs[inIdx1]]; - } else - push primaryInputs, net["${id}_A"]; - - var inIdx2 = rand((elementsof outputs) + 1); - if (inIdx2 < elementsof outputs) { - code ~= " connect ${outputs[inIdx2]} ${net["${id}_B"]}\n"; - delete unusedOutpus[outputs[inIdx2]]; - } else - push primaryInputs, net["${id}_B"]; - - unusedOutpus[net["${id}_Y"]] = 1; - push outputs, net["${id}_Y"]; - } - - foreach netDecl (unusedOutpus) - push primaryOutputs, netDecl; - - return code; -} - -function makeConnections(fromNets, toNets) -{ - var code = ""; - foreach[] toNet (toNets) { - var fromNet = fromNets[rand(elementsof fromNets)]; - code != " connect $fromNet $toNet\n"; - } - return code; -} - -var numNodes; - -write(<:> - : graph nand - - ${makeNAND(net, "nand")} - : extern ${net["nand_VDD"]} - : extern ${net["nand_VSS"]} - : extern ${net["nand_A"]} - : extern ${net["nand_B"]} - : extern ${net["nand_Y"]} - : endgraph - : - : graph nor - ${makeNOR(net, "nor")} - : extern ${net["nor_VDD"]} - : extern ${net["nor_VSS"]} - : extern ${net["nor_A"]} - : extern ${net["nor_B"]} - : extern ${net["nor_Y"]} - : endgraph - : - : graph needle_1 - - ${makeGraph(1, 100, ports, ports)} - - - : extern $net - - : endgraph - : - : graph needle_2 - - ${makeGraph(2, 200, ports, ports)} - - - : extern $net - - : endgraph - : - : graph needle_3 - - ${makeGraph(3, 300, ports, ports)} - - - : extern $net - - : endgraph - : - : graph haystack - - - - - ${makeGraph(1, 100, inPorts1, outPorts1)} - - - ${makeGraph(2, 200, inPorts2, outPorts2)} - - - ${makeGraph(3, 300, inPorts3, outPorts3)} - - - ${makeGraph(2, 200, inPorts4, outPorts4)} - - - ${makeGraph(1, 100, inPorts5, outPorts5)} - - - ${makeConnections(outPorts1, inPorts2)} - ${makeConnections(outPorts2, inPorts3)} - ${makeConnections(outPorts3, inPorts4)} - ${makeConnections(outPorts4, inPorts5)} - - : endgraph - : - : solve nand haystack false - : expect $count_nand - : clearoverlap - : - : solve nor haystack false - : expect $count_nor - : clearoverlap - : - : solve needle_1 haystack false - : expect 2 - : - : solve needle_2 haystack false - : expect 2 - : - : solve needle_3 haystack false - : expect 1 -); - -numNodes["haystack"] -= numNodes["needle_3"]; -numNodes["needle_3"] -= numNodes["needle_2"]; -numNodes["needle_2"] -= numNodes["needle_1"]; - -write(<:> - : - : # Needle_1: ${numNodes["needle_1"]} transistors - : # Needle_2: ${numNodes["needle_2"]} transistors - : # Needle_3: ${numNodes["needle_3"]} transistors - : # Haystack: ${numNodes["haystack"]} transistors -); - diff --git a/yosys/libs/subcircuit/test_macc22.txt b/yosys/libs/subcircuit/test_macc22.txt deleted file mode 100644 index 71938c1c1..000000000 --- a/yosys/libs/subcircuit/test_macc22.txt +++ /dev/null @@ -1,48 +0,0 @@ - -# verbose - -graph macc22 - node mul_1 mul A 32 B 32 Y 32 - node mul_2 mul A 32 B 32 Y 32 - node add_1 add A 32 B 32 Y 32 - connect mul_1 Y add_1 A - connect mul_2 Y add_1 B - extern mul_1 A B - extern mul_2 A B - extern add_1 Y -endgraph - -graph macc4x2 - node mul_1 mul A 32 B 32 Y 32 - node mul_2 mul A 32 B 32 Y 32 - node mul_3 mul A 32 B 32 Y 32 - node mul_4 mul A 32 B 32 Y 32 - node add_1 add A 32 B 32 Y 32 - node add_2 add A 32 B 32 Y 32 - node add_3 add A 32 B 32 Y 32 - connect mul_1 Y add_1 A - connect mul_2 Y add_1 B - connect mul_3 Y add_2 A - connect mul_4 Y add_2 B - connect add_1 Y add_3 A - connect add_2 Y add_3 B - extern mul_1 A B - extern mul_2 A B - extern mul_3 A B - extern mul_4 A B - extern add_3 Y -endgraph - -solve macc22 macc4x2 -expect 2 - -swapgroup mul A B - -solve macc22 macc4x2 -expect 2 - -swapperm add A B : B A - -solve macc22 macc4x2 -expect 4 - diff --git a/yosys/libs/subcircuit/test_mine.txt b/yosys/libs/subcircuit/test_mine.txt deleted file mode 100644 index 7ba272ea1..000000000 --- a/yosys/libs/subcircuit/test_mine.txt +++ /dev/null @@ -1,41 +0,0 @@ - -# verbose - -graph macc22 - node mul_1 mul A 32 B 32 Y 32 - node mul_2 mul A 32 B 32 Y 32 - node add_1 add A 32 B 32 Y 32 - connect mul_1 Y add_1 A - connect mul_2 Y add_1 B - extern mul_1 A B - extern mul_2 A B - extern add_1 Y -endgraph - -graph macc4x2 - node mul_1 mul A 32 B 32 Y 32 - node mul_2 mul A 32 B 32 Y 32 - node mul_3 mul A 32 B 32 Y 32 - node mul_4 mul A 32 B 32 Y 32 - node add_1 add A 32 B 32 Y 32 - node add_2 add A 32 B 32 Y 32 - node add_3 add A 32 B 32 Y 32 - connect mul_1 Y add_1 A - connect mul_2 Y add_1 B - connect mul_3 Y add_2 A - connect mul_4 Y add_2 B - connect add_1 Y add_3 A - connect add_2 Y add_3 B - extern mul_1 A B - extern mul_2 A B - extern mul_3 A B - extern mul_4 A B - extern add_3 Y -endgraph - -swapgroup mul A B -swapgroup add A B - -mine 2 10 2 -expect 6 - diff --git a/yosys/libs/subcircuit/test_perm.pl b/yosys/libs/subcircuit/test_perm.pl deleted file mode 100644 index b4e05e35e..000000000 --- a/yosys/libs/subcircuit/test_perm.pl +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/perl -w - -use strict; - -# let "macc" implement a function like Y = (A*B) + (C*D) -# -# the following permutations of the input pins exist: -# -# g01 | A B C D | match -# g02 | A B D C | match -# g03 | A C B D | not -# g04 | A C D B | not -# g05 | A D B C | not -# g06 | A D C B | not -# g07 | B A C D | match -# g08 | B A D C | match -# g09 | B C A D | not -# g10 | B C D A | not -# g11 | B D A C | not -# g12 | B D C A | not -# g13 | C A B D | not -# g14 | C A D B | not -# g15 | C B A D | not -# g16 | C B D A | not -# g17 | C D A B | match -# g18 | C D B A | match -# g19 | D A B C | not -# g20 | D A C B | not -# g21 | D B A C | not -# g22 | D B C A | not -# g23 | D C A B | match -# g24 | D C B A | match - -my @matches = qw/g01 g02 g07 g08 g17 g18 g23 g24/; -my @non_matches = qw/g03 g04 g05 g06 g09 g10 g11 g12 g13 g14 g15 g16 g19 g20 g21 g22/; - -print "\n"; - -for my $i (0..3) { -for my $j (0..2) { -for my $k (0..1) { - my @t = qw/A B C D/; - print "# "; - print splice(@t,$i,1),splice(@t,$j,1),splice(@t,$k,1),$t[0]; - print "\n"; -}}} - -print "\n"; - -my $iter = 1; -for my $i (0..3) { -for my $j (0..2) { -for my $k (0..1) { - my @t = qw/A B C D/; - printf "graph g%02d\n", $iter++; - printf " node input input A 32 1 B 32 1 C 32 1 D 32 1\n"; - printf " node macc macc A 32 1 B 32 1 C 32 1 D 32 1\n"; - printf " connect input A macc %s\n", splice(@t,$i,1); - printf " connect input B macc %s\n", splice(@t,$j,1); - printf " connect input C macc %s\n", splice(@t,$k,1); - printf " connect input D macc %s\n", splice(@t,0,1); - printf "endgraph\n"; - printf "\n"; -}}} - -$iter = 1; -printf "graph gXL\n"; -for my $i (0..3) { -for my $j (0..2) { -for my $k (0..1) { - my $id = sprintf "_%02d", $iter++; - my @t = qw/A B C D/; - printf " node input$id input A 16 B 16 C 16 D 16\n"; - printf " node macc$id macc A 16 B 16 C 16 D 16\n"; - printf " connect input$id A macc$id %s\n", splice(@t,$i,1); - printf " connect input$id B macc$id %s\n", splice(@t,$j,1); - printf " connect input$id C macc$id %s\n", splice(@t,$k,1); - printf " connect input$id D macc$id %s\n", splice(@t,0,1); -}}} -printf "endgraph\n"; -printf "\n"; - - -printf "swapgroup macc A B\n"; -printf "swapgroup macc C D\n"; -printf "swapperm macc A B C D : C D A B\n"; - -for my $i (@matches) { -for my $j (@non_matches) { - printf "solve %s %s\n", $i, $j; -}} -printf "expect 0\n\n"; - -for my $i (@matches) { -for my $j (@matches) { - printf "solve %s %s\n", $i, $j; -}} -printf "expect %d\n\n", @matches*@matches; - -printf "solve g01 gXL false\n"; -printf "expect 8\n"; - -printf "solve g03 gXL false\n"; -printf "expect 8\n"; - -printf "solve g04 gXL false\n"; -printf "expect 8\n"; - diff --git a/yosys/libs/subcircuit/test_shorts.spl b/yosys/libs/subcircuit/test_shorts.spl deleted file mode 100644 index f1cb4cfd5..000000000 --- a/yosys/libs/subcircuit/test_shorts.spl +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env splrun -// -// Test procedure for matching Gates with shorted inputs, as suggested in -// "SubCircuit Extraction with SubGraph Isomorphism. Zong Ling, Ph. D. IBM -// Almaden Research Center -- EDA Shape Processing zling@us.ibm.com.": -// -// Four NAND gates and a NOR gate. One NAND gate (G1) has no shorted inputs, -// one (G2) has an input shorted to VSS, one (G3) has an input shorted to VDD, -// and one (G4) has both inputs shorted together. Th last gate (G5) is a NOR -// gate. - -var net; - -function makeNAND(id) -{ - net["${id}_VDD"] = "${id}_pa S"; - net["${id}_VSS"] = "${id}_nb S"; - - net["${id}_A"] = "${id}_pa G"; - net["${id}_B"] = "${id}_pb G"; - net["${id}_Y"] = "${id}_pb D"; - - return <:> - : node ${id}_pa pmos S 1 D 1 G 1 - : node ${id}_pb pmos S 1 D 1 G 1 - : node ${id}_na nmos S 1 D 1 G 1 - : node ${id}_nb nmos S 1 D 1 G 1 - : connect ${id}_pa S ${id}_pb S - : connect ${id}_pa D ${id}_pb D - : connect ${id}_pa D ${id}_na D - : connect ${id}_na S ${id}_nb D - : connect ${id}_pa G ${id}_na G - : connect ${id}_pb G ${id}_nb G - ; -} - -function makeNOR(id) -{ - net["${id}_VDD"] = "${id}_pa S"; - net["${id}_VSS"] = "${id}_nb S"; - - net["${id}_A"] = "${id}_pa G"; - net["${id}_B"] = "${id}_pb G"; - net["${id}_Y"] = "${id}_pb D"; - - return <:> - : node ${id}_pa pmos S 1 D 1 G 1 - : node ${id}_pb pmos S 1 D 1 G 1 - : node ${id}_na nmos S 1 D 1 G 1 - : node ${id}_nb nmos S 1 D 1 G 1 - : connect ${id}_pa D ${id}_pb S - : connect ${id}_pb D ${id}_na D - : connect ${id}_pb D ${id}_nb D - : connect ${id}_na S ${id}_nb S - : connect ${id}_pa G ${id}_na G - : connect ${id}_pb G ${id}_nb G - ; -} - -write(<:> - : graph nand - : ${ makeNAND("G0") } - : extern ${net["G0_VDD"]} - : extern ${net["G0_VSS"]} - : extern ${net["G0_A"]} - : extern ${net["G0_B"]} - : extern ${net["G0_Y"]} - : endgraph - : - : graph nor - : ${ makeNOR("G0") } - : extern ${net["G0_VDD"]} - : extern ${net["G0_VSS"]} - : extern ${net["G0_A"]} - : extern ${net["G0_B"]} - : extern ${net["G0_Y"]} - : endgraph - : - : graph haystack - : ${ makeNAND("G1") } - : ${ makeNAND("G2") } - : ${ makeNAND("G3") } - : ${ makeNAND("G4") } - ${ makeNOR("G5") } - : - : node vdd vsupply V 1 - : connect vdd V ${net["G1_VDD"]} - : connect vdd V ${net["G2_VDD"]} - : connect vdd V ${net["G3_VDD"]} - : connect vdd V ${net["G4_VDD"]} - : connect vdd V ${net["G5_VDD"]} - : - : node vss vsupply V 1 - : connect vss V ${net["G1_VSS"]} - : connect vss V ${net["G2_VSS"]} - : connect vss V ${net["G3_VSS"]} - : connect vss V ${net["G4_VSS"]} - : connect vss V ${net["G5_VSS"]} - : - : connect ${net["G2_A"]} ${net["G1_A"]} - : connect ${net["G2_B"]} ${net["G2_VSS"]} - : - : connect ${net["G3_A"]} ${net["G1_VDD"]} - : connect ${net["G3_B"]} ${net["G2_Y"]} - : - : connect ${net["G4_A"]} ${net["G1_Y"]} - : connect ${net["G4_B"]} ${net["G1_Y"]} - : - : connect ${net["G5_A"]} ${net["G3_Y"]} - : connect ${net["G5_B"]} ${net["G4_Y"]} - : endgraph - : - : solve nand haystack false - : clearoverlap - : expect 4 - : - : solve nor haystack false - : clearoverlap - : expect 1 -); - diff --git a/yosys/manual/.gitignore b/yosys/manual/.gitignore deleted file mode 100644 index 110f65b19..000000000 --- a/yosys/manual/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -*.aux -*.bbl -*.blg -*.idx -*.log -*.out -*.pdf -*.toc -*.snm -*.nav -*.vrb -*.ok diff --git a/yosys/manual/APPNOTE_010_Verilog_to_BLIF.tex b/yosys/manual/APPNOTE_010_Verilog_to_BLIF.tex deleted file mode 100644 index 0ecdf6194..000000000 --- a/yosys/manual/APPNOTE_010_Verilog_to_BLIF.tex +++ /dev/null @@ -1,466 +0,0 @@ - -% IEEEtran howto: -% http://ftp.univie.ac.at/packages/tex/macros/latex/contrib/IEEEtran/IEEEtran_HOWTO.pdf -\documentclass[9pt,technote,a4paper]{IEEEtran} - -\usepackage[T1]{fontenc} % required for luximono! -\usepackage[scaled=0.8]{luximono} % typewriter font with bold face - -% To install the luximono font files: -% getnonfreefonts-sys --all or -% getnonfreefonts-sys luximono -% -% when there are trouble you might need to: -% - Create /etc/texmf/updmap.d/99local-luximono.cfg -% containing the single line: Map ul9.map -% - Run update-updmap followed by mktexlsr and updmap-sys -% -% This commands must be executed as root with a root environment -% (i.e. run "sudo su" and then execute the commands in the root -% shell, don't just prefix the commands with "sudo"). - -\usepackage[unicode,bookmarks=false]{hyperref} -\usepackage[english]{babel} -\usepackage[utf8]{inputenc} -\usepackage{amssymb} -\usepackage{amsmath} -\usepackage{amsfonts} -\usepackage{units} -\usepackage{nicefrac} -\usepackage{eurosym} -\usepackage{graphicx} -\usepackage{verbatim} -\usepackage{algpseudocode} -\usepackage{scalefnt} -\usepackage{xspace} -\usepackage{color} -\usepackage{colortbl} -\usepackage{multirow} -\usepackage{hhline} -\usepackage{listings} -\usepackage{float} - -\usepackage{tikz} -\usetikzlibrary{calc} -\usetikzlibrary{arrows} -\usetikzlibrary{scopes} -\usetikzlibrary{through} -\usetikzlibrary{shapes.geometric} - -\lstset{basicstyle=\ttfamily,frame=trBL,xleftmargin=2em,xrightmargin=1em,numbers=left} - -\begin{document} - -\title{Yosys Application Note 010: \\ Converting Verilog to BLIF} -\author{Clifford Wolf \\ November 2013} -\maketitle - -\begin{abstract} -Verilog-2005 is a powerful Hardware Description Language (HDL) that can be used -to easily create complex designs from small HDL code. It is the preferred -method of design entry for many designers\footnote{The other half prefers VHDL, -a very different but -- of course -- equally powerful language.}. - -The Berkeley Logic Interchange Format (BLIF) \cite{blif} is a simple file format for -exchanging sequential logic between programs. It is easy to generate and -easy to parse and is therefore the preferred method of design entry for -many authors of logic synthesis tools. - -Yosys \cite{yosys} is a feature-rich -Open-Source Verilog synthesis tool that can be used to bridge the gap between -the two file formats. It implements most of Verilog-2005 and thus can be used -to import modern behavioral Verilog designs into BLIF-based design flows -without dependencies on proprietary synthesis tools. - -The scope of Yosys goes of course far beyond Verilog logic synthesis. But -it is a useful and important feature and this Application Note will focus -on this aspect of Yosys. -\end{abstract} - -\section{Installation} - -Yosys written in C++ (using features from C++11) and is tested on modern Linux. -It should compile fine on most UNIX systems with a C++11 compiler. The README -file contains useful information on building Yosys and its prerequisites. - -Yosys is a large and feature-rich program with a couple of dependencies. It is, -however, possible to deactivate some of the dependencies in the Makefile, -resulting in features in Yosys becoming unavailable. When problems with building -Yosys are encountered, a user who is only interested in the features of Yosys -that are discussed in this Application Note may deactivate {\tt TCL}, {\tt Qt} -and {\tt MiniSAT} support in the {\tt Makefile} and may opt against building -{\tt yosys-abc}. - -\bigskip - -This Application Note is based on GIT Rev. {\tt e216e0e} from 2013-11-23 of -Yosys \cite{yosys}. The Verilog sources used for the examples are taken from -yosys-bigsim \cite{bigsim}, a collection of real-world designs used for -regression testing Yosys. - -\section{Getting Started} - -We start our tour with the Navr\'e processor from yosys-bigsim. The Navr\'e -processor \cite{navre} is an Open Source AVR clone. It is a single module ({\tt -softusb\_navre}) in a single design file ({\tt softusb\_navre.v}). It also is -using only features that map nicely to the BLIF format, for example it only -uses synchronous resets. - -Converting {\tt softusb\_navre.v} to {\tt softusb\_navre.blif} could not be -easier: - -\begin{figure}[H] -\begin{lstlisting}[language=sh] -yosys -o softusb_navre.blif -S softusb_navre.v -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{Calling Yosys without script file} -\end{figure} - -Behind the scenes Yosys is controlled by synthesis scripts that execute -commands that operate on Yosys' internal state. For example, the {\tt -o -softusb\_navre.blif} option just adds the command {\tt write\_blif -softusb\_navre.blif} to the end of the script. Likewise a file on the -command line -- {\tt softusb\_navre.v} in this case -- adds the command -{\tt read\_verilog softusb\_navre.v} to the beginning of the -synthesis script. In both cases the file type is detected from the -file extension. - -Finally the option {\tt -S} instantiates a built-in default synthesis script. -Instead of using {\tt -S} one could also specify the synthesis commands -for the script on the command line using the {\tt -p} option, either using -individual options for each command or by passing one big command string -with a semicolon-separated list of commands. But in most cases it is more -convenient to use an actual script file. - -\section{Using a Synthesis Script} - -With a script file we have better control over Yosys. The following script -file replicates what the command from the last section did: - -\begin{figure}[H] -\begin{lstlisting}[language=sh] -read_verilog softusb_navre.v -hierarchy -proc; opt; memory; opt; techmap; opt -write_blif softusb_navre.blif -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{\tt softusb\_navre.ys} -\end{figure} - -The first and last line obviously read the Verilog file and write the BLIF -file. - -\medskip - -The 2nd line checks the design hierarchy and instantiates parametrized -versions of the modules in the design, if necessary. In the case of this -simple design this is a no-op. However, as a general rule a synthesis script -should always contain this command as first command after reading the input -files. - -\medskip - -The 3rd line does most of the actual work: - -\begin{itemize} -\item The command {\tt opt} is the Yosys' built-in optimizer. It can perform -some simple optimizations such as const-folding and removing unconnected parts -of the design. It is common practice to call opt after each major step in the -synthesis procedure. In cases where too much optimization is not appreciated -(for example when analyzing a design), it is recommended to call {\tt clean} -instead of {\tt opt}. -\item The command {\tt proc} converts {\it processes} (Yosys' internal -representation of Verilog {\tt always}- and {\tt initial}-blocks) to circuits -of multiplexers and storage elements (various types of flip-flops). -\item The command {\tt memory} converts Yosys' internal representations of -arrays and array accesses to multi-port block memories, and then maps this -block memories to address decoders and flip-flops, unless the option {\tt -nomap} -is used, in which case the multi-port block memories stay in the design -and can then be mapped to architecture-specific memory primitives using -other commands. -\item The command {\tt techmap} turns a high-level circuit with coarse grain -cells such as wide adders and multipliers to a fine-grain circuit of simple -logic primitives and single-bit storage elements. The command does that by -substituting the complex cells by circuits of simpler cells. It is possible -to provide a custom set of rules for this process in the form of a Verilog -source file, as we will see in the next section. -\end{itemize} - -Now Yosys can be run with the filename of the synthesis script as argument: - -\begin{figure}[H] -\begin{lstlisting}[language=sh] -yosys softusb_navre.ys -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{Calling Yosys with script file} -\end{figure} - -\medskip - -Now that we are using a synthesis script we can easily modify how Yosys -synthesizes the design. The first thing we should customize is the -call to the {\tt hierarchy} command: - -Whenever it is known that there are no implicit blackboxes in the design, i.e. -modules that are referenced but are not defined, the {\tt hierarchy} command -should be called with the {\tt -check} option. This will then cause synthesis -to fail when implicit blackboxes are found in the design. - -The 2nd thing we can improve regarding the {\tt hierarchy} command is that we -can tell it the name of the top level module of the design hierarchy. It will -then automatically remove all modules that are not referenced from this top -level module. - -\medskip - -For many designs it is also desired to optimize the encodings for the finite -state machines (FSMs) in the design. The {\tt fsm} command finds FSMs, extracts -them, performs some basic optimizations and then generate a circuit from -the extracted and optimized description. It would also be possible to tell -the {\tt fsm} command to leave the FSMs in their extracted form, so they can be -further processed using custom commands. But in this case we don't want that. - -\medskip - -So now we have the final synthesis script for generating a BLIF file -for the Navr\'e CPU: - -\begin{figure}[H] -\begin{lstlisting}[language=sh] -read_verilog softusb_navre.v -hierarchy -check -top softusb_navre -proc; opt; memory; opt; fsm; opt; techmap; opt -write_blif softusb_navre.blif -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{{\tt softusb\_navre.ys} (improved)} -\end{figure} - -\section{Advanced Example: The Amber23 ARMv2a CPU} - -Our 2nd example is the Amber23 \cite{amber} -ARMv2a CPU. Once again we base our example on the Verilog code that is included -in yosys-bigsim \cite{bigsim}. - -\begin{figure}[b!] -\begin{lstlisting}[language=sh] -read_verilog a23_alu.v -read_verilog a23_barrel_shift_fpga.v -read_verilog a23_barrel_shift.v -read_verilog a23_cache.v -read_verilog a23_coprocessor.v -read_verilog a23_core.v -read_verilog a23_decode.v -read_verilog a23_execute.v -read_verilog a23_fetch.v -read_verilog a23_multiply.v -read_verilog a23_ram_register_bank.v -read_verilog a23_register_bank.v -read_verilog a23_wishbone.v -read_verilog generic_sram_byte_en.v -read_verilog generic_sram_line_en.v -hierarchy -check -top a23_core -add -global_input globrst 1 -proc -global_arst globrst -techmap -map adff2dff.v -opt; memory; opt; fsm; opt; techmap -write_blif amber23.blif -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{\tt amber23.ys} -\label{aber23.ys} -\end{figure} - -The problem with this core is that it contains no dedicated reset logic. -Instead the coding techniques shown in Listing~\ref{glob_arst} are used to -define reset values for the global asynchronous reset in an FPGA -implementation. This design can not be expressed in BLIF as it is. Instead we -need to use a synthesis script that transforms this form to synchronous resets that -can be expressed in BLIF. - -(Note that there is no problem if this coding techniques are used to model -ROM, where the register is initialized using this syntax but is never updated -otherwise.) - -\medskip - -Listing~\ref{aber23.ys} shows the synthesis script for the Amber23 core. In -line 17 the {\tt add} command is used to add a 1-bit wide global input signal -with the name {\tt globrst}. That means that an input with that name is added -to each module in the design hierarchy and then all module instantiations are -altered so that this new signal is connected throughout the whole design -hierarchy. - -\begin{figure}[t!] -\begin{lstlisting}[language=Verilog] -reg [7:0] a = 13, b; -initial b = 37; -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{Implicit coding of global asynchronous resets} -\label{glob_arst} -\end{figure} - -\begin{figure}[b!] -\begin{lstlisting}[language=Verilog] -(* techmap_celltype = "$adff" *) -module adff2dff (CLK, ARST, D, Q); - -parameter WIDTH = 1; -parameter CLK_POLARITY = 1; -parameter ARST_POLARITY = 1; -parameter ARST_VALUE = 0; - -input CLK, ARST; -input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q; - -wire [1023:0] _TECHMAP_DO_ = "proc"; - -wire _TECHMAP_FAIL_ = - !CLK_POLARITY || !ARST_POLARITY; - -always @(posedge CLK) - if (ARST) - Q <= ARST_VALUE; - else - Q <= D; - -endmodule -\end{lstlisting} -\renewcommand{\figurename}{Listing} -\caption{\tt adff2dff.v} -\label{adff2dff.v} -\end{figure} - -In line 18 the {\tt proc} command is called. But in this script the signal name -{\tt globrst} is passed to the command as a global reset signal for resetting -the registers to their assigned initial values. - -Finally in line 19 the {\tt techmap} command is used to replace all instances -of flip-flops with asynchronous resets with flip-flops with synchronous resets. -The map file used for this is shown in Listing~\ref{adff2dff.v}. Note how the -{\tt techmap\_celltype} attribute is used in line 1 to tell the techmap command -which cells to replace in the design, how the {\tt \_TECHMAP\_FAIL\_} wire in -lines 15 and 16 (which evaluates to a constant value) determines if the -parameter set is compatible with this replacement circuit, and how the {\tt -\_TECHMAP\_DO\_} wire in line 13 provides a mini synthesis-script to be used to -process this cell. - -\begin{figure*} -\begin{lstlisting}[language=C] -#include -#include - -#define BITMAP_SIZE 64 -#define OUTPORT 0x10000000 - -static uint32_t bitmap[BITMAP_SIZE/32]; - -static void bitmap_set(uint32_t idx) { bitmap[idx/32] |= 1 << (idx % 32); } -static bool bitmap_get(uint32_t idx) { return (bitmap[idx/32] & (1 << (idx % 32))) != 0; } -static void output(uint32_t val) { *((volatile uint32_t*)OUTPORT) = val; } - -int main() { - uint32_t i, j, k; - output(2); - for (i = 0; i < BITMAP_SIZE; i++) { - if (bitmap_get(i)) continue; - output(3+2*i); - for (j = 2*(3+2*i);; j += 3+2*i) { - if (j%2 == 0) continue; - k = (j-3)/2; - if (k >= BITMAP_SIZE) break; - bitmap_set(k); - } - } - output(0); - return 0; -} -\end{lstlisting} -\renewcommand{\figurename}{Listing} -\caption{Test program for the Amber23 CPU (Sieve of Eratosthenes). Compiled using -GCC 4.6.3 for ARM with {\tt -Os -marm -march=armv2a -mno-thumb-interwork --ffreestanding}, linked with {\tt -{}-fix-v4bx} set and booted with a custom -setup routine written in ARM assembler.} -\label{sieve} -\end{figure*} - -\section{Verification of the Amber23 CPU} - -The BLIF file for the Amber23 core, generated using Listings~\ref{aber23.ys} -and \ref{adff2dff.v} and the version of the Amber23 RTL source that is bundled -with yosys-bigsim, was verified using the test-bench from yosys-bigsim. -It successfully executed the program shown in Listing~\ref{sieve} in the -test-bench. - -For simulation the BLIF file was converted back to Verilog using ABC -\cite{ABC}. So this test includes the successful transformation of the BLIF -file into ABC's internal format as well. - -The only thing left to write about the simulation itself is that it probably -was one of the most energy inefficient and time consuming ways of successfully -calculating the first 31 primes the author has ever conducted. - -\section{Limitations} - -At the time of this writing Yosys does not support multi-dimensional memories, -does not support writing to individual bits of array elements, does not -support initialization of arrays with {\tt \$readmemb} and {\tt \$readmemh}, -and has only limited support for tristate logic, to name just a few -limitations. - -That being said, Yosys can synthesize an overwhelming majority of real-world -Verilog RTL code. The remaining cases can usually be modified to be compatible -with Yosys quite easily. - -The various designs in yosys-bigsim are a good place to look for examples -of what is within the capabilities of Yosys. - -\section{Conclusion} - -Yosys is a feature-rich Verilog-2005 synthesis tool. It has many uses, but -one is to provide an easy gateway from high-level Verilog code to low-level -logic circuits. - -The command line option {\tt -S} can be used to quickly synthesize Verilog -code to BLIF files without a hassle. - -With custom synthesis scripts it becomes possible to easily perform high-level -optimizations, such as re-encoding FSMs. In some extreme cases, such as the -Amber23 ARMv2 CPU, the more advanced Yosys features can be used to change a -design to fit a certain need without actually touching the RTL code. - -\begin{thebibliography}{9} - -\bibitem{yosys} -Clifford Wolf. The Yosys Open SYnthesis Suite. \\ -\url{http://www.clifford.at/yosys/} - -\bibitem{bigsim} -yosys-bigsim, a collection of real-world Verilog designs for regression testing purposes. \\ -\url{https://github.com/cliffordwolf/yosys-bigsim} - -\bibitem{navre} -Sebastien Bourdeauducq. Navr\'e AVR clone (8-bit RISC). \\ -\url{http://opencores.org/project,navre} - -\bibitem{amber} -Conor Santifort. Amber ARM-compatible core. \\ -\url{http://opencores.org/project,amber} - -\bibitem{ABC} -Berkeley Logic Synthesis and Verification Group. ABC: A System for Sequential Synthesis and Verification. \\ -\url{http://www.eecs.berkeley.edu/~alanmi/abc/} - -\bibitem{blif} -Berkeley Logic Interchange Format (BLIF) \\ -\url{http://vlsi.colorado.edu/~vis/blif.ps} - -\end{thebibliography} - - -\end{document} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation.tex b/yosys/manual/APPNOTE_011_Design_Investigation.tex deleted file mode 100644 index 9780c7833..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation.tex +++ /dev/null @@ -1,1070 +0,0 @@ - -% IEEEtran howto: -% http://ftp.univie.ac.at/packages/tex/macros/latex/contrib/IEEEtran/IEEEtran_HOWTO.pdf -\documentclass[9pt,technote,a4paper]{IEEEtran} - -\usepackage[T1]{fontenc} % required for luximono! -\usepackage[scaled=0.8]{luximono} % typewriter font with bold face - -% To install the luximono font files: -% getnonfreefonts-sys --all or -% getnonfreefonts-sys luximono -% -% when there are trouble you might need to: -% - Create /etc/texmf/updmap.d/99local-luximono.cfg -% containing the single line: Map ul9.map -% - Run update-updmap followed by mktexlsr and updmap-sys -% -% This commands must be executed as root with a root environment -% (i.e. run "sudo su" and then execute the commands in the root -% shell, don't just prefix the commands with "sudo"). - -\usepackage[unicode,bookmarks=false]{hyperref} -\usepackage[english]{babel} -\usepackage[utf8]{inputenc} -\usepackage{amssymb} -\usepackage{amsmath} -\usepackage{amsfonts} -\usepackage{units} -\usepackage{nicefrac} -\usepackage{eurosym} -\usepackage{graphicx} -\usepackage{verbatim} -\usepackage{algpseudocode} -\usepackage{scalefnt} -\usepackage{xspace} -\usepackage{color} -\usepackage{colortbl} -\usepackage{multirow} -\usepackage{hhline} -\usepackage{listings} -\usepackage{float} - -\usepackage{tikz} -\usetikzlibrary{calc} -\usetikzlibrary{arrows} -\usetikzlibrary{scopes} -\usetikzlibrary{through} -\usetikzlibrary{shapes.geometric} - -\def\FIXME{{\color{red}\bf FIXME}} - -\lstset{basicstyle=\ttfamily,frame=trBL,xleftmargin=0.7cm,xrightmargin=0.2cm,numbers=left} - -\begin{document} - -\title{Yosys Application Note 011: \\ Interactive Design Investigation} -\author{Clifford Wolf \\ Original Version December 2013} -\maketitle - -\begin{abstract} -Yosys \cite{yosys} can be a great environment for building custom synthesis -flows. It can also be an excellent tool for teaching and learning Verilog based -RTL synthesis. In both applications it is of great importance to be able to -analyze the designs it produces easily. - -This Yosys application note covers the generation of circuit diagrams with the -Yosys {\tt show} command, the selection of interesting parts of the circuit -using the {\tt select} command, and briefly discusses advanced investigation -commands for evaluating circuits and solving SAT problems. -\end{abstract} - -\section{Installation and Prerequisites} - -This Application Note is based on the Yosys \cite{yosys} GIT Rev. {\tt 2b90ba1} from -2013-12-08. The {\tt README} file covers how to install Yosys. The -{\tt show} command requires a working installation of GraphViz \cite{graphviz} -and \cite{xdot} for generating the actual circuit diagrams. - -\section{Overview} - -This application note is structured as follows: - -Sec.~\ref{intro_show} introduces the {\tt show} command and explains the -symbols used in the circuit diagrams generated by it. - -Sec.~\ref{navigate} introduces additional commands used to navigate in the -design, select portions of the design, and print additional information on -the elements in the design that are not contained in the circuit diagrams. - -Sec.~\ref{poke} introduces commands to evaluate the design and solve SAT -problems within the design. - -Sec.~\ref{conclusion} concludes the document and summarizes the key points. - -\section{Introduction to the {\tt show} command} -\label{intro_show} - -\begin{figure}[b] -\begin{lstlisting} -$ cat example.ys -read_verilog example.v -show -pause -proc -show -pause -opt -show -pause - -$ cat example.v -module example(input clk, a, b, c, - output reg [1:0] y); - always @(posedge clk) - if (c) - y <= c ? a + b : 2'd0; -endmodule -\end{lstlisting} -\caption{Yosys script with {\tt show} commands and example design} -\label{example_src} -\end{figure} - -\begin{figure}[b!] -\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/example_00.pdf} -\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/example_01.pdf} -\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/example_02.pdf} -\caption{Output of the three {\tt show} commands from Fig.~\ref{example_src}} -\label{example_out} -\end{figure} - -The {\tt show} command generates a circuit diagram for the design in its -current state. Various options can be used to change the appearance of the -circuit diagram, set the name and format for the output file, and so forth. -When called without any special options, it saves the circuit diagram in -a temporary file and launches {\tt xdot} to display the diagram. -Subsequent calls to {\tt show} re-use the {\tt xdot} instance -(if still running). - -\subsection{A simple circuit} - -Fig.~\ref{example_src} shows a simple synthesis script and a Verilog file that -demonstrate the usage of {\tt show} in a simple setting. Note that {\tt show} -is called with the {\tt -pause} option, that halts execution of the Yosys -script until the user presses the Enter key. The {\tt show -pause} command -also allows the user to enter an interactive shell to further investigate the -circuit before continuing synthesis. - -So this script, when executed, will show the design after each of the three -synthesis commands. The generated circuit diagrams are shown in Fig.~\ref{example_out}. - -The first diagram (from top to bottom) shows the design directly after being -read by the Verilog front-end. Input and output ports are displayed as -octagonal shapes. Cells are displayed as rectangles with inputs on the left -and outputs on the right side. The cell labels are two lines long: The first line -contains a unique identifier for the cell and the second line contains the cell -type. Internal cell types are prefixed with a dollar sign. The Yosys manual -contains a chapter on the internal cell library used in Yosys. - -Constants are shown as ellipses with the constant value as label. The syntax -{\tt '} is used for for constants that are not 32-bit wide -and/or contain bits that are not 0 or 1 (i.e. {\tt x} or {\tt z}). Ordinary -32-bit constants are written using decimal numbers. - -Single-bit signals are shown as thin arrows pointing from the driver to the -load. Signals that are multiple bits wide are shown as think arrows. - -Finally {\it processes\/} are shown in boxes with round corners. Processes -are Yosys' internal representation of the decision-trees and synchronization -events modelled in a Verilog {\tt always}-block. The label reads {\tt PROC} -followed by a unique identifier in the first line and contains the source code -location of the original {\tt always}-block in the 2nd line. Note how the -multiplexer from the {\tt ?:}-expression is represented as a {\tt \$mux} cell -but the multiplexer from the {\tt if}-statement is yet still hidden within the -process. - -\medskip - -The {\tt proc} command transforms the process from the first diagram into a -multiplexer and a d-type flip-flip, which brings us to the 2nd diagram. - -The Rhombus shape to the right is a dangling wire. (Wire nodes are only shown -if they are dangling or have ``public'' names, for example names assigned from -the Verilog input.) Also note that the design now contains two instances of a -{\tt BUF}-node. This are artefacts left behind by the {\tt proc}-command. It is -quite usual to see such artefacts after calling commands that perform changes -in the design, as most commands only care about doing the transformation in the -least complicated way, not about cleaning up after them. The next call to {\tt -clean} (or {\tt opt}, which includes {\tt clean} as one of its operations) will -clean up this artefacts. This operation is so common in Yosys scripts that it -can simply be abbreviated with the {\tt ;;} token, which doubles as -separator for commands. Unless one wants to specifically analyze this artefacts -left behind some operations, it is therefore recommended to always call {\tt clean} -before calling {\tt show}. - -\medskip - -In this script we directly call {\tt opt} as next step, which finally leads us to -the 3rd diagram in Fig.~\ref{example_out}. Here we see that the {\tt opt} command -not only has removed the artifacts left behind by {\tt proc}, but also determined -correctly that it can remove the first {\tt \$mux} cell without changing the behavior -of the circuit. - -\begin{figure}[b!] -\includegraphics[width=\linewidth,trim=0 2cm 0 0]{APPNOTE_011_Design_Investigation/splice.pdf} -\caption{Output of {\tt yosys -p 'proc; opt; show' splice.v}} -\label{splice_dia} -\end{figure} - -\begin{figure}[b!] -\lstinputlisting{APPNOTE_011_Design_Investigation/splice.v} -\caption{\tt splice.v} -\label{splice_src} -\end{figure} - -\begin{figure}[t!] -\includegraphics[height=\linewidth]{APPNOTE_011_Design_Investigation/cmos_00.pdf} -\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/cmos_01.pdf} -\caption{Effects of {\tt splitnets} command and of providing a cell library. (The -circuit is a half-adder built from simple CMOS gates.)} -\label{splitnets_libfile} -\end{figure} - -\subsection{Break-out boxes for signal vectors} - -As has been indicated by the last example, Yosys is can manage signal vectors (aka. -multi-bit wires or buses) as native objects. This provides great advantages -when analyzing circuits that operate on wide integers. But it also introduces -some additional complexity when the individual bits of of a signal vector -are accessed. The example show in Fig.~\ref{splice_dia} and \ref{splice_src} -demonstrates how such circuits are visualized by the {\tt show} command. - -The key elements in understanding this circuit diagram are of course the boxes -with round corners and rows labeled {\tt : -- :}. -Each of this boxes has one signal per row on one side and a common signal for all rows on the -other side. The {\tt :} tuples specify which bits of the signals are broken out -and connected. So the top row of the box connecting the signals {\tt a} and {\tt x} indicates -that the bit 0 (i.e. the range 0:0) from signal {\tt a} is connected to bit 1 (i.e. the range -1:1) of signal {\tt x}. - -Lines connecting such boxes together and lines connecting such boxes to cell -ports have a slightly different look to emphasise that they are not actual signal -wires but a necessity of the graphical representation. This distinction seems -like a technicality, until one wants to debug a problem related to the way -Yosys internally represents signal vectors, for example when writing custom -Yosys commands. - -\subsection{Gate level netlists} - -Finally Fig.~\ref{splitnets_libfile} shows two common pitfalls when working -with designs mapped to a cell library. The top figure has two problems: First -Yosys did not have access to the cell library when this diagram was generated, -resulting in all cell ports defaulting to being inputs. This is why all ports -are drawn on the left side the cells are awkwardly arranged in a large column. -Secondly the two-bit vector {\tt y} requires breakout-boxes for its individual -bits, resulting in an unnecessary complex diagram. - -For the 2nd diagram Yosys has been given a description of the cell library as -Verilog file containing blackbox modules. There are two ways to load cell -descriptions into Yosys: First the Verilog file for the cell library can be -passed directly to the {\tt show} command using the {\tt -lib } -option. Secondly it is possible to load cell libraries into the design with -the {\tt read\_verilog -lib } command. The 2nd method has the great -advantage that the library only needs to be loaded once and can then be used -in all subsequent calls to the {\tt show} command. - -In addition to that, the 2nd diagram was generated after {\tt splitnet -ports} -was run on the design. This command splits all signal vectors into individual -signal bits, which is often desirable when looking at gate-level circuits. The -{\tt -ports} option is required to also split module ports. Per default the -command only operates on interior signals. - -\subsection{Miscellaneous notes} - -Per default the {\tt show} command outputs a temporary {\tt dot} file and launches -{\tt xdot} to display it. The options {\tt -format}, {\tt -viewer} -and {\tt -prefix} can be used to change format, viewer and filename prefix. -Note that the {\tt pdf} and {\tt ps} format are the only formats that support -plotting multiple modules in one run. - -In densely connected circuits it is sometimes hard to keep track of the -individual signal wires. For this cases it can be useful to call {\tt show} -with the {\tt -colors } argument, which randomly assigns colors to the -nets. The integer (> 0) is used as seed value for the random color -assignments. Sometimes it is necessary it try some values to find an assignment -of colors that looks good. - -The command {\tt help show} prints a complete listing of all options supported -by the {\tt show} command. - -\section{Navigating the design} -\label{navigate} - -Plotting circuit diagrams for entire modules in the design brings us only helps -in simple cases. For complex modules the generated circuit diagrams are just stupidly big -and are no help at all. In such cases one first has to select the relevant -portions of the circuit. - -In addition to {\it what\/} to display one also needs to carefully decide -{\it when\/} to display it, with respect to the synthesis flow. In general -it is a good idea to troubleshoot a circuit in the earliest state in which -a problem can be reproduced. So if, for example, the internal state before calling -the {\tt techmap} command already fails to verify, it is better to troubleshoot -the coarse-grain version of the circuit before {\tt techmap} than the gate-level -circuit after {\tt techmap}. - -\medskip - -Note: It is generally recommended to verify the internal state of a design by -writing it to a Verilog file using {\tt write\_verilog -noexpr} and using the -simulation models from {\tt simlib.v} and {\tt simcells.v} from the Yosys data -directory (as printed by {\tt yosys-config -{}-datdir}). - -\subsection{Interactive Navigation} - -\begin{figure} -\begin{lstlisting} -yosys> ls - -1 modules: - example - -yosys> cd example - -yosys [example]> ls - -7 wires: - $0\y[1:0] - $add$example.v:5$2_Y - a - b - c - clk - y - -3 cells: - $add$example.v:5$2 - $procdff$7 - $procmux$5 -\end{lstlisting} -\caption{Demonstration of {\tt ls} and {\tt cd} using {\tt example.v} from Fig.~\ref{example_src}} -\label{lscd} -\end{figure} - -\begin{figure}[b] -\begin{lstlisting} - attribute \src "example.v:5" - cell $add $add$example.v:5$2 - parameter \A_SIGNED 0 - parameter \A_WIDTH 1 - parameter \B_SIGNED 0 - parameter \B_WIDTH 1 - parameter \Y_WIDTH 2 - connect \A \a - connect \B \b - connect \Y $add$example.v:5$2_Y - end -\end{lstlisting} -\caption{Output of {\tt dump \$2} using the design from Fig.~\ref{example_src} and Fig.~\ref{example_out}} -\label{dump2} -\end{figure} - -Once the right state within the synthesis flow for debugging the circuit has -been identified, it is recommended to simply add the {\tt shell} command -to the matching place in the synthesis script. This command will stop the -synthesis at the specified moment and go to shell mode, where the user can -interactively enter commands. - -For most cases, the shell will start with the whole design selected (i.e. when -the synthesis script does not already narrow the selection). The command {\tt -ls} can now be used to create a list of all modules. The command {\tt cd} can -be used to switch to one of the modules (type {\tt cd ..} to switch back). Now -the {\tt ls} command lists the objects within that module. Fig.~\ref{lscd} -demonstrates this using the design from Fig.~\ref{example_src}. - -There is a thing to note in Fig.~\ref{lscd}: We can see that the cell names -from Fig.~\ref{example_out} are just abbreviations of the actual cell names, -namely the part after the last dollar-sign. Most auto-generated names (the ones -starting with a dollar sign) are rather long and contains some additional -information on the origin of the named object. But in most cases those names -can simply be abbreviated using the last part. - -Usually all interactive work is done with one module selected using the {\tt cd} -command. But it is also possible to work from the design-context ({\tt cd ..}). In -this case all object names must be prefixed with {\tt /}. For -example {\tt a*/b*} would refer to all objects whose names start with {\tt b} from -all modules whose names start with {\tt a}. - -The {\tt dump} command can be used to print all information about an object. -For example {\tt dump \$2} will print Fig.~\ref{dump2}. This can for example -be useful to determine the names of nets connected to cells, as the net-names -are usually suppressed in the circuit diagram if they are auto-generated. - -For the remainder of this document we will assume that the commands are run from -module-context and not design-context. - -\subsection{Working with selections} - -\begin{figure}[t] -\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/example_03.pdf} -\caption{Output of {\tt show} after {\tt select \$2} or {\tt select t:\$add} -(see also Fig.~\ref{example_out})} -\label{seladd} -\end{figure} - -When a module is selected using the {\tt cd} command, all commands (with a few -exceptions, such as the {\tt read\_*} and {\tt write\_*} commands) operate -only on the selected module. This can also be useful for synthesis scripts -where different synthesis strategies should be applied to different modules -in the design. - -But for most interactive work we want to further narrow the set of selected -objects. This can be done using the {\tt select} command. - -For example, if the command {\tt select \$2} is executed, a subsequent {\tt show} -command will yield the diagram shown in Fig.~\ref{seladd}. Note that the nets are -now displayed in ellipses. This indicates that they are not selected, but only -shown because the diagram contains a cell that is connected to the net. This -of course makes no difference for the circuit that is shown, but it can be a useful -information when manipulating selections. - -Objects can not only be selected by their name but also by other properties. -For example {\tt select t:\$add} will select all cells of type {\tt \$add}. In -this case this is also yields the diagram shown in Fig.~\ref{seladd}. - -\begin{figure}[b] -\lstinputlisting{APPNOTE_011_Design_Investigation/foobaraddsub.v} -\caption{Test module for operations on selections} -\label{foobaraddsub} -\end{figure} - -The output of {\tt help select} contains a complete syntax reference for -matching different properties. - -Many commands can operate on explicit selections. For example the command {\tt -dump t:\$add} will print information on all {\tt \$add} cells in the active -module. Whenever a command has {\tt [selection]} as last argument in its usage -help, this means that it will use the engine behind the {\tt select} command -to evaluate additional arguments and use the resulting selection instead of -the selection created by the last {\tt select} command. - -Normally the {\tt select} command overwrites a previous selection. The -commands {\tt select -add} and {\tt select -del} can be used to add -or remove objects from the current selection. - -The command {\tt select -clear} can be used to reset the selection to the -default, which is a complete selection of everything in the current module. - -\subsection{Operations on selections} - -\begin{figure}[t] -\lstinputlisting{APPNOTE_011_Design_Investigation/sumprod.v} -\caption{Another test module for operations on selections} -\label{sumprod} -\end{figure} - -\begin{figure}[b] -\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/sumprod_00.pdf} -\caption{Output of {\tt show a:sumstuff} on Fig.~\ref{sumprod}} -\label{sumprod_00} -\end{figure} - -The {\tt select} command is actually much more powerful than it might seem on -the first glimpse. When it is called with multiple arguments, each argument is -evaluated and pushed separately on a stack. After all arguments have been -processed it simply creates the union of all elements on the stack. So the -following command will select all {\tt \$add} cells and all objects with -the {\tt foo} attribute set: - -\begin{verbatim} -select t:$add a:foo -\end{verbatim} - -(Try this with the design shown in Fig.~\ref{foobaraddsub}. Use the {\tt -select -list} command to list the current selection.) - -In many cases simply adding more and more stuff to the selection is an -ineffective way of selecting the interesting part of the design. Special -arguments can be used to combine the elements on the stack. -For example the {\tt \%i} arguments pops the last two elements from -the stack, intersects them, and pushes the result back on the stack. So the -following command will select all {\$add} cells that have the {\tt foo} -attribute set: - -\begin{verbatim} -select t:$add a:foo %i -\end{verbatim} - -The listing in Fig.~\ref{sumprod} uses the Yosys non-standard {\tt \{* ... *\}} -syntax to set the attribute {\tt sumstuff} on all cells generated by the first -assign statement. (This works on arbitrary large blocks of Verilog code an -can be used to mark portions of code for analysis.) - -Selecting {\tt a:sumstuff} in this module will yield the circuit diagram shown -in Fig.~\ref{sumprod_00}. As only the cells themselves are selected, but not -the temporary wire {\tt \$1\_Y}, the two adders are shown as two disjunct -parts. This can be very useful for global signals like clock and reset signals: just -unselect them using a command such as {\tt select -del clk rst} and each cell -using them will get its own net label. - -In this case however we would like to see the cells connected properly. This -can be achieved using the {\tt \%x} action, that broadens the selection, i.e. -for each selected wire it selects all cells connected to the wire and vice -versa. So {\tt show a:sumstuff \%x} yields the diagram shown in Fig.~\ref{sumprod_01}. - -\begin{figure}[t] -\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/sumprod_01.pdf} -\caption{Output of {\tt show a:sumstuff \%x} on Fig.~\ref{sumprod}} -\label{sumprod_01} -\end{figure} - -\subsection{Selecting logic cones} - -Fig.~\ref{sumprod_01} shows what is called the {\it input cone\/} of {\tt sum}, i.e. -all cells and signals that are used to generate the signal {\tt sum}. The {\tt \%ci} -action can be used to select the input cones of all object in the top selection -in the stack maintained by the {\tt select} command. - -As the {\tt \%x} action, this commands broadens the selection by one ``step''. But -this time the operation only works against the direction of data flow. That means, -wires only select cells via output ports and cells only select wires via input ports. - -Fig.~\ref{select_prod} show the sequence of diagrams generated by the following -commands: - -\begin{verbatim} -show prod -show prod %ci -show prod %ci %ci -show prod %ci %ci %ci -\end{verbatim} - -When selecting many levels of logic, repeating {\tt \%ci} over and over again -can be a bit dull. So there is a shortcut for that: the number of iterations -can be appended to the action. So for example the action {\tt \%ci3} is -identical to performing the {\tt \%ci} action three times. - -The action {\tt \%ci*} performs the {\tt \%ci} action over and over again until -it has no effect anymore. - -\begin{figure}[t] -\hfill \includegraphics[width=4cm,trim=0 1cm 0 1cm]{APPNOTE_011_Design_Investigation/sumprod_02.pdf} \\ -\includegraphics[width=\linewidth,trim=0 0cm 0 1cm]{APPNOTE_011_Design_Investigation/sumprod_03.pdf} \\ -\includegraphics[width=\linewidth,trim=0 0cm 0 1cm]{APPNOTE_011_Design_Investigation/sumprod_04.pdf} \\ -\includegraphics[width=\linewidth,trim=0 2cm 0 1cm]{APPNOTE_011_Design_Investigation/sumprod_05.pdf} \\ -\caption{Objects selected by {\tt select prod \%ci...}} -\label{select_prod} -\end{figure} - -\medskip - -In most cases there are certain cell types and/or ports that should not be considered for the {\tt \%ci} -action, or we only want to follow certain cell types and/or ports. This can be achieved using additional -patterns that can be appended to the {\tt \%ci} action. - -Lets consider the design from Fig.~\ref{memdemo_src}. It serves no purpose other than being a non-trivial -circuit for demonstrating some of the advanced Yosys features. We synthesize the circuit using {\tt proc; -opt; memory; opt} and change to the {\tt memdemo} module with {\tt cd memdemo}. If we type {\tt show} -now we see the diagram shown in Fig.~\ref{memdemo_00}. - -\begin{figure}[b!] -\lstinputlisting{APPNOTE_011_Design_Investigation/memdemo.v} -\caption{Demo circuit for demonstrating some advanced Yosys features} -\label{memdemo_src} -\end{figure} - -\begin{figure*}[t] -\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{APPNOTE_011_Design_Investigation/memdemo_00.pdf} \\ -\caption{Complete circuit diagram for the design shown in Fig.~\ref{memdemo_src}} -\label{memdemo_00} -\end{figure*} - -But maybe we are only interested in the tree of multiplexers that select the -output value. In order to get there, we would start by just showing the output signal -and its immediate predecessors: - -\begin{verbatim} -show y %ci2 -\end{verbatim} - -From this we would learn that {\tt y} is driven by a {\tt \$dff cell}, that -{\tt y} is connected to the output port {\tt Q}, that the {\tt clk} signal goes -into the {\tt CLK} input port of the cell, and that the data comes from a -auto-generated wire into the input {\tt D} of the flip-flop cell. - -As we are not interested in the clock signal we add an additional pattern to the {\tt \%ci} -action, that tells it to only follow ports {\tt Q} and {\tt D} of {\tt \$dff} cells: - -\begin{verbatim} -show y %ci2:+$dff[Q,D] -\end{verbatim} - -To add a pattern we add a colon followed by the pattern to the {\tt \%ci} -action. The pattern it self starts with {\tt -} or {\tt +}, indicating if it is -an include or exclude pattern, followed by an optional comma separated list -of cell types, followed by an optional comma separated list of port names in -square brackets. - -Since we know that the only cell considered in this case is a {\tt \$dff} cell, -we could as well only specify the port names: - -\begin{verbatim} -show y %ci2:+[Q,D] -\end{verbatim} - -Or we could decide to tell the {\tt \%ci} action to not follow the {\tt CLK} input: - -\begin{verbatim} -show y %ci2:-[CLK] -\end{verbatim} - -\begin{figure}[b] -\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{APPNOTE_011_Design_Investigation/memdemo_01.pdf} \\ -\caption{Output of {\tt show y \%ci2:+\$dff[Q,D] \%ci*:-\$mux[S]:-\$dff}} -\label{memdemo_01} -\end{figure} - -Next we would investigate the next logic level by adding another {\tt \%ci2} to -the command: - -\begin{verbatim} -show y %ci2:-[CLK] %ci2 -\end{verbatim} - -From this we would learn that the next cell is a {\tt \$mux} cell and we would add additional -pattern to narrow the selection on the path we are interested. In the end we would end up -with a command such as - -\begin{verbatim} -show y %ci2:+$dff[Q,D] %ci*:-$mux[S]:-$dff -\end{verbatim} - -in which the first {\tt \%ci} jumps over the initial d-type flip-flop and the -2nd action selects the entire input cone without going over multiplexer select -inputs and flip-flop cells. The diagram produces by this command is shown in -Fig.~\ref{memdemo_01}. - -\medskip - -Similar to {\tt \%ci} exists an action {\tt \%co} to select output cones that -accepts the same syntax for pattern and repetition. The {\tt \%x} action mentioned -previously also accepts this advanced syntax. - -This actions for traversing the circuit graph, combined with the actions for -boolean operations such as intersection ({\tt \%i}) and difference ({\tt \%d}) -are powerful tools for extracting the relevant portions of the circuit under -investigation. - -See {\tt help select} for a complete list of actions available in selections. - -\subsection{Storing and recalling selections} - -The current selection can be stored in memory with the command {\tt select -set -}. It can later be recalled using {\tt select @}. In fact, the {\tt -@} expression pushes the stored selection on the stack maintained by the -{\tt select} command. So for example - -\begin{verbatim} -select @foo @bar %i -\end{verbatim} - -will select the intersection between the stored selections {\tt foo} and {\tt bar}. - -\medskip - -In larger investigation efforts it is highly recommended to maintain a script that -sets up relevant selections, so they can easily be recalled, for example when -Yosys needs to be re-run after a design or source code change. - -The {\tt history} command can be used to list all recent interactive commands. -This feature can be useful for creating such a script from the commands used in -an interactive session. - -\section{Advanced investigation techniques} -\label{poke} - -When working with very large modules, it is often not enough to just select the -interesting part of the module. Instead it can be useful to extract the -interesting part of the circuit into a separate module. This can for example be -useful if one wants to run a series of synthesis commands on the critical part -of the module and wants to carefully read all the debug output created by the -commands in order to spot a problem. This kind of troubleshooting is much easier -if the circuit under investigation is encapsulated in a separate module. - -Fig.~\ref{submod} shows how the {\tt submod} command can be used to split the -circuit from Fig.~\ref{memdemo_src} and \ref{memdemo_00} into its components. -The {\tt -name} option is used to specify the name of the new module and -also the name of the new cell in the current module. - -\begin{figure}[t] -\includegraphics[width=\linewidth,trim=0 1.3cm 0 0cm]{APPNOTE_011_Design_Investigation/submod_00.pdf} \\ \centerline{\tt memdemo} \vskip1em\par -\includegraphics[width=\linewidth,trim=0 1.3cm 0 0cm]{APPNOTE_011_Design_Investigation/submod_01.pdf} \\ \centerline{\tt scramble} \vskip1em\par -\includegraphics[width=\linewidth,trim=0 1.3cm 0 0cm]{APPNOTE_011_Design_Investigation/submod_02.pdf} \\ \centerline{\tt outstage} \vskip1em\par -\includegraphics[width=\linewidth,trim=0 1.3cm 0 0cm]{APPNOTE_011_Design_Investigation/submod_03.pdf} \\ \centerline{\tt selstage} \vskip1em\par -\begin{lstlisting}[basicstyle=\ttfamily\scriptsize] -select -set outstage y %ci2:+$dff[Q,D] %ci*:-$mux[S]:-$dff -select -set selstage y %ci2:+$dff[Q,D] %ci*:-$dff @outstage %d -select -set scramble mem* %ci2 %ci*:-$dff mem* %d @selstage %d -submod -name scramble @scramble -submod -name outstage @outstage -submod -name selstage @selstage -\end{lstlisting} -\caption{The circuit from Fig.~\ref{memdemo_src} and \ref{memdemo_00} broken up using {\tt submod}} -\label{submod} -\end{figure} - -\subsection{Evaluation of combinatorial circuits} - -The {\tt eval} command can be used to evaluate combinatorial circuits. -For example (see Fig.~\ref{submod} for the circuit diagram of {\tt selstage}): - -{\scriptsize -\begin{verbatim} - yosys [selstage]> eval -set s2,s1 4'b1001 -set d 4'hc -show n2 -show n1 - - 9. Executing EVAL pass (evaluate the circuit given an input). - Full command line: eval -set s2,s1 4'b1001 -set d 4'hc -show n2 -show n1 - Eval result: \n2 = 2'10. - Eval result: \n1 = 2'10. -\end{verbatim} -\par} - -So the {\tt -set} option is used to set input values and the {\tt -show} option -is used to specify the nets to evaluate. If no {\tt -show} option is specified, -all selected output ports are used per default. - -If a necessary input value is not given, an error is produced. The option -{\tt -set-undef} can be used to instead set all unspecified input nets to -undef ({\tt x}). - -The {\tt -table} option can be used to create a truth table. For example: - -{\scriptsize -\begin{verbatim} - yosys [selstage]> eval -set-undef -set d[3:1] 0 -table s1,d[0] - - 10. Executing EVAL pass (evaluate the circuit given an input). - Full command line: eval -set-undef -set d[3:1] 0 -table s1,d[0] - - \s1 \d [0] | \n1 \n2 - ---- ------ | ---- ---- - 2'00 1'0 | 2'00 2'00 - 2'00 1'1 | 2'xx 2'00 - 2'01 1'0 | 2'00 2'00 - 2'01 1'1 | 2'xx 2'01 - 2'10 1'0 | 2'00 2'00 - 2'10 1'1 | 2'xx 2'10 - 2'11 1'0 | 2'00 2'00 - 2'11 1'1 | 2'xx 2'11 - - Assumed undef (x) value for the following signals: \s2 -\end{verbatim} -} - -Note that the {\tt eval} command (as well as the {\tt sat} command discussed in -the next sections) does only operate on flattened modules. It can not analyze -signals that are passed through design hierarchy levels. So the {\tt flatten} -command must be used on modules that instantiate other modules before this -commands can be applied. - -\subsection{Solving combinatorial SAT problems} - -\begin{figure}[b] -\lstinputlisting{APPNOTE_011_Design_Investigation/primetest.v} -\caption{A simple miter circuit for testing if a number is prime. But it has a -problem (see main text and Fig.~\ref{primesat}).} -\label{primetest} -\end{figure} - -\begin{figure*}[!t] -\begin{lstlisting}[basicstyle=\ttfamily\small] -yosys [primetest]> sat -prove ok 1 -set p 31 - -8. Executing SAT pass (solving SAT problems in the circuit). -Full command line: sat -prove ok 1 -set p 31 - -Setting up SAT problem: -Import set-constraint: \p = 16'0000000000011111 -Final constraint equation: \p = 16'0000000000011111 -Imported 6 cells to SAT database. -Import proof-constraint: \ok = 1'1 -Final proof equation: \ok = 1'1 - -Solving problem with 2790 variables and 8241 clauses.. -SAT proof finished - model found: FAIL! - - ______ ___ ___ _ _ _ _ - (_____ \ / __) / __) (_) | | | | - _____) )___ ___ ___ _| |__ _| |__ _____ _| | _____ __| | | - | ____/ ___) _ \ / _ (_ __) (_ __|____ | | || ___ |/ _ |_| - | | | | | |_| | |_| || | | | / ___ | | || ____( (_| |_ - |_| |_| \___/ \___/ |_| |_| \_____|_|\_)_____)\____|_| - - - Signal Name Dec Hex Bin - -------------------- ---------- ---------- --------------------- - \a 15029 3ab5 0011101010110101 - \b 4099 1003 0001000000000011 - \ok 0 0 0 - \p 31 1f 0000000000011111 - -yosys [primetest]> sat -prove ok 1 -set p 31 -set a[15:8],b[15:8] 0 - -9. Executing SAT pass (solving SAT problems in the circuit). -Full command line: sat -prove ok 1 -set p 31 -set a[15:8],b[15:8] 0 - -Setting up SAT problem: -Import set-constraint: \p = 16'0000000000011111 -Import set-constraint: { \a [15:8] \b [15:8] } = 16'0000000000000000 -Final constraint equation: { \a [15:8] \b [15:8] \p } = { 16'0000000000000000 16'0000000000011111 } -Imported 6 cells to SAT database. -Import proof-constraint: \ok = 1'1 -Final proof equation: \ok = 1'1 - -Solving problem with 2790 variables and 8257 clauses.. -SAT proof finished - no model found: SUCCESS! - - /$$$$$$ /$$$$$$$$ /$$$$$$$ - /$$__ $$ | $$_____/ | $$__ $$ - | $$ \ $$ | $$ | $$ \ $$ - | $$ | $$ | $$$$$ | $$ | $$ - | $$ | $$ | $$__/ | $$ | $$ - | $$/$$ $$ | $$ | $$ | $$ - | $$$$$$/ /$$| $$$$$$$$ /$$| $$$$$$$//$$ - \____ $$$|__/|________/|__/|_______/|__/ - \__/ -\end{lstlisting} -\caption{Experiments with the miter circuit from Fig.~\ref{primetest}. The first attempt of proving that 31 -is prime failed because the SAT solver found a creative way of factorizing 31 using integer overflow.} -\label{primesat} -\end{figure*} - -Often the opposite of the {\tt eval} command is needed, i.e. the circuits -output is given and we want to find the matching input signals. For small -circuits with only a few input bits this can be accomplished by trying all -possible input combinations, as it is done by the {\tt eval -table} command. -For larger circuits however, Yosys provides the {\tt sat} command that uses -a SAT \cite{CircuitSAT} solver \cite{MiniSAT} to solve this kind of problems. - -The {\tt sat} command works very similar to the {\tt eval} command. The main -difference is that it is now also possible to set output values and find the -corresponding input values. For Example: - -{\scriptsize -\begin{verbatim} - yosys [selstage]> sat -show s1,s2,d -set s1 s2 -set n2,n1 4'b1001 - - 11. Executing SAT pass (solving SAT problems in the circuit). - Full command line: sat -show s1,s2,d -set s1 s2 -set n2,n1 4'b1001 - - Setting up SAT problem: - Import set-constraint: \s1 = \s2 - Import set-constraint: { \n2 \n1 } = 4'1001 - Final constraint equation: { \n2 \n1 \s1 } = { 4'1001 \s2 } - Imported 3 cells to SAT database. - Import show expression: { \s1 \s2 \d } - - Solving problem with 81 variables and 207 clauses.. - SAT solving finished - model found: - - Signal Name Dec Hex Bin - -------------------- ---------- ---------- --------------- - \d 9 9 1001 - \s1 0 0 00 - \s2 0 0 00 -\end{verbatim} -} - -Note that the {\tt sat} command supports signal names in both arguments -to the {\tt -set} option. In the above example we used {\tt -set s1 s2} -to constraint {\tt s1} and {\tt s2} to be equal. When more complex -constraints are needed, a wrapper circuit must be constructed that -checks the constraints and signals if the constraint was met using an -extra output port, which then can be forced to a value using the {\tt --set} option. (Such a circuit that contains the circuit under test -plus additional constraint checking circuitry is called a {\it miter\/} -circuit.) - -Fig.~\ref{primetest} shows a miter circuit that is supposed to be used as a -prime number test. If {\tt ok} is 1 for all input values {\tt a} and {\tt b} -for a given {\tt p}, then {\tt p} is prime, or at least that is the idea. - -The Yosys shell session shown in Fig.~\ref{primesat} demonstrates that SAT -solvers can even find the unexpected solutions to a problem: Using integer -overflow there actually is a way of ``factorizing'' 31. The clean solution -would of course be to perform the test in 32 bits, for example by replacing -{\tt p != a*b} in the miter with {\tt p != \{16'd0,a\}*b}, or by using a -temporary variable for the 32 bit product {\tt a*b}. But as 31 fits well into -8 bits (and as the purpose of this document is to show off Yosys features) -we can also simply force the upper 8 bits of {\tt a} and {\tt b} to zero for -the {\tt sat} call, as is done in the second command in Fig.~\ref{primesat} -(line 31). - -The {\tt -prove} option used in this example works similar to {\tt -set}, but -tries to find a case in which the two arguments are not equal. If such a case is -not found, the property is proven to hold for all inputs that satisfy the other -constraints. - -It might be worth noting, that SAT solvers are not particularly efficient at -factorizing large numbers. But if a small factorization problem occurs as -part of a larger circuit problem, the Yosys SAT solver is perfectly capable -of solving it. - -\subsection{Solving sequential SAT problems} - -\begin{figure}[t!] -\begin{lstlisting}[basicstyle=\ttfamily\scriptsize] -yosys [memdemo]> sat -seq 6 -show y -show d -set-init-undef \ - -max_undef -set-at 4 y 1 -set-at 5 y 2 -set-at 6 y 3 - -6. Executing SAT pass (solving SAT problems in the circuit). -Full command line: sat -seq 6 -show y -show d -set-init-undef - -max_undef -set-at 4 y 1 -set-at 5 y 2 -set-at 6 y 3 - -Setting up time step 1: -Final constraint equation: { } = { } -Imported 29 cells to SAT database. - -Setting up time step 2: -Final constraint equation: { } = { } -Imported 29 cells to SAT database. - -Setting up time step 3: -Final constraint equation: { } = { } -Imported 29 cells to SAT database. - -Setting up time step 4: -Import set-constraint for timestep: \y = 4'0001 -Final constraint equation: \y = 4'0001 -Imported 29 cells to SAT database. - -Setting up time step 5: -Import set-constraint for timestep: \y = 4'0010 -Final constraint equation: \y = 4'0010 -Imported 29 cells to SAT database. - -Setting up time step 6: -Import set-constraint for timestep: \y = 4'0011 -Final constraint equation: \y = 4'0011 -Imported 29 cells to SAT database. - -Setting up initial state: -Final constraint equation: { \y \s2 \s1 \mem[3] \mem[2] \mem[1] - \mem[0] } = 24'xxxxxxxxxxxxxxxxxxxxxxxx - -Import show expression: \y -Import show expression: \d - -Solving problem with 10322 variables and 27881 clauses.. -SAT model found. maximizing number of undefs. -SAT solving finished - model found: - - Time Signal Name Dec Hex Bin - ---- -------------------- ---------- ---------- --------------- - init \mem[0] -- -- xxxx - init \mem[1] -- -- xxxx - init \mem[2] -- -- xxxx - init \mem[3] -- -- xxxx - init \s1 -- -- xx - init \s2 -- -- xx - init \y -- -- xxxx - ---- -------------------- ---------- ---------- --------------- - 1 \d 0 0 0000 - 1 \y -- -- xxxx - ---- -------------------- ---------- ---------- --------------- - 2 \d 1 1 0001 - 2 \y -- -- xxxx - ---- -------------------- ---------- ---------- --------------- - 3 \d 2 2 0010 - 3 \y 0 0 0000 - ---- -------------------- ---------- ---------- --------------- - 4 \d 3 3 0011 - 4 \y 1 1 0001 - ---- -------------------- ---------- ---------- --------------- - 5 \d -- -- 001x - 5 \y 2 2 0010 - ---- -------------------- ---------- ---------- --------------- - 6 \d -- -- xxxx - 6 \y 3 3 0011 -\end{lstlisting} -\caption{Solving a sequential SAT problem in the {\tt memdemo} module from Fig.~\ref{memdemo_src}.} -\label{memdemo_sat} -\end{figure} - -The SAT solver functionality in Yosys can not only be used to solve -combinatorial problems, but can also solve sequential problems. Let's consider -the entire {\tt memdemo} module from Fig.~\ref{memdemo_src} and suppose we -want to know which sequence of input values for {\tt d} will cause the output -{\tt y} to produce the sequence 1, 2, 3 from any initial state. -Fig.~\ref{memdemo_sat} show the solution to this question, as produced by -the following command: - -\begin{verbatim} - sat -seq 6 -show y -show d -set-init-undef \ - -max_undef -set-at 4 y 1 -set-at 5 y 2 -set-at 6 y 3 -\end{verbatim} - -The {\tt -seq 6} option instructs the {\tt sat} command to solve a sequential -problem in 6 time steps. (Experiments with lower number of steps have show that -at least 3 cycles are necessary to bring the circuit in a state from which -the sequence 1, 2, 3 can be produced.) - -The {\tt -set-init-undef} option tells the {\tt sat} command to initialize -all registers to the undef ({\tt x}) state. The way the {\tt x} state -is treated in Verilog will ensure that the solution will work for any -initial state. - -The {\tt -max\_undef} option instructs the {\tt sat} command to find a solution -with a maximum number of undefs. This way we can see clearly which inputs bits -are relevant to the solution. - -Finally the three {\tt -set-at} options add constraints for the {\tt y} -signal to play the 1, 2, 3 sequence, starting with time step 4. - -It is not surprising that the solution sets {\tt d = 0} in the first step, as -this is the only way of setting the {\tt s1} and {\tt s2} registers to a known -value. The input values for the other steps are a bit harder to work out -manually, but the SAT solver finds the correct solution in an instant. - -\medskip - -There is much more to write about the {\tt sat} command. For example, there is -a set of options that can be used to performs sequential proofs using temporal -induction \cite{tip}. The command {\tt help sat} can be used to print a list -of all options with short descriptions of their functions. - -\section{Conclusion} -\label{conclusion} - -Yosys provides a wide range of functions to analyze and investigate designs. For -many cases it is sufficient to simply display circuit diagrams, maybe use some -additional commands to narrow the scope of the circuit diagrams to the interesting -parts of the circuit. But some cases require more than that. For this applications -Yosys provides commands that can be used to further inspect the behavior of the -circuit, either by evaluating which output values are generated from certain input values -({\tt eval}) or by evaluation which input values and initial conditions can result -in a certain behavior at the outputs ({\tt sat}). The SAT command can even be used -to prove (or disprove) theorems regarding the circuit, in more advanced cases -with the additional help of a miter circuit. - -This features can be powerful tools for the circuit designer using Yosys as a -utility for building circuits and the software developer using Yosys as a -framework for new algorithms alike. - -\begin{thebibliography}{9} - -\bibitem{yosys} -Clifford Wolf. The Yosys Open SYnthesis Suite. -\url{http://www.clifford.at/yosys/} - -\bibitem{graphviz} -Graphviz - Graph Visualization Software. -\url{http://www.graphviz.org/} - -\bibitem{xdot} -xdot.py - an interactive viewer for graphs written in Graphviz's dot language. -\url{https://github.com/jrfonseca/xdot.py} - -\bibitem{CircuitSAT} -{\it Circuit satisfiability problem} on Wikipedia -\url{http://en.wikipedia.org/wiki/Circuit_satisfiability} - -\bibitem{MiniSAT} -MiniSat: a minimalistic open-source SAT solver. -\url{http://minisat.se/} - -\bibitem{tip} -Niklas Een and Niklas S\"orensson (2003). -Temporal Induction by Incremental SAT Solving. -\url{http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.8161} - -\end{thebibliography} - -\end{document} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/cmos.v b/yosys/manual/APPNOTE_011_Design_Investigation/cmos.v deleted file mode 100644 index 2912c760a..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/cmos.v +++ /dev/null @@ -1,3 +0,0 @@ -module cmos_demo(input a, b, output [1:0] y); -assign y = a + b; -endmodule diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/cmos_00.dot b/yosys/manual/APPNOTE_011_Design_Investigation/cmos_00.dot deleted file mode 100644 index 49c630080..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/cmos_00.dot +++ /dev/null @@ -1,34 +0,0 @@ -digraph "cmos_demo" { -rankdir="LR"; -remincross=true; -n4 [ shape=octagon, label="a", color="black", fontcolor="black" ]; -n5 [ shape=octagon, label="b", color="black", fontcolor="black" ]; -n6 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -c10 [ shape=record, label="{{ A| B| Y}|$g0\nNOR|{}}" ]; -c11 [ shape=record, label="{{ A| Y}|$g1\nNOT|{}}" ]; -c12 [ shape=record, label="{{ A| Y}|$g2\nNOT|{}}" ]; -c13 [ shape=record, label="{{ A| B| Y}|$g3\nNOR|{}}" ]; -x0 [ shape=record, style=rounded, label=" 1:1 - 0:0 " ]; -x0:e -> c13:p9:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -c14 [ shape=record, label="{{ A| B| Y}|$g4\nNOR|{}}" ]; -x1 [ shape=record, style=rounded, label=" 1:1 - 0:0 " ]; -x1:e -> c14:p8:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -x2 [ shape=record, style=rounded, label=" 0:0 - 0:0 " ]; -x2:e -> c14:p9:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -n1 [ shape=diamond, label="$n4" ]; -n1:e -> c10:p9:w [color="black", label=""]; -n1:e -> c14:p7:w [color="black", label=""]; -n2 [ shape=diamond, label="$n5" ]; -n2:e -> c11:p9:w [color="black", label=""]; -n2:e -> c13:p7:w [color="black", label=""]; -n3 [ shape=diamond, label="$n6_1" ]; -n3:e -> c12:p9:w [color="black", label=""]; -n3:e -> c13:p8:w [color="black", label=""]; -n4:e -> c10:p8:w [color="black", label=""]; -n4:e -> c12:p7:w [color="black", label=""]; -n5:e -> c10:p7:w [color="black", label=""]; -n5:e -> c11:p7:w [color="black", label=""]; -n6:e -> x0:s0:w [color="black", label=""]; -n6:e -> x1:s0:w [color="black", label=""]; -n6:e -> x2:s0:w [color="black", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/cmos_01.dot b/yosys/manual/APPNOTE_011_Design_Investigation/cmos_01.dot deleted file mode 100644 index ea6f4403c..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/cmos_01.dot +++ /dev/null @@ -1,23 +0,0 @@ -digraph "cmos_demo" { -rankdir="LR"; -remincross=true; -n4 [ shape=octagon, label="a", color="black", fontcolor="black" ]; -n5 [ shape=octagon, label="b", color="black", fontcolor="black" ]; -n6 [ shape=octagon, label="y[0]", color="black", fontcolor="black" ]; -n7 [ shape=octagon, label="y[1]", color="black", fontcolor="black" ]; -c11 [ shape=record, label="{{ A| B}|$g0\nNOR|{ Y}}" ]; -c12 [ shape=record, label="{{ A}|$g1\nNOT|{ Y}}" ]; -c13 [ shape=record, label="{{ A}|$g2\nNOT|{ Y}}" ]; -c14 [ shape=record, label="{{ A| B}|$g3\nNOR|{ Y}}" ]; -c15 [ shape=record, label="{{ A| B}|$g4\nNOR|{ Y}}" ]; -c11:p10:e -> c15:p8:w [color="black", label=""]; -c12:p10:e -> c14:p8:w [color="black", label=""]; -c13:p10:e -> c14:p9:w [color="black", label=""]; -n4:e -> c11:p9:w [color="black", label=""]; -n4:e -> c13:p8:w [color="black", label=""]; -n5:e -> c11:p8:w [color="black", label=""]; -n5:e -> c12:p8:w [color="black", label=""]; -c15:p10:e -> n6:w [color="black", label=""]; -c14:p10:e -> n7:w [color="black", label=""]; -n7:e -> c15:p9:w [color="black", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/example.v b/yosys/manual/APPNOTE_011_Design_Investigation/example.v deleted file mode 100644 index 8c71989b3..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/example.v +++ /dev/null @@ -1,6 +0,0 @@ -module example(input clk, a, b, c, - output reg [1:0] y); - always @(posedge clk) - if (c) - y <= c ? a + b : 2'd0; -endmodule diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/example.ys b/yosys/manual/APPNOTE_011_Design_Investigation/example.ys deleted file mode 100644 index b1e956088..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/example.ys +++ /dev/null @@ -1,11 +0,0 @@ -read_verilog example.v -show -format dot -prefix example_00 -proc -show -format dot -prefix example_01 -opt -show -format dot -prefix example_02 - -cd example -select t:$add -show -format dot -prefix example_03 - diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/example_00.dot b/yosys/manual/APPNOTE_011_Design_Investigation/example_00.dot deleted file mode 100644 index 1e23ed0ea..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/example_00.dot +++ /dev/null @@ -1,23 +0,0 @@ -digraph "example" { -rankdir="LR"; -remincross=true; -n4 [ shape=octagon, label="a", color="black", fontcolor="black" ]; -n5 [ shape=octagon, label="b", color="black", fontcolor="black" ]; -n6 [ shape=octagon, label="c", color="black", fontcolor="black" ]; -n7 [ shape=octagon, label="clk", color="black", fontcolor="black" ]; -n8 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -c12 [ shape=record, label="{{ A| B}|$2\n$add|{ Y}}" ]; -v0 [ label="2'00" ]; -c14 [ shape=record, label="{{ A| B| S}|$3\n$mux|{ Y}}" ]; -p1 [shape=box, style=rounded, label="PROC $1\nexample.v:3"]; -c12:p11:e -> c14:p10:w [color="black", style="setlinewidth(3)", label=""]; -c14:p11:e -> p1:w [color="black", style="setlinewidth(3)", label=""]; -n4:e -> c12:p9:w [color="black", label=""]; -n5:e -> c12:p10:w [color="black", label=""]; -n6:e -> c14:p13:w [color="black", label=""]; -n6:e -> p1:w [color="black", label=""]; -n7:e -> p1:w [color="black", label=""]; -p1:e -> n8:w [color="black", style="setlinewidth(3)", label=""]; -n8:e -> p1:w [color="black", style="setlinewidth(3)", label=""]; -v0:e -> c14:p9:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/example_01.dot b/yosys/manual/APPNOTE_011_Design_Investigation/example_01.dot deleted file mode 100644 index e89292b51..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/example_01.dot +++ /dev/null @@ -1,33 +0,0 @@ -digraph "example" { -rankdir="LR"; -remincross=true; -n6 [ shape=octagon, label="a", color="black", fontcolor="black" ]; -n7 [ shape=octagon, label="b", color="black", fontcolor="black" ]; -n8 [ shape=octagon, label="c", color="black", fontcolor="black" ]; -n9 [ shape=octagon, label="clk", color="black", fontcolor="black" ]; -n10 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -c14 [ shape=record, label="{{ A| B}|$2\n$add|{ Y}}" ]; -c18 [ shape=record, label="{{ CLK| D}|$7\n$dff|{ Q}}" ]; -c20 [ shape=record, label="{{ A| B| S}|$5\n$mux|{ Y}}" ]; -v0 [ label="2'00" ]; -c21 [ shape=record, label="{{ A| B| S}|$3\n$mux|{ Y}}" ]; -x1 [shape=box, style=rounded, label="BUF"]; -x2 [shape=box, style=rounded, label="BUF"]; -n1 [ shape=diamond, label="$0\\y[1:0]" ]; -x2:e:e -> n1:w [color="black", style="setlinewidth(3)", label=""]; -c18:p17:e -> n10:w [color="black", style="setlinewidth(3)", label=""]; -n10:e -> c20:p11:w [color="black", style="setlinewidth(3)", label=""]; -c14:p13:e -> c21:p12:w [color="black", style="setlinewidth(3)", label=""]; -n3 [ shape=point ]; -c20:p13:e -> n3:w [color="black", style="setlinewidth(3)", label=""]; -n3:e -> c18:p16:w [color="black", style="setlinewidth(3)", label=""]; -n3:e -> x2:w:w [color="black", style="setlinewidth(3)", label=""]; -x1:e:e -> c20:p19:w [color="black", label=""]; -c21:p13:e -> c20:p12:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> c14:p11:w [color="black", label=""]; -n7:e -> c14:p12:w [color="black", label=""]; -n8:e -> c21:p19:w [color="black", label=""]; -n8:e -> x1:w:w [color="black", label=""]; -n9:e -> c18:p15:w [color="black", label=""]; -v0:e -> c21:p11:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/example_02.dot b/yosys/manual/APPNOTE_011_Design_Investigation/example_02.dot deleted file mode 100644 index f950ed2ed..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/example_02.dot +++ /dev/null @@ -1,20 +0,0 @@ -digraph "example" { -rankdir="LR"; -remincross=true; -n3 [ shape=octagon, label="a", color="black", fontcolor="black" ]; -n4 [ shape=octagon, label="b", color="black", fontcolor="black" ]; -n5 [ shape=octagon, label="c", color="black", fontcolor="black" ]; -n6 [ shape=octagon, label="clk", color="black", fontcolor="black" ]; -n7 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -c11 [ shape=record, label="{{ A| B}|$2\n$add|{ Y}}" ]; -c15 [ shape=record, label="{{ CLK| D}|$7\n$dff|{ Q}}" ]; -c17 [ shape=record, label="{{ A| B| S}|$5\n$mux|{ Y}}" ]; -c17:p10:e -> c15:p13:w [color="black", style="setlinewidth(3)", label=""]; -c11:p10:e -> c17:p9:w [color="black", style="setlinewidth(3)", label=""]; -n3:e -> c11:p8:w [color="black", label=""]; -n4:e -> c11:p9:w [color="black", label=""]; -n5:e -> c17:p16:w [color="black", label=""]; -n6:e -> c15:p12:w [color="black", label=""]; -c15:p14:e -> n7:w [color="black", style="setlinewidth(3)", label=""]; -n7:e -> c17:p8:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/example_03.dot b/yosys/manual/APPNOTE_011_Design_Investigation/example_03.dot deleted file mode 100644 index e19d24af7..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/example_03.dot +++ /dev/null @@ -1,11 +0,0 @@ -digraph "example" { -rankdir="LR"; -remincross=true; -v0 [ label="a" ]; -v1 [ label="b" ]; -v2 [ label="$2_Y" ]; -c4 [ shape=record, label="{{ A| B}|$2\n$add|{ Y}}" ]; -v0:e -> c4:p1:w [color="black", label=""]; -v1:e -> c4:p2:w [color="black", label=""]; -c4:p3:e -> v2:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/foobaraddsub.v b/yosys/manual/APPNOTE_011_Design_Investigation/foobaraddsub.v deleted file mode 100644 index 0f277211d..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/foobaraddsub.v +++ /dev/null @@ -1,8 +0,0 @@ -module foobaraddsub(a, b, c, d, fa, fs, ba, bs); - input [7:0] a, b, c, d; - output [7:0] fa, fs, ba, bs; - assign fa = a + (* foo *) b; - assign fs = a - (* foo *) b; - assign ba = c + (* bar *) d; - assign bs = c - (* bar *) d; -endmodule diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/make.sh b/yosys/manual/APPNOTE_011_Design_Investigation/make.sh deleted file mode 100644 index 3845dac6b..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/make.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -set -ex -if false; then - rm -f *.dot - ../../yosys example.ys - ../../yosys -p 'proc; opt; show -format dot -prefix splice' splice.v - ../../yosys -p 'techmap; abc -liberty ../../techlibs/cmos/cmos_cells.lib;; show -format dot -prefix cmos_00' cmos.v - ../../yosys -p 'techmap; splitnets -ports; abc -liberty ../../techlibs/cmos/cmos_cells.lib;; show -lib ../../techlibs/cmos/cmos_cells.v -format dot -prefix cmos_01' cmos.v - ../../yosys -p 'opt; cd sumprod; select a:sumstuff; show -format dot -prefix sumprod_00' sumprod.v - ../../yosys -p 'opt; cd sumprod; select a:sumstuff %x; show -format dot -prefix sumprod_01' sumprod.v - ../../yosys -p 'opt; cd sumprod; select prod; show -format dot -prefix sumprod_02' sumprod.v - ../../yosys -p 'opt; cd sumprod; select prod %ci; show -format dot -prefix sumprod_03' sumprod.v - ../../yosys -p 'opt; cd sumprod; select prod %ci2; show -format dot -prefix sumprod_04' sumprod.v - ../../yosys -p 'opt; cd sumprod; select prod %ci3; show -format dot -prefix sumprod_05' sumprod.v - ../../yosys -p 'proc; opt; memory; opt; cd memdemo; show -format dot -prefix memdemo_00' memdemo.v - ../../yosys -p 'proc; opt; memory; opt; cd memdemo; show -format dot -prefix memdemo_01 y %ci2:+$dff[Q,D] %ci*:-$mux[S]:-$dff' memdemo.v - ../../yosys submod.ys - sed -i '/^label=/ d;' *.dot -fi -for dot_file in *.dot; do - pdf_file=${dot_file%.dot}.pdf - dot -Tpdf -o $pdf_file $dot_file -done diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/memdemo.v b/yosys/manual/APPNOTE_011_Design_Investigation/memdemo.v deleted file mode 100644 index b39564ddc..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/memdemo.v +++ /dev/null @@ -1,19 +0,0 @@ -module memdemo(clk, d, y); - -input clk; -input [3:0] d; -output reg [3:0] y; - -integer i; -reg [1:0] s1, s2; -reg [3:0] mem [0:3]; - -always @(posedge clk) begin - for (i = 0; i < 4; i = i+1) - mem[i] <= mem[(i+1) % 4] + mem[(i+2) % 4]; - { s2, s1 } = d ? { s1, s2 } ^ d : 4'b0; - mem[s1] <= d; - y <= mem[s2]; -end - -endmodule diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/memdemo_00.dot b/yosys/manual/APPNOTE_011_Design_Investigation/memdemo_00.dot deleted file mode 100644 index 0336a9aac..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/memdemo_00.dot +++ /dev/null @@ -1,138 +0,0 @@ -digraph "memdemo" { -rankdir="LR"; -remincross=true; -n24 [ shape=octagon, label="clk", color="black", fontcolor="black" ]; -n25 [ shape=octagon, label="d", color="black", fontcolor="black" ]; -n26 [ shape=diamond, label="mem[0]", color="black", fontcolor="black" ]; -n27 [ shape=diamond, label="mem[1]", color="black", fontcolor="black" ]; -n28 [ shape=diamond, label="mem[2]", color="black", fontcolor="black" ]; -n29 [ shape=diamond, label="mem[3]", color="black", fontcolor="black" ]; -n30 [ shape=diamond, label="s1", color="black", fontcolor="black" ]; -n31 [ shape=diamond, label="s2", color="black", fontcolor="black" ]; -n32 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -c36 [ shape=record, label="{{ A| B}|$28\n$add|{ Y}}" ]; -c37 [ shape=record, label="{{ A| B}|$31\n$add|{ Y}}" ]; -c38 [ shape=record, label="{{ A| B}|$34\n$add|{ Y}}" ]; -c39 [ shape=record, label="{{ A| B}|$37\n$add|{ Y}}" ]; -c41 [ shape=record, label="{{ A| B| S}|$110\n$mux|{ Y}}" ]; -x0 [ shape=record, style=rounded, label=" 1:1 - 0:0 " ]; -x0:e -> c41:p40:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -c42 [ shape=record, label="{{ A| B| S}|$113\n$mux|{ Y}}" ]; -x1 [ shape=record, style=rounded, label=" 0:0 - 0:0 " ]; -x1:e -> c42:p40:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -c43 [ shape=record, label="{{ A| B| S}|$116\n$mux|{ Y}}" ]; -x2 [ shape=record, style=rounded, label=" 0:0 - 0:0 " ]; -x2:e -> c43:p40:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -v3 [ label="1'1" ]; -c44 [ shape=record, label="{{ A| B}|$145\n$and|{ Y}}" ]; -v4 [ label="1'1" ]; -c45 [ shape=record, label="{{ A| B}|$175\n$and|{ Y}}" ]; -v5 [ label="1'1" ]; -c46 [ shape=record, label="{{ A| B}|$205\n$and|{ Y}}" ]; -v6 [ label="1'1" ]; -c47 [ shape=record, label="{{ A| B}|$235\n$and|{ Y}}" ]; -v7 [ label="2'00" ]; -c48 [ shape=record, label="{{ A| B}|$143\n$eq|{ Y}}" ]; -v8 [ label="2'01" ]; -c49 [ shape=record, label="{{ A| B}|$173\n$eq|{ Y}}" ]; -v9 [ label="2'10" ]; -c50 [ shape=record, label="{{ A| B}|$203\n$eq|{ Y}}" ]; -v10 [ label="2'11" ]; -c51 [ shape=record, label="{{ A| B}|$233\n$eq|{ Y}}" ]; -c52 [ shape=record, label="{{ A| B| S}|$147\n$mux|{ Y}}" ]; -c53 [ shape=record, label="{{ A| B| S}|$177\n$mux|{ Y}}" ]; -c54 [ shape=record, label="{{ A| B| S}|$207\n$mux|{ Y}}" ]; -c55 [ shape=record, label="{{ A| B| S}|$237\n$mux|{ Y}}" ]; -c59 [ shape=record, label="{{ CLK| D}|$66\n$dff|{ Q}}" ]; -c60 [ shape=record, label="{{ CLK| D}|$68\n$dff|{ Q}}" ]; -c61 [ shape=record, label="{{ CLK| D}|$70\n$dff|{ Q}}" ]; -c62 [ shape=record, label="{{ CLK| D}|$72\n$dff|{ Q}}" ]; -c63 [ shape=record, label="{{ CLK| D}|$59\n$dff|{ Q}}" ]; -c64 [ shape=record, label="{{ CLK| D}|$63\n$dff|{ Q}}" ]; -c65 [ shape=record, label="{{ CLK| D}|$64\n$dff|{ Q}}" ]; -c66 [ shape=record, label="{{ A}|$39\n$reduce_bool|{ Y}}" ]; -v11 [ label="4'0000" ]; -c67 [ shape=record, label="{{ A| B| S}|$40\n$mux|{ Y}}" ]; -x12 [ shape=record, style=rounded, label=" 3:2 - 1:0 | 1:0 - 1:0 " ]; -c67:p35:e -> x12:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -c68 [ shape=record, label="{{ A| B}|$38\n$xor|{ Y}}" ]; -x13 [ shape=record, style=rounded, label=" 1:0 - 3:2 | 1:0 - 1:0 " ]; -x13:e -> c68:p33:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -c36:p35:e -> c52:p33:w [color="black", style="setlinewidth(3)", label=""]; -c44:p35:e -> c52:p40:w [color="black", label=""]; -c45:p35:e -> c53:p40:w [color="black", label=""]; -c46:p35:e -> c54:p40:w [color="black", label=""]; -c47:p35:e -> c55:p40:w [color="black", label=""]; -c48:p35:e -> c44:p33:w [color="black", label=""]; -c49:p35:e -> c45:p33:w [color="black", label=""]; -c50:p35:e -> c46:p33:w [color="black", label=""]; -c51:p35:e -> c47:p33:w [color="black", label=""]; -c52:p35:e -> c59:p57:w [color="black", style="setlinewidth(3)", label=""]; -c53:p35:e -> c60:p57:w [color="black", style="setlinewidth(3)", label=""]; -c37:p35:e -> c53:p33:w [color="black", style="setlinewidth(3)", label=""]; -c54:p35:e -> c61:p57:w [color="black", style="setlinewidth(3)", label=""]; -c55:p35:e -> c62:p57:w [color="black", style="setlinewidth(3)", label=""]; -c66:p35:e -> c67:p40:w [color="black", label=""]; -c68:p35:e -> c67:p34:w [color="black", style="setlinewidth(3)", label=""]; -n24:e -> c59:p56:w [color="black", label=""]; -n24:e -> c60:p56:w [color="black", label=""]; -n24:e -> c61:p56:w [color="black", label=""]; -n24:e -> c62:p56:w [color="black", label=""]; -n24:e -> c63:p56:w [color="black", label=""]; -n24:e -> c64:p56:w [color="black", label=""]; -n24:e -> c65:p56:w [color="black", label=""]; -n25:e -> c52:p34:w [color="black", style="setlinewidth(3)", label=""]; -n25:e -> c53:p34:w [color="black", style="setlinewidth(3)", label=""]; -n25:e -> c54:p34:w [color="black", style="setlinewidth(3)", label=""]; -n25:e -> c55:p34:w [color="black", style="setlinewidth(3)", label=""]; -n25:e -> c66:p33:w [color="black", style="setlinewidth(3)", label=""]; -n25:e -> c68:p34:w [color="black", style="setlinewidth(3)", label=""]; -c59:p58:e -> n26:w [color="black", style="setlinewidth(3)", label=""]; -n26:e -> c38:p34:w [color="black", style="setlinewidth(3)", label=""]; -n26:e -> c39:p33:w [color="black", style="setlinewidth(3)", label=""]; -n26:e -> c42:p33:w [color="black", style="setlinewidth(3)", label=""]; -c60:p58:e -> n27:w [color="black", style="setlinewidth(3)", label=""]; -n27:e -> c36:p33:w [color="black", style="setlinewidth(3)", label=""]; -n27:e -> c39:p34:w [color="black", style="setlinewidth(3)", label=""]; -n27:e -> c42:p34:w [color="black", style="setlinewidth(3)", label=""]; -c61:p58:e -> n28:w [color="black", style="setlinewidth(3)", label=""]; -n28:e -> c36:p34:w [color="black", style="setlinewidth(3)", label=""]; -n28:e -> c37:p33:w [color="black", style="setlinewidth(3)", label=""]; -n28:e -> c43:p33:w [color="black", style="setlinewidth(3)", label=""]; -c62:p58:e -> n29:w [color="black", style="setlinewidth(3)", label=""]; -n29:e -> c37:p34:w [color="black", style="setlinewidth(3)", label=""]; -n29:e -> c38:p33:w [color="black", style="setlinewidth(3)", label=""]; -n29:e -> c43:p34:w [color="black", style="setlinewidth(3)", label=""]; -c38:p35:e -> c54:p33:w [color="black", style="setlinewidth(3)", label=""]; -c63:p58:e -> n30:w [color="black", style="setlinewidth(3)", label=""]; -n30:e -> x13:s1:w [color="black", style="setlinewidth(3)", label=""]; -c64:p58:e -> n31:w [color="black", style="setlinewidth(3)", label=""]; -n31:e -> x13:s0:w [color="black", style="setlinewidth(3)", label=""]; -c65:p58:e -> n32:w [color="black", style="setlinewidth(3)", label=""]; -c39:p35:e -> c55:p33:w [color="black", style="setlinewidth(3)", label=""]; -n5 [ shape=point ]; -x12:s0:e -> n5:w [color="black", style="setlinewidth(3)", label=""]; -n5:e -> c48:p34:w [color="black", style="setlinewidth(3)", label=""]; -n5:e -> c49:p34:w [color="black", style="setlinewidth(3)", label=""]; -n5:e -> c50:p34:w [color="black", style="setlinewidth(3)", label=""]; -n5:e -> c51:p34:w [color="black", style="setlinewidth(3)", label=""]; -n5:e -> c63:p57:w [color="black", style="setlinewidth(3)", label=""]; -n6 [ shape=point ]; -x12:s1:e -> n6:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> c64:p57:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> x0:s0:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> x1:s0:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> x2:s0:w [color="black", style="setlinewidth(3)", label=""]; -c41:p35:e -> c65:p57:w [color="black", style="setlinewidth(3)", label=""]; -c42:p35:e -> c41:p33:w [color="black", style="setlinewidth(3)", label=""]; -c43:p35:e -> c41:p34:w [color="black", style="setlinewidth(3)", label=""]; -v10:e -> c51:p33:w [color="black", style="setlinewidth(3)", label=""]; -v11:e -> c67:p33:w [color="black", style="setlinewidth(3)", label=""]; -v3:e -> c44:p34:w [color="black", label=""]; -v4:e -> c45:p34:w [color="black", label=""]; -v5:e -> c46:p34:w [color="black", label=""]; -v6:e -> c47:p34:w [color="black", label=""]; -v7:e -> c48:p33:w [color="black", style="setlinewidth(3)", label=""]; -v8:e -> c49:p33:w [color="black", style="setlinewidth(3)", label=""]; -v9:e -> c50:p33:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/memdemo_01.dot b/yosys/manual/APPNOTE_011_Design_Investigation/memdemo_01.dot deleted file mode 100644 index 2ad92c78b..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/memdemo_01.dot +++ /dev/null @@ -1,29 +0,0 @@ -digraph "memdemo" { -rankdir="LR"; -remincross=true; -n4 [ shape=diamond, label="mem[0]", color="black", fontcolor="black" ]; -n5 [ shape=diamond, label="mem[1]", color="black", fontcolor="black" ]; -n6 [ shape=diamond, label="mem[2]", color="black", fontcolor="black" ]; -n7 [ shape=diamond, label="mem[3]", color="black", fontcolor="black" ]; -n8 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -v0 [ label="$0\\s2[1:0] [1]" ]; -c13 [ shape=record, label="{{ A| B| S}|$110\n$mux|{ Y}}" ]; -v1 [ label="$0\\s2[1:0] [0]" ]; -c14 [ shape=record, label="{{ A| B| S}|$113\n$mux|{ Y}}" ]; -v2 [ label="$0\\s2[1:0] [0]" ]; -c15 [ shape=record, label="{{ A| B| S}|$116\n$mux|{ Y}}" ]; -v3 [ label="clk" ]; -c19 [ shape=record, label="{{ CLK| D}|$64\n$dff|{ Q}}" ]; -c13:p12:e -> c19:p17:w [color="black", style="setlinewidth(3)", label=""]; -c14:p12:e -> c13:p9:w [color="black", style="setlinewidth(3)", label=""]; -c15:p12:e -> c13:p10:w [color="black", style="setlinewidth(3)", label=""]; -n4:e -> c14:p9:w [color="black", style="setlinewidth(3)", label=""]; -n5:e -> c14:p10:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> c15:p9:w [color="black", style="setlinewidth(3)", label=""]; -n7:e -> c15:p10:w [color="black", style="setlinewidth(3)", label=""]; -c19:p18:e -> n8:w [color="black", style="setlinewidth(3)", label=""]; -v0:e -> c13:p11:w [color="black", label=""]; -v1:e -> c14:p11:w [color="black", label=""]; -v2:e -> c15:p11:w [color="black", label=""]; -v3:e -> c19:p16:w [color="black", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/primetest.v b/yosys/manual/APPNOTE_011_Design_Investigation/primetest.v deleted file mode 100644 index 6cb766b73..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/primetest.v +++ /dev/null @@ -1,4 +0,0 @@ -module primetest(p, a, b, ok); -input [15:0] p, a, b; -output ok = p != a*b || a == 1 || b == 1; -endmodule diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/splice.dot b/yosys/manual/APPNOTE_011_Design_Investigation/splice.dot deleted file mode 100644 index 4657feed1..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/splice.dot +++ /dev/null @@ -1,39 +0,0 @@ -digraph "splice_demo" { -rankdir="LR"; -remincross=true; -n1 [ shape=octagon, label="a", color="black", fontcolor="black" ]; -n2 [ shape=octagon, label="b", color="black", fontcolor="black" ]; -n3 [ shape=octagon, label="c", color="black", fontcolor="black" ]; -n4 [ shape=octagon, label="d", color="black", fontcolor="black" ]; -n5 [ shape=octagon, label="e", color="black", fontcolor="black" ]; -n6 [ shape=octagon, label="f", color="black", fontcolor="black" ]; -n7 [ shape=octagon, label="x", color="black", fontcolor="black" ]; -n8 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -c11 [ shape=record, label="{{ A}|$2\n$neg|{ Y}}" ]; -x0 [ shape=record, style=rounded, label=" 1:0 - 3:2 | 1:0 - 1:0 " ]; -x0:e -> c11:p9:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -x1 [ shape=record, style=rounded, label=" 3:0 - 7:4 " ]; -c11:p10:e -> x1:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -c12 [ shape=record, label="{{ A}|$1\n$not|{ Y}}" ]; -x2 [ shape=record, style=rounded, label=" 1:0 - 3:2 | 1:0 - 1:0 " ]; -x2:e -> c12:p9:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -x3 [ shape=record, style=rounded, label=" 3:2 - 1:0 | 1:0 - 3:2 " ]; -c12:p10:e -> x3:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -x4 [ shape=record, style=rounded, label=" 0:0 - 1:1 | 1:1 - 0:0 " ]; -x5 [ shape=record, style=rounded, label=" 1:0 - 3:2 | 1:0 - 1:0 " ]; -x6 [ shape=record, style=rounded, label=" 3:0 - 11:8 " ]; -x5:e -> x6:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -n1:e -> x4:s0:w [color="black", style="setlinewidth(3)", label=""]; -n1:e -> x4:s1:w [color="black", style="setlinewidth(3)", label=""]; -n1:e -> x5:s1:w [color="black", style="setlinewidth(3)", label=""]; -n2:e -> x5:s0:w [color="black", style="setlinewidth(3)", label=""]; -n3:e -> x0:s1:w [color="black", style="setlinewidth(3)", label=""]; -n4:e -> x0:s0:w [color="black", style="setlinewidth(3)", label=""]; -n5:e -> x2:s1:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> x2:s0:w [color="black", style="setlinewidth(3)", label=""]; -x4:e -> n7:w [color="black", style="setlinewidth(3)", label=""]; -x1:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""]; -x3:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""]; -x3:s1:e -> n8:w [color="black", style="setlinewidth(3)", label=""]; -x6:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/splice.v b/yosys/manual/APPNOTE_011_Design_Investigation/splice.v deleted file mode 100644 index 1cf7274c0..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/splice.v +++ /dev/null @@ -1,10 +0,0 @@ -module splice_demo(a, b, c, d, e, f, x, y); - -input [1:0] a, b, c, d, e, f; -output [1:0] x = {a[0], a[1]}; - -output [11:0] y; -assign {y[11:4], y[1:0], y[3:2]} = - {a, b, -{c, d}, ~{e, f}}; - -endmodule diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/submod.ys b/yosys/manual/APPNOTE_011_Design_Investigation/submod.ys deleted file mode 100644 index 29ad61076..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/submod.ys +++ /dev/null @@ -1,16 +0,0 @@ -read_verilog memdemo.v -proc; opt; memory; opt - -cd memdemo -select -set outstage y %ci2:+$dff[Q,D] %ci*:-$mux[S]:-$dff -select -set selstage y %ci2:+$dff[Q,D] %ci*:-$dff @outstage %d -select -set scramble mem* %ci2 %ci*:-$dff mem* %d @selstage %d -submod -name scramble @scramble -submod -name outstage @outstage -submod -name selstage @selstage - -cd .. -show -format dot -prefix submod_00 memdemo -show -format dot -prefix submod_01 scramble -show -format dot -prefix submod_02 outstage -show -format dot -prefix submod_03 selstage diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/submod_00.dot b/yosys/manual/APPNOTE_011_Design_Investigation/submod_00.dot deleted file mode 100644 index 2e55268ee..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/submod_00.dot +++ /dev/null @@ -1,45 +0,0 @@ -digraph "memdemo" { -rankdir="LR"; -remincross=true; -n5 [ shape=octagon, label="clk", color="black", fontcolor="black" ]; -n6 [ shape=octagon, label="d", color="black", fontcolor="black" ]; -n7 [ shape=diamond, label="mem[0]", color="black", fontcolor="black" ]; -n8 [ shape=diamond, label="mem[1]", color="black", fontcolor="black" ]; -n9 [ shape=diamond, label="mem[2]", color="black", fontcolor="black" ]; -n10 [ shape=diamond, label="mem[3]", color="black", fontcolor="black" ]; -n11 [ shape=diamond, label="s1", color="black", fontcolor="black" ]; -n12 [ shape=diamond, label="s2", color="black", fontcolor="black" ]; -n13 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -c17 [ shape=record, label="{{ CLK| D}|$59\n$dff|{ Q}}" ]; -c18 [ shape=record, label="{{ CLK| D}|$63\n$dff|{ Q}}" ]; -c20 [ shape=record, label="{{ clk| mem[0]| mem[1]| mem[2]| mem[3]| n1}|outstage\noutstage|{ y}}" ]; -c21 [ shape=record, label="{{ clk| d| n1}|scramble\nscramble|{ mem[0]| mem[1]| mem[2]| mem[3]}}" ]; -c23 [ shape=record, label="{{ d| s1| s2}|selstage\nselstage|{ n1| n2}}" ]; -n1 [ shape=point ]; -c23:p19:e -> n1:w [color="black", style="setlinewidth(3)", label=""]; -n1:e -> c17:p15:w [color="black", style="setlinewidth(3)", label=""]; -n1:e -> c21:p19:w [color="black", style="setlinewidth(3)", label=""]; -c21:p10:e -> n10:w [color="black", style="setlinewidth(3)", label=""]; -n10:e -> c20:p10:w [color="black", style="setlinewidth(3)", label=""]; -c17:p16:e -> n11:w [color="black", style="setlinewidth(3)", label=""]; -n11:e -> c23:p11:w [color="black", style="setlinewidth(3)", label=""]; -c18:p16:e -> n12:w [color="black", style="setlinewidth(3)", label=""]; -n12:e -> c23:p12:w [color="black", style="setlinewidth(3)", label=""]; -c20:p13:e -> n13:w [color="black", style="setlinewidth(3)", label=""]; -n2 [ shape=point ]; -c23:p22:e -> n2:w [color="black", style="setlinewidth(3)", label=""]; -n2:e -> c18:p15:w [color="black", style="setlinewidth(3)", label=""]; -n2:e -> c20:p19:w [color="black", style="setlinewidth(3)", label=""]; -n5:e -> c17:p14:w [color="black", label=""]; -n5:e -> c18:p14:w [color="black", label=""]; -n5:e -> c20:p5:w [color="black", label=""]; -n5:e -> c21:p5:w [color="black", label=""]; -n6:e -> c21:p6:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> c23:p6:w [color="black", style="setlinewidth(3)", label=""]; -c21:p7:e -> n7:w [color="black", style="setlinewidth(3)", label=""]; -n7:e -> c20:p7:w [color="black", style="setlinewidth(3)", label=""]; -c21:p8:e -> n8:w [color="black", style="setlinewidth(3)", label=""]; -n8:e -> c20:p8:w [color="black", style="setlinewidth(3)", label=""]; -c21:p9:e -> n9:w [color="black", style="setlinewidth(3)", label=""]; -n9:e -> c20:p9:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/submod_01.dot b/yosys/manual/APPNOTE_011_Design_Investigation/submod_01.dot deleted file mode 100644 index f8f8c008a..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/submod_01.dot +++ /dev/null @@ -1,87 +0,0 @@ -digraph "scramble" { -rankdir="LR"; -remincross=true; -n17 [ shape=octagon, label="clk", color="black", fontcolor="black" ]; -n18 [ shape=octagon, label="d", color="black", fontcolor="black" ]; -n19 [ shape=octagon, label="mem[0]", color="black", fontcolor="black" ]; -n20 [ shape=octagon, label="mem[1]", color="black", fontcolor="black" ]; -n21 [ shape=octagon, label="mem[2]", color="black", fontcolor="black" ]; -n22 [ shape=octagon, label="mem[3]", color="black", fontcolor="black" ]; -n23 [ shape=octagon, label="n1", color="black", fontcolor="black" ]; -c27 [ shape=record, label="{{ A| B}|$28\n$add|{ Y}}" ]; -c28 [ shape=record, label="{{ A| B}|$31\n$add|{ Y}}" ]; -c29 [ shape=record, label="{{ A| B}|$34\n$add|{ Y}}" ]; -c30 [ shape=record, label="{{ A| B}|$37\n$add|{ Y}}" ]; -v0 [ label="1'1" ]; -c31 [ shape=record, label="{{ A| B}|$145\n$and|{ Y}}" ]; -v1 [ label="1'1" ]; -c32 [ shape=record, label="{{ A| B}|$175\n$and|{ Y}}" ]; -v2 [ label="1'1" ]; -c33 [ shape=record, label="{{ A| B}|$205\n$and|{ Y}}" ]; -v3 [ label="1'1" ]; -c34 [ shape=record, label="{{ A| B}|$235\n$and|{ Y}}" ]; -v4 [ label="2'00" ]; -c35 [ shape=record, label="{{ A| B}|$143\n$eq|{ Y}}" ]; -v5 [ label="2'01" ]; -c36 [ shape=record, label="{{ A| B}|$173\n$eq|{ Y}}" ]; -v6 [ label="2'10" ]; -c37 [ shape=record, label="{{ A| B}|$203\n$eq|{ Y}}" ]; -v7 [ label="2'11" ]; -c38 [ shape=record, label="{{ A| B}|$233\n$eq|{ Y}}" ]; -c40 [ shape=record, label="{{ A| B| S}|$147\n$mux|{ Y}}" ]; -c41 [ shape=record, label="{{ A| B| S}|$177\n$mux|{ Y}}" ]; -c42 [ shape=record, label="{{ A| B| S}|$207\n$mux|{ Y}}" ]; -c43 [ shape=record, label="{{ A| B| S}|$237\n$mux|{ Y}}" ]; -c47 [ shape=record, label="{{ CLK| D}|$66\n$dff|{ Q}}" ]; -c48 [ shape=record, label="{{ CLK| D}|$68\n$dff|{ Q}}" ]; -c49 [ shape=record, label="{{ CLK| D}|$70\n$dff|{ Q}}" ]; -c50 [ shape=record, label="{{ CLK| D}|$72\n$dff|{ Q}}" ]; -c27:p26:e -> c40:p24:w [color="black", style="setlinewidth(3)", label=""]; -c36:p26:e -> c32:p24:w [color="black", label=""]; -c37:p26:e -> c33:p24:w [color="black", label=""]; -c38:p26:e -> c34:p24:w [color="black", label=""]; -c40:p26:e -> c47:p45:w [color="black", style="setlinewidth(3)", label=""]; -c41:p26:e -> c48:p45:w [color="black", style="setlinewidth(3)", label=""]; -c42:p26:e -> c49:p45:w [color="black", style="setlinewidth(3)", label=""]; -c43:p26:e -> c50:p45:w [color="black", style="setlinewidth(3)", label=""]; -n17:e -> c47:p44:w [color="black", label=""]; -n17:e -> c48:p44:w [color="black", label=""]; -n17:e -> c49:p44:w [color="black", label=""]; -n17:e -> c50:p44:w [color="black", label=""]; -n18:e -> c40:p25:w [color="black", style="setlinewidth(3)", label=""]; -n18:e -> c41:p25:w [color="black", style="setlinewidth(3)", label=""]; -n18:e -> c42:p25:w [color="black", style="setlinewidth(3)", label=""]; -n18:e -> c43:p25:w [color="black", style="setlinewidth(3)", label=""]; -c47:p46:e -> n19:w [color="black", style="setlinewidth(3)", label=""]; -n19:e -> c29:p25:w [color="black", style="setlinewidth(3)", label=""]; -n19:e -> c30:p24:w [color="black", style="setlinewidth(3)", label=""]; -c28:p26:e -> c41:p24:w [color="black", style="setlinewidth(3)", label=""]; -c48:p46:e -> n20:w [color="black", style="setlinewidth(3)", label=""]; -n20:e -> c27:p24:w [color="black", style="setlinewidth(3)", label=""]; -n20:e -> c30:p25:w [color="black", style="setlinewidth(3)", label=""]; -c49:p46:e -> n21:w [color="black", style="setlinewidth(3)", label=""]; -n21:e -> c27:p25:w [color="black", style="setlinewidth(3)", label=""]; -n21:e -> c28:p24:w [color="black", style="setlinewidth(3)", label=""]; -c50:p46:e -> n22:w [color="black", style="setlinewidth(3)", label=""]; -n22:e -> c28:p25:w [color="black", style="setlinewidth(3)", label=""]; -n22:e -> c29:p24:w [color="black", style="setlinewidth(3)", label=""]; -n23:e -> c35:p25:w [color="black", style="setlinewidth(3)", label=""]; -n23:e -> c36:p25:w [color="black", style="setlinewidth(3)", label=""]; -n23:e -> c37:p25:w [color="black", style="setlinewidth(3)", label=""]; -n23:e -> c38:p25:w [color="black", style="setlinewidth(3)", label=""]; -c29:p26:e -> c42:p24:w [color="black", style="setlinewidth(3)", label=""]; -c30:p26:e -> c43:p24:w [color="black", style="setlinewidth(3)", label=""]; -c31:p26:e -> c40:p39:w [color="black", label=""]; -c32:p26:e -> c41:p39:w [color="black", label=""]; -c33:p26:e -> c42:p39:w [color="black", label=""]; -c34:p26:e -> c43:p39:w [color="black", label=""]; -c35:p26:e -> c31:p24:w [color="black", label=""]; -v0:e -> c31:p25:w [color="black", label=""]; -v1:e -> c32:p25:w [color="black", label=""]; -v2:e -> c33:p25:w [color="black", label=""]; -v3:e -> c34:p25:w [color="black", label=""]; -v4:e -> c35:p24:w [color="black", style="setlinewidth(3)", label=""]; -v5:e -> c36:p24:w [color="black", style="setlinewidth(3)", label=""]; -v6:e -> c37:p24:w [color="black", style="setlinewidth(3)", label=""]; -v7:e -> c38:p24:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/submod_02.dot b/yosys/manual/APPNOTE_011_Design_Investigation/submod_02.dot deleted file mode 100644 index 1a672c484..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/submod_02.dot +++ /dev/null @@ -1,33 +0,0 @@ -digraph "outstage" { -rankdir="LR"; -remincross=true; -n4 [ shape=octagon, label="clk", color="black", fontcolor="black" ]; -n5 [ shape=octagon, label="mem[0]", color="black", fontcolor="black" ]; -n6 [ shape=octagon, label="mem[1]", color="black", fontcolor="black" ]; -n7 [ shape=octagon, label="mem[2]", color="black", fontcolor="black" ]; -n8 [ shape=octagon, label="mem[3]", color="black", fontcolor="black" ]; -n9 [ shape=octagon, label="n1", color="black", fontcolor="black" ]; -n10 [ shape=octagon, label="y", color="black", fontcolor="black" ]; -c15 [ shape=record, label="{{ A| B| S}|$110\n$mux|{ Y}}" ]; -x0 [ shape=record, style=rounded, label=" 1:1 - 0:0 " ]; -x0:e -> c15:p13:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -c16 [ shape=record, label="{{ A| B| S}|$113\n$mux|{ Y}}" ]; -x1 [ shape=record, style=rounded, label=" 0:0 - 0:0 " ]; -x1:e -> c16:p13:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -c17 [ shape=record, label="{{ A| B| S}|$116\n$mux|{ Y}}" ]; -x2 [ shape=record, style=rounded, label=" 0:0 - 0:0 " ]; -x2:e -> c17:p13:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", label=""]; -c21 [ shape=record, label="{{ CLK| D}|$64\n$dff|{ Q}}" ]; -c15:p14:e -> c21:p19:w [color="black", style="setlinewidth(3)", label=""]; -c21:p20:e -> n10:w [color="black", style="setlinewidth(3)", label=""]; -c16:p14:e -> c15:p11:w [color="black", style="setlinewidth(3)", label=""]; -c17:p14:e -> c15:p12:w [color="black", style="setlinewidth(3)", label=""]; -n4:e -> c21:p18:w [color="black", label=""]; -n5:e -> c16:p11:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> c16:p12:w [color="black", style="setlinewidth(3)", label=""]; -n7:e -> c17:p11:w [color="black", style="setlinewidth(3)", label=""]; -n8:e -> c17:p12:w [color="black", style="setlinewidth(3)", label=""]; -n9:e -> x0:s0:w [color="black", label=""]; -n9:e -> x1:s0:w [color="black", label=""]; -n9:e -> x2:s0:w [color="black", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/submod_03.dot b/yosys/manual/APPNOTE_011_Design_Investigation/submod_03.dot deleted file mode 100644 index 0dbbe3baa..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/submod_03.dot +++ /dev/null @@ -1,26 +0,0 @@ -digraph "selstage" { -rankdir="LR"; -remincross=true; -n3 [ shape=octagon, label="d", color="black", fontcolor="black" ]; -n4 [ shape=octagon, label="n1", color="black", fontcolor="black" ]; -n5 [ shape=octagon, label="n2", color="black", fontcolor="black" ]; -n6 [ shape=octagon, label="s1", color="black", fontcolor="black" ]; -n7 [ shape=octagon, label="s2", color="black", fontcolor="black" ]; -c10 [ shape=record, label="{{ A}|$39\n$reduce_bool|{ Y}}" ]; -v0 [ label="4'0000" ]; -c13 [ shape=record, label="{{ A| B| S}|$40\n$mux|{ Y}}" ]; -x1 [ shape=record, style=rounded, label=" 3:2 - 1:0 | 1:0 - 1:0 " ]; -c13:p9:e -> x1:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -c14 [ shape=record, label="{{ A| B}|$38\n$xor|{ Y}}" ]; -x2 [ shape=record, style=rounded, label=" 1:0 - 3:2 | 1:0 - 1:0 " ]; -x2:e -> c14:p8:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, color="black", style="setlinewidth(3)", label=""]; -c10:p9:e -> c13:p12:w [color="black", label=""]; -c14:p9:e -> c13:p11:w [color="black", style="setlinewidth(3)", label=""]; -n3:e -> c10:p8:w [color="black", style="setlinewidth(3)", label=""]; -n3:e -> c14:p11:w [color="black", style="setlinewidth(3)", label=""]; -x1:s0:e -> n4:w [color="black", style="setlinewidth(3)", label=""]; -x1:s1:e -> n5:w [color="black", style="setlinewidth(3)", label=""]; -n6:e -> x2:s1:w [color="black", style="setlinewidth(3)", label=""]; -n7:e -> x2:s0:w [color="black", style="setlinewidth(3)", label=""]; -v0:e -> c13:p8:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod.v b/yosys/manual/APPNOTE_011_Design_Investigation/sumprod.v deleted file mode 100644 index 4091bf0a1..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod.v +++ /dev/null @@ -1,12 +0,0 @@ -module sumprod(a, b, c, sum, prod); - - input [7:0] a, b, c; - output [7:0] sum, prod; - - {* sumstuff *} - assign sum = a + b + c; - {* *} - - assign prod = a * b * c; - -endmodule diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_00.dot b/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_00.dot deleted file mode 100644 index 06522dcc9..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_00.dot +++ /dev/null @@ -1,18 +0,0 @@ -digraph "sumprod" { -rankdir="LR"; -remincross=true; -v0 [ label="a" ]; -v1 [ label="b" ]; -v2 [ label="$1_Y" ]; -c4 [ shape=record, label="{{ A| B}|$1\n$add|{ Y}}" ]; -v3 [ label="$1_Y" ]; -v4 [ label="c" ]; -v5 [ label="sum" ]; -c5 [ shape=record, label="{{ A| B}|$2\n$add|{ Y}}" ]; -v0:e -> c4:p1:w [color="black", style="setlinewidth(3)", label=""]; -v1:e -> c4:p2:w [color="black", style="setlinewidth(3)", label=""]; -c4:p3:e -> v2:w [color="black", style="setlinewidth(3)", label=""]; -v3:e -> c5:p1:w [color="black", style="setlinewidth(3)", label=""]; -v4:e -> c5:p2:w [color="black", style="setlinewidth(3)", label=""]; -c5:p3:e -> v5:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_01.dot b/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_01.dot deleted file mode 100644 index aefe7a6da..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_01.dot +++ /dev/null @@ -1,15 +0,0 @@ -digraph "sumprod" { -rankdir="LR"; -remincross=true; -n2 [ shape=octagon, label="a", color="black", fontcolor="black" ]; -n3 [ shape=octagon, label="b", color="black", fontcolor="black" ]; -n4 [ shape=octagon, label="c", color="black", fontcolor="black" ]; -n5 [ shape=octagon, label="sum", color="black", fontcolor="black" ]; -c9 [ shape=record, label="{{ A| B}|$1\n$add|{ Y}}" ]; -c10 [ shape=record, label="{{ A| B}|$2\n$add|{ Y}}" ]; -c9:p8:e -> c10:p6:w [color="black", style="setlinewidth(3)", label=""]; -n2:e -> c9:p6:w [color="black", style="setlinewidth(3)", label=""]; -n3:e -> c9:p7:w [color="black", style="setlinewidth(3)", label=""]; -n4:e -> c10:p7:w [color="black", style="setlinewidth(3)", label=""]; -c10:p8:e -> n5:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_02.dot b/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_02.dot deleted file mode 100644 index 4646c9947..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_02.dot +++ /dev/null @@ -1,5 +0,0 @@ -digraph "sumprod" { -rankdir="LR"; -remincross=true; -n1 [ shape=octagon, label="prod", color="black", fontcolor="black" ]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_03.dot b/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_03.dot deleted file mode 100644 index dcfea2b56..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_03.dot +++ /dev/null @@ -1,11 +0,0 @@ -digraph "sumprod" { -rankdir="LR"; -remincross=true; -n1 [ shape=octagon, label="prod", color="black", fontcolor="black" ]; -v0 [ label="$3_Y" ]; -v1 [ label="c" ]; -c5 [ shape=record, label="{{ A| B}|$4\n$mul|{ Y}}" ]; -c5:p4:e -> n1:w [color="black", style="setlinewidth(3)", label=""]; -v0:e -> c5:p2:w [color="black", style="setlinewidth(3)", label=""]; -v1:e -> c5:p3:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_04.dot b/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_04.dot deleted file mode 100644 index e77c41aa2..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_04.dot +++ /dev/null @@ -1,11 +0,0 @@ -digraph "sumprod" { -rankdir="LR"; -remincross=true; -n2 [ shape=octagon, label="c", color="black", fontcolor="black" ]; -n3 [ shape=octagon, label="prod", color="black", fontcolor="black" ]; -c7 [ shape=record, label="{{ A| B}|$4\n$mul|{ Y}}" ]; -n1 [ shape=diamond, label="$3_Y" ]; -n1:e -> c7:p4:w [color="black", style="setlinewidth(3)", label=""]; -n2:e -> c7:p5:w [color="black", style="setlinewidth(3)", label=""]; -c7:p6:e -> n3:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_05.dot b/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_05.dot deleted file mode 100644 index b54441290..000000000 --- a/yosys/manual/APPNOTE_011_Design_Investigation/sumprod_05.dot +++ /dev/null @@ -1,15 +0,0 @@ -digraph "sumprod" { -rankdir="LR"; -remincross=true; -n2 [ shape=octagon, label="c", color="black", fontcolor="black" ]; -n3 [ shape=octagon, label="prod", color="black", fontcolor="black" ]; -v0 [ label="a" ]; -v1 [ label="b" ]; -c7 [ shape=record, label="{{ A| B}|$3\n$mul|{ Y}}" ]; -c8 [ shape=record, label="{{ A| B}|$4\n$mul|{ Y}}" ]; -c7:p6:e -> c8:p4:w [color="black", style="setlinewidth(3)", label=""]; -n2:e -> c8:p5:w [color="black", style="setlinewidth(3)", label=""]; -c8:p6:e -> n3:w [color="black", style="setlinewidth(3)", label=""]; -v0:e -> c7:p4:w [color="black", style="setlinewidth(3)", label=""]; -v1:e -> c7:p5:w [color="black", style="setlinewidth(3)", label=""]; -} diff --git a/yosys/manual/APPNOTE_012_Verilog_to_BTOR.tex b/yosys/manual/APPNOTE_012_Verilog_to_BTOR.tex deleted file mode 100644 index 1bc277876..000000000 --- a/yosys/manual/APPNOTE_012_Verilog_to_BTOR.tex +++ /dev/null @@ -1,435 +0,0 @@ - -% IEEEtran howto: -% http://ftp.univie.ac.at/packages/tex/macros/latex/contrib/IEEEtran/IEEEtran_HOWTO.pdf -\documentclass[9pt,technote,a4paper]{IEEEtran} - -\usepackage[T1]{fontenc} % required for luximono! -\usepackage[scaled=0.8]{luximono} % typewriter font with bold face - -% To install the luximono font files: -% getnonfreefonts-sys --all or -% getnonfreefonts-sys luximono -% -% when there are trouble you might need to: -% - Create /etc/texmf/updmap.d/99local-luximono.cfg -% containing the single line: Map ul9.map -% - Run update-updmap followed by mktexlsr and updmap-sys -% -% This commands must be executed as root with a root environment -% (i.e. run "sudo su" and then execute the commands in the root -% shell, don't just prefix the commands with "sudo"). - -\usepackage[unicode,bookmarks=false]{hyperref} -\usepackage[english]{babel} -\usepackage[utf8]{inputenc} -\usepackage{amssymb} -\usepackage{amsmath} -\usepackage{amsfonts} -\usepackage{units} -\usepackage{nicefrac} -\usepackage{eurosym} -\usepackage{graphicx} -\usepackage{verbatim} -\usepackage{algpseudocode} -\usepackage{scalefnt} -\usepackage{xspace} -\usepackage{color} -\usepackage{colortbl} -\usepackage{multirow} -\usepackage{hhline} -\usepackage{listings} -\usepackage{float} - -\usepackage{tikz} -\usetikzlibrary{calc} -\usetikzlibrary{arrows} -\usetikzlibrary{scopes} -\usetikzlibrary{through} -\usetikzlibrary{shapes.geometric} - -\lstset{basicstyle=\ttfamily,frame=trBL,xleftmargin=2em,xrightmargin=1em,numbers=left} - -\begin{document} - -\title{Yosys Application Note 012: \\ Converting Verilog to BTOR} -\author{Ahmed Irfan and Clifford Wolf \\ April 2015} -\maketitle - -\begin{abstract} -Verilog-2005 is a powerful Hardware Description Language (HDL) that -can be used to easily create complex designs from small HDL code. -BTOR~\cite{btor} is a bit-precise word-level format for model -checking. It is a simple format and easy to parse. It allows to model -the model checking problem over the theory of bit-vectors with -one-dimensional arrays, thus enabling to model Verilog designs with -registers and memories. Yosys~\cite{yosys} is an Open-Source Verilog -synthesis tool that can be used to convert Verilog designs with simple -assertions to BTOR format. - -\end{abstract} - -\section{Installation} - -Yosys written in C++ (using features from C++11) and is tested on -modern Linux. It should compile fine on most UNIX systems with a -C++11 compiler. The README file contains useful information on -building Yosys and its prerequisites. - -Yosys is a large and feature-rich program with some dependencies. For -this work, we may deactivate other extra features such as {\tt TCL} -and {\tt ABC} support in the {\tt Makefile}. - -\bigskip - -This Application Note is based on GIT Rev. {\tt 082550f} from -2015-04-04 of Yosys~\cite{yosys}. - -\section{Quick Start} - -We assume that the Verilog design is synthesizable and we also assume -that the design does not have multi-dimensional memories. As BTOR -implicitly initializes registers to zero value and memories stay -uninitialized, we assume that the Verilog design does -not contain initial blocks. For more details about the BTOR format, -please refer to~\cite{btor}. - -We provide a shell script {\tt verilog2btor.sh} which can be used to -convert a Verilog design to BTOR. The script can be found in the -{\tt backends/btor} directory. The following example shows its usage: - -\begin{figure}[H] -\begin{lstlisting}[language=sh,numbers=none] -verilog2btor.sh fsm.v fsm.btor test -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{Using verilog2btor script} -\end{figure} - -The script {\tt verilog2btor.sh} takes three parameters. In the above -example, the first parameter {\tt fsm.v} is the input design, the second -parameter {\tt fsm.btor} is the file name of BTOR output, and the third -parameter {\tt test} is the name of top module in the design. - -To specify the properties (that need to be checked), we have two -options: -\begin{itemize} -\item We can use the Verilog {\tt assert} statement in the procedural block - or module body of the Verilog design, as shown in - Listing~\ref{specifying_property_assert}. This is the preferred option. -\item We can use a single-bit output wire, whose name starts with - {\tt safety}. The value of this output wire needs to be driven low - when the property is met, i.e. the solver will try to find a model - that makes the safety pin go high. This is demonstrated in - Listing~\ref{specifying_property_output}. -\end{itemize} - -\begin{figure}[H] -\begin{lstlisting}[language=Verilog,numbers=none] -module test(input clk, input rst, output y); - - reg [2:0] state; - - always @(posedge clk) begin - if (rst || state == 3) begin - state <= 0; - end else begin - assert(state < 3); - state <= state + 1; - end - end - - assign y = state[2]; - - assert property (y !== 1'b1); - -endmodule -\end{lstlisting} -\renewcommand{\figurename}{Listing} -\caption{Specifying property in Verilog design with {\tt assert}} -\label{specifying_property_assert} -\end{figure} - -\begin{figure}[H] -\begin{lstlisting}[language=Verilog,numbers=none] -module test(input clk, input rst, - output y, output safety1); - - reg [2:0] state; - - always @(posedge clk) begin - if (rst || state == 3) - state <= 0; - else - state <= state + 1; - end - - assign y = state[2]; - - assign safety1 = !(y !== 1'b1); - -endmodule -\end{lstlisting} -\renewcommand{\figurename}{Listing} -\caption{Specifying property in Verilog design with output wire} -\label{specifying_property_output} -\end{figure} - -We can run Boolector~\cite{boolector}~$1.4.1$\footnote{ -Newer version of Boolector do not support sequential models. -Boolector 1.4.1 can be built with picosat-951. Newer versions -of picosat have an incompatible API.} on the generated BTOR -file: - -\begin{figure}[H] -\begin{lstlisting}[language=sh,numbers=none] -$ boolector fsm.btor -unsat -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{Running boolector on BTOR file} -\end{figure} - -We can also use nuXmv~\cite{nuxmv}, but on BTOR designs it does not -support memories yet. With the next release of nuXmv, we will be also -able to verify designs with memories. - -\section{Detailed Flow} - -Yosys is able to synthesize Verilog designs up to the gate level. -We are interested in keeping registers and memories when synthesizing -the design. For this purpose, we describe a customized Yosys synthesis -flow, that is also provided by the {\tt verilog2btor.sh} script. -Listing~\ref{btor_script_memory} shows the Yosys commands that are -executed by {\tt verilog2btor.sh}. - -\begin{figure}[H] -\begin{lstlisting}[language=sh] -read_verilog -sv $1; -hierarchy -top $3; hierarchy -libdir $DIR; -hierarchy -check; -proc; opt; -opt_expr -mux_undef; opt; -rename -hide;;; -splice; opt; -memory_dff -wr_only; memory_collect;; -flatten;; -memory_unpack; -splitnets -driver; -setundef -zero -undriven; -opt;;; -write_btor $2; -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{Synthesis Flow for BTOR with memories} -\label{btor_script_memory} -\end{figure} - -Here is short description of what is happening in the script line by -line: - -\begin{enumerate} -\item Reading the input file. -\item Setting the top module in the hierarchy and trying to read - automatically the files which are given as {\tt include} in the file - read in first line. -\item Checking the design hierarchy. -\item Converting processes to multiplexers (muxs) and flip-flops. -\item Removing undef signals from muxs. -\item Hiding all signal names that are not used as module ports. -\item Explicit type conversion, by introducing slice and concat cells - in the circuit. -\item Converting write memories to synchronous memories, and - collecting the memories to multi-port memories. -\item Flattening the design to get only one module. -\item Separating read and write memories. -\item Splitting the signals that are partially assigned -\item Setting undef to zero value. -\item Final optimization pass. -\item Writing BTOR file. -\end{enumerate} - -For detailed description of the commands mentioned above, please refer -to the Yosys documentation, or run {\tt yosys -h \it command\_name}. - -The script presented earlier can be easily modified to have a BTOR -file that does not contain memories. This is done by removing the line -number~8 and 10, and introduces a new command {\tt memory} at line -number~8. Listing~\ref{btor_script_without_memory} shows the -modified Yosys script file: - -\begin{figure}[H] -\begin{lstlisting}[language=sh,numbers=none] -read_verilog -sv $1; -hierarchy -top $3; hierarchy -libdir $DIR; -hierarchy -check; -proc; opt; -opt_expr -mux_undef; opt; -rename -hide;;; -splice; opt; -memory;; -flatten;; -splitnets -driver; -setundef -zero -undriven; -opt;;; -write_btor $2; -\end{lstlisting} - \renewcommand{\figurename}{Listing} -\caption{Synthesis Flow for BTOR without memories} -\label{btor_script_without_memory} -\end{figure} - -\section{Example} - -Here is an example Verilog design that we want to convert to BTOR: - -\begin{figure}[H] -\begin{lstlisting}[language=Verilog,numbers=none] -module array(input clk); - - reg [7:0] counter; - reg [7:0] mem [7:0]; - - always @(posedge clk) begin - counter <= counter + 8'd1; - mem[counter] <= counter; - end - - assert property (!(counter > 8'd0) || - mem[counter - 8'd1] == counter - 8'd1); - -endmodule -\end{lstlisting} -\renewcommand{\figurename}{Listing} -\caption{Example - Verilog Design} -\label{example_verilog} -\end{figure} - -The generated BTOR file that contain memories, using the script shown -in Listing~\ref{btor_script_memory}: -\begin{figure}[H] -\begin{lstlisting}[numbers=none] -1 var 1 clk -2 array 8 3 -3 var 8 $auto$rename.cc:150:execute$20 -4 const 8 00000001 -5 sub 8 3 4 -6 slice 3 5 2 0 -7 read 8 2 6 -8 slice 3 3 2 0 -9 add 8 3 4 -10 const 8 00000000 -11 ugt 1 3 10 -12 not 1 11 -13 const 8 11111111 -14 slice 1 13 0 0 -15 one 1 -16 eq 1 1 15 -17 and 1 16 14 -18 write 8 3 2 8 3 -19 acond 8 3 17 18 2 -20 anext 8 3 2 19 -21 eq 1 7 5 -22 or 1 12 21 -23 const 1 1 -24 one 1 -25 eq 1 23 24 -26 cond 1 25 22 24 -27 root 1 -26 -28 cond 8 1 9 3 -29 next 8 3 28 -\end{lstlisting} -\renewcommand{\figurename}{Listing} -\caption{Example - Converted BTOR with memory} -\label{example_btor} -\end{figure} - -And the BTOR file obtained by the script shown in -Listing~\ref{btor_script_without_memory}, which expands the memory -into individual elements: -\begin{figure}[H] -\begin{lstlisting}[numbers=none,escapechar=@] -1 var 1 clk -2 var 8 mem[0] -3 var 8 $auto$rename.cc:150:execute$20 -4 slice 3 3 2 0 -5 slice 1 4 0 0 -6 not 1 5 -7 slice 1 4 1 1 -8 not 1 7 -9 slice 1 4 2 2 -10 not 1 9 -11 and 1 8 10 -12 and 1 6 11 -13 cond 8 12 3 2 -14 cond 8 1 13 2 -15 next 8 2 14 -16 const 8 00000001 -17 add 8 3 16 -18 const 8 00000000 -19 ugt 1 3 18 -20 not 1 19 -21 var 8 mem[2] -22 and 1 7 10 -23 and 1 6 22 -24 cond 8 23 3 21 -25 cond 8 1 24 21 -26 next 8 21 25 -27 sub 8 3 16 - -@\vbox to 0pt{\vss\vdots\vskip3pt}@ -54 cond 1 53 50 52 -55 root 1 -54 - -@\vbox to 0pt{\vss\vdots\vskip3pt}@ -77 cond 8 76 3 44 -78 cond 8 1 77 44 -79 next 8 44 78 -\end{lstlisting} -\renewcommand{\figurename}{Listing} -\caption{Example - Converted BTOR without memory} -\label{example_btor} -\end{figure} - -\section{Limitations} - -BTOR does not support initialization of memories and registers, i.e. they are -implicitly initialized to value zero, so the initial block for -memories need to be removed when converting to BTOR. It should -also be kept in consideration that BTOR does not support the {\tt x} or {\tt z} -values of Verilog. - -Another thing to bear in mind is that Yosys will convert multi-dimensional -memories to one-dimensional memories and address decoders. Therefore -out-of-bounds memory accesses can yield unexpected results. - -\section{Conclusion} - -Using the described flow, we can use Yosys to generate word-level -verification benchmarks with or without memories from Verilog designs. - -\begin{thebibliography}{9} - -\bibitem{yosys} -Clifford Wolf. The Yosys Open SYnthesis Suite. \\ -\url{http://www.clifford.at/yosys/} - -\bibitem{boolector} -Robert Brummayer and Armin Biere, Boolector: An Efficient SMT Solver for Bit-Vectors and Arrays\\ -\url{http://fmv.jku.at/boolector/} - -\bibitem{btor} -Robert Brummayer and Armin Biere and Florian Lonsing, BTOR: -Bit-Precise Modelling of Word-Level Problems for Model Checking\\ -\url{http://fmv.jku.at/papers/BrummayerBiereLonsing-BPR08.pdf} - -\bibitem{nuxmv} -Roberto Cavada and Alessandro Cimatti and Michele Dorigatti and -Alberto Griggio and Alessandro Mariotti and Andrea Micheli and Sergio -Mover and Marco Roveri and Stefano Tonetta, The nuXmv Symbolic Model -Checker\\ -\url{https://es-static.fbk.eu/tools/nuxmv/index.php} - -\end{thebibliography} - - -\end{document} diff --git a/yosys/manual/CHAPTER_Appnotes.tex b/yosys/manual/CHAPTER_Appnotes.tex deleted file mode 100644 index e0d093290..000000000 --- a/yosys/manual/CHAPTER_Appnotes.tex +++ /dev/null @@ -1,29 +0,0 @@ - -\chapter{Application Notes} -\label{chapter:appnotes} - -% \begin{fixme} -% This appendix will cover some typical use-cases of Yosys in the form of application notes. -% \end{fixme} -% -% \section{Synthesizing using a Cell Library in Liberty Format} -% \section{Reverse Engineering the MOS6502 from an NMOS Transistor Netlist} -% \section{Reconfigurable Coarse-Grain Synthesis using Intersynth} - -This appendix contains copies of the Yosys application notes. - -\begin{itemize} -\item Yosys AppNote 010: Converting Verilog to BLIF \dotfill Page \pageref{app:010} \hskip2cm\null -\item Yosys AppNote 011: Interactive Design Investigation \dotfill Page \pageref{app:011} \hskip2cm\null -\item Yosys AppNote 012: Converting Verilog to BTOR \dotfill Page \pageref{app:012} \hskip2cm\null -\end{itemize} - -\eject\label{app:010} -\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_010_Verilog_to_BLIF.pdf} - -\eject\label{app:011} -\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_011_Design_Investigation.pdf} - -\eject\label{app:012} -\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_012_Verilog_to_BTOR.pdf} - diff --git a/yosys/manual/CHAPTER_Approach.tex b/yosys/manual/CHAPTER_Approach.tex deleted file mode 100644 index 4b170ee0a..000000000 --- a/yosys/manual/CHAPTER_Approach.tex +++ /dev/null @@ -1,145 +0,0 @@ - -\chapter{Approach} -\label{chapter:approach} - -Yosys is a tool for synthesising (behavioural) Verilog HDL code to target architecture netlists. Yosys aims at a wide -range of application domains and thus must be flexible and easy to adapt to new tasks. This chapter covers the general -approach followed in the effort to implement this tool. - -\section{Data- and Control-Flow} - -The data- and control-flow of a typical synthesis tool is very similar to the data- and control-flow of a typical -compiler: different subsystems are called in a predetermined order, each consuming the data generated by the -last subsystem and generating the data for the next subsystem (see Fig.~\ref{fig:approach_flow}). - -\begin{figure}[b] - \hfil - \begin{tikzpicture} - \path (-1.5,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=orange!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Frontend} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=green!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Pass} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=green!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Pass} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=green!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Pass} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=orange!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Backend} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - - \path (-3,-0.5) coordinate (cursor); - \draw (cursor) -- node[below] {HDL} ++(3,0) coordinate (cursor); - \draw[|-|] (cursor) -- node[below] {Internal Format(s)} ++(8,0) coordinate (cursor); - \draw (cursor) -- node[below] {Netlist} ++(3,0); - - \path (-3,3.5) coordinate (cursor); - \draw[-] (cursor) -- node[above] {High-Level} ++(3,0) coordinate (cursor); - \draw[-] (cursor) -- ++(8,0) coordinate (cursor); - \draw[->] (cursor) -- node[above] {Low-Level} ++(3,0); - - \end{tikzpicture} - \caption{General data- and control-flow of a synthesis tool} - \label{fig:approach_flow} -\end{figure} - -The first subsystem to be called is usually called a {\it frontend}. It does not process the data generated by -another subsystem but instead reads the user input---in the case of a HDL synthesis tool, the behavioural -HDL code. - -The subsystems that consume data from previous subsystems and produce data for the next subsystems (usually in the -same or a similar format) are called {\it passes}. - -The last subsystem that is executed transforms the data generated by the last pass into a suitable output -format and writes it to a disk file. This subsystem is usually called the {\it backend}. - -In Yosys all frontends, passes and backends are directly available as commands in the synthesis script. Thus -the user can easily create a custom synthesis flow just by calling passes in the right order in a synthesis -script. - -\section{Internal Formats in Yosys} - -Yosys uses two different internal formats. The first is used to store an abstract syntax tree (AST) of a Verilog -input file. This format is simply called {\it AST} and is generated by the Verilog Frontend. This data structure -is consumed by a subsystem called {\it AST Frontend}\footnote{In Yosys the term {\it pass} is only used to -refer to commands that operate on the RTLIL data structure.}. This AST Frontend then generates a design in Yosys' -main internal format, the Register-Transfer-Level-Intermediate-Language (RTLIL) representation. It does that -by first performing a number of simplifications within the AST representation and then generating RTLIL from -the simplified AST data structure. - -The RTLIL representation is used by all passes as input and outputs. This has the following advantages over -using different representational formats between different passes: - -\begin{itemize} -\item The passes can be rearranged in a different order and passes can be removed or inserted. -\item Passes can simply pass-thru the parts of the design they don't change without the need - to convert between formats. In fact Yosys passes output the same data structure they received - as input and performs all changes in place. -\item All passes use the same interface, thus reducing the effort required to understand a pass - when reading the Yosys source code, e.g.~when adding additional features. -\end{itemize} - -The RTLIL representation is basically a netlist representation with the following additional features: - -\begin{itemize} -\item An internal cell library with fixed-function cells to represent RTL datapath and register cells as well -as logical gate-level cells (single-bit gates and registers). -\item Support for multi-bit values that can use individual bits from wires as well as constant bits to -represent coarse-grain netlists. -\item Support for basic behavioural constructs (if-then-else structures and multi-case switches with -a sensitivity list for updating the outputs). -\item Support for multi-port memories. -\end{itemize} - -The use of RTLIL also has the disadvantage of having a very powerful format -between all passes, even when doing gate-level synthesis where the more -advanced features are not needed. In order to reduce complexity for passes that -operate on a low-level representation, these passes check the features used in -the input RTLIL and fail to run when unsupported high-level constructs are -used. In such cases a pass that transforms the higher-level constructs to -lower-level constructs must be called from the synthesis script first. - -\section{Typical Use Case} -\label{sec:typusecase} - -The following example script may be used in a synthesis flow to convert the behavioural Verilog code -from the input file {\tt design.v} to a gate-level netlist {\tt synth.v} using the cell library -described by the Liberty file \citeweblink{LibertyFormat} {\tt cells.lib}: - -\begin{lstlisting}[language=sh,numbers=left,frame=single] -# read input file to internal representation -read_verilog design.v - -# convert high-level behavioral parts ("processes") to d-type flip-flops and muxes -proc - -# perform some simple optimizations -opt - -# convert high-level memory constructs to d-type flip-flops and multiplexers -memory - -# perform some simple optimizations -opt - -# convert design to (logical) gate-level netlists -techmap - -# perform some simple optimizations -opt - -# map internal register types to the ones from the cell library -dfflibmap -liberty cells.lib - -# use ABC to map remaining logic to cells from the cell library -abc -liberty cells.lib - -# cleanup -opt - -# write results to output file -write_verilog synth.v -\end{lstlisting} - -A detailed description of the commands available in Yosys can be found in App.~\ref{commandref}. - diff --git a/yosys/manual/CHAPTER_Auxlibs.tex b/yosys/manual/CHAPTER_Auxlibs.tex deleted file mode 100644 index 440ea1375..000000000 --- a/yosys/manual/CHAPTER_Auxlibs.tex +++ /dev/null @@ -1,35 +0,0 @@ - -\chapter{Auxiliary Libraries} - -The Yosys source distribution contains some auxiliary libraries that are bundled -with Yosys. - -\section{SHA1} - -The files in {\tt libs/sha1/} provide a public domain SHA1 implementation written -by Steve Reid, Bruce Guenter, and Volker Grabsch. It is used for generating -unique names when specializing parameterized modules. - -\section{BigInt} - -The files in {\tt libs/bigint/} provide a library for performing arithmetic with -arbitrary length integers. It is written by Matt McCutchen \citeweblink{bigint}. - -The BigInt library is used for evaluating constant expressions, e.g.~using the {\tt -ConstEval} class provided in {\tt kernel/consteval.h}. - -\section{SubCircuit} -\label{sec:SubCircuit} - -The files in {\tt libs/subcircuit} provide a library for solving the subcircuit -isomorphism problem. It is written by Clifford Wolf and based on the Ullmann -Subgraph Isomorphism Algorithm \cite{UllmannSubgraphIsomorphism}. It is used by -the {\tt extract} pass (see {\tt help extract} or Sec.~\ref{cmd:extract}). - -\section{ezSAT} - -The files in {\tt libs/ezsat} provide a library for simplifying generating CNF -formulas for SAT solvers. It also contains bindings of MiniSAT. The ezSAT -library is written by Clifford Wolf. It is used by the {\tt sat} pass (see -{\tt help sat} or Sec.~\ref{cmd:sat}). - diff --git a/yosys/manual/CHAPTER_Auxprogs.tex b/yosys/manual/CHAPTER_Auxprogs.tex deleted file mode 100644 index 724d37f0b..000000000 --- a/yosys/manual/CHAPTER_Auxprogs.tex +++ /dev/null @@ -1,25 +0,0 @@ - -\chapter{Auxiliary Programs} - -Besides the main {\tt yosys} executable, the Yosys distribution contains a set -of additional helper programs. - -\section{yosys-config} - -The {\tt yosys-config} tool (an auto-generated shell-script) can be used to -query compiler options and other information needed for building loadable -modules for Yosys. FIXME: See Sec.~\ref{chapter:prog} for details. - -\section{yosys-filterlib} -\label{sec:filterlib} - -The {\tt yosys-filterlib} tool is a small utility that can be used to strip -or extract information from a Liberty file. See Sec.~\ref{sec:techmap_extern} -for details. - -\section{yosys-abc} - -This is a unmodified copy of ABC \citeweblink{ABC}. Not all versions of Yosys -work with all versions of ABC. So Yosys comes with its own yosys-abc to avoid -compatibility issues between the two. - diff --git a/yosys/manual/CHAPTER_Basics.tex b/yosys/manual/CHAPTER_Basics.tex deleted file mode 100644 index 5c60b7305..000000000 --- a/yosys/manual/CHAPTER_Basics.tex +++ /dev/null @@ -1,839 +0,0 @@ - -\chapter{Basic Principles} -\label{chapter:basics} - -This chapter contains a short introduction to the basic principles of digital -circuit synthesis. - -\section{Levels of Abstraction} - -Digital circuits can be represented at different levels of abstraction. -During the design process a circuit is usually first specified using a higher -level abstraction. Implementation can then be understood as finding a -functionally equivalent representation at a lower abstraction level. When -this is done automatically using software, the term {\it synthesis} is used. - -So synthesis is the automatic conversion of a high-level representation of a -circuit to a functionally equivalent low-level representation of a circuit. -Figure~\ref{fig:Basics_abstractions} lists the different levels of abstraction -and how they relate to different kinds of synthesis. - -\begin{figure}[b!] - \hfil - \begin{tikzpicture} - \tikzstyle{lvl} = [draw, fill=green!10, rectangle, minimum height=2em, minimum width=15em] - \node[lvl] (sys) {System Level}; - \node[lvl] (hl) [below of=sys] {High Level}; - \node[lvl] (beh) [below of=hl] {Behavioral Level}; - \node[lvl] (rtl) [below of=beh] {Register-Transfer Level (RTL)}; - \node[lvl] (lg) [below of=rtl] {Logical Gate Level}; - \node[lvl] (pg) [below of=lg] {Physical Gate Level}; - \node[lvl] (sw) [below of=pg] {Switch Level}; - - \draw[dotted] (sys.east) -- ++(1,0) coordinate (sysx); - \draw[dotted] (hl.east) -- ++(1,0) coordinate (hlx); - \draw[dotted] (beh.east) -- ++(1,0) coordinate (behx); - \draw[dotted] (rtl.east) -- ++(1,0) coordinate (rtlx); - \draw[dotted] (lg.east) -- ++(1,0) coordinate (lgx); - \draw[dotted] (pg.east) -- ++(1,0) coordinate (pgx); - \draw[dotted] (sw.east) -- ++(1,0) coordinate (swx); - - \draw[gray,|->] (sysx) -- node[right] {System Design} (hlx); - \draw[|->|] (hlx) -- node[right] {High Level Synthesis (HLS)} (behx); - \draw[->|] (behx) -- node[right] {Behavioral Synthesis} (rtlx); - \draw[->|] (rtlx) -- node[right] {RTL Synthesis} (lgx); - \draw[->|] (lgx) -- node[right] {Logic Synthesis} (pgx); - \draw[gray,->|] (pgx) -- node[right] {Cell Library} (swx); - - \draw[dotted] (behx) -- ++(5,0) coordinate (a); - \draw[dotted] (pgx) -- ++(5,0) coordinate (b); - \draw[|->|] (a) -- node[right] {Yosys} (b); - \end{tikzpicture} - \caption{Different levels of abstraction and synthesis.} - \label{fig:Basics_abstractions} -\end{figure} - -Regardless of the way a lower level representation of a circuit is -obtained (synthesis or manual design), the lower level representation is usually -verified by comparing simulation results of the lower level and the higher level -representation \footnote{In recent years formal equivalence -checking also became an important verification method for validating RTL and -lower abstraction representation of the design.}. -Therefore even if no synthesis is used, there must still be a simulatable -representation of the circuit in all levels to allow for verification of the -design. - -Note: The exact meaning of terminology such as ``High-Level'' is of course not -fixed over time. For example the HDL ``ABEL'' was first introduced in 1985 as ``A High-Level -Design Language for Programmable Logic Devices'' \cite{ABEL}, but would not -be considered a ``High-Level Language'' today. - -\subsection{System Level} - -The System Level abstraction of a system only looks at its biggest building -blocks like CPUs and computing cores. At this level the circuit is usually described -using traditional programming languages like C/C++ or Matlab. Sometimes special -software libraries are used that are aimed at simulation circuits on the system -level, such as SystemC. - -Usually no synthesis tools are used to automatically transform a system level -representation of a circuit to a lower-level representation. But system level -design tools exist that can be used to connect system level building blocks. - -The IEEE 1685-2009 standard defines the IP-XACT file format that can be used to -represent designs on the system level and building blocks that can be used in -such system level designs. \cite{IP-XACT} - -\subsection{High Level} - -The high-level abstraction of a system (sometimes referred to as {\it -algorithmic} level) is also often represented using traditional programming -languages, but with a reduced feature set. For example when representing a -design at the high level abstraction in C, pointers can only be used to mimic -concepts that can be found in hardware, such as memory interfaces. Full -featured dynamic memory management is not allowed as it has no corresponding -concept in digital circuits. - -Tools exist to synthesize high level code (usually in the form of C/C++/SystemC -code with additional metadata) to behavioural HDL code (usually in the form of -Verilog or VHDL code). Aside from the many commercial tools for high level synthesis -there are also a number of FOSS tools for high level synthesis -\citeweblink{C_to_Verilog} \citeweblink{LegUp}. - -\subsection{Behavioural Level} - -At the behavioural abstraction level a language aimed at hardware description such -as Verilog or VHDL is used to describe the circuit, but so-called {\it behavioural -modelling} is used in at least part of the circuit description. In behavioural -modelling there must be a language feature that allows for imperative programming to be used to -describe data paths and registers. This is the {\tt always}-block in Verilog and -the {\tt process}-block in VHDL. - -In behavioural modelling, code fragments are provided together with a {\it -sensitivity list}; a list of signals and conditions. In simulation, the code -fragment is executed whenever a signal in the sensitivity list changes its -value or a condition in the sensitivity list is triggered. A synthesis tool -must be able to transfer this representation into an appropriate datapath followed -by the appropriate types of register. - -For example consider the following Verilog code fragment: - -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -always @(posedge clk) - y <= a + b; -\end{lstlisting} - -In simulation the statement \lstinline[language=Verilog]{y <= a + b} is executed whenever -a positive edge on the signal \lstinline[language=Verilog]{clk} is detected. The synthesis -result however will contain an adder that calculates the sum \lstinline[language=Verilog]{a + b} -all the time, followed by a d-type flip-flop with the adder output on its D-input and the -signal \lstinline[language=Verilog]{y} on its Q-output. - -Usually the imperative code fragments used in behavioural modelling can contain -statements for conditional execution (\lstinline[language=Verilog]{if}- and -\lstinline[language=Verilog]{case}-statements in Verilog) as well as loops, -as long as those loops can be completely unrolled. - -Interestingly there seems to be no other FOSS Tool that is capable of -performing Verilog or VHDL behavioural syntheses besides Yosys (see -App.~\ref{chapter:sota}). - -\subsection{Register-Transfer Level (RTL)} - -On the Register-Transfer Level the design is represented by combinatorial data -paths and registers (usually d-type flip flops). The following Verilog code fragment -is equivalent to the previous Verilog example, but is in RTL representation: - -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -assign tmp = a + b; // combinatorial data path - -always @(posedge clk) // register - y <= tmp; -\end{lstlisting} - -A design in RTL representation is usually stored using HDLs like Verilog and VHDL. But only -a very limited subset of features is used, namely minimalistic {\tt always}-blocks (Verilog) -or {\tt process}-blocks (VHDL) that model the register type used and unconditional assignments -for the datapath logic. The use of HDLs on this level simplifies simulation as no additional -tools are required to simulate a design in RTL representation. - -Many optimizations and analyses can be performed best at the RTL level. Examples include FSM -detection and optimization, identification of memories or other larger building blocks -and identification of shareable resources. - -Note that RTL is the first abstraction level in which the circuit is represented as a -graph of circuit elements (registers and combinatorial cells) and signals. Such a graph, -when encoded as list of cells and connections, is called a netlist. - -RTL synthesis is easy as each circuit node element in the netlist can simply be replaced -with an equivalent gate-level circuit. However, usually the term {\it RTL synthesis} does -not only refer to synthesizing an RTL netlist to a gate level netlist but also to performing -a number of highly sophisticated optimizations within the RTL representation, such as -the examples listed above. - -A number of FOSS tools exist that can perform isolated tasks within the domain of RTL -synthesis steps. But there seems to be no FOSS tool that covers a wide range of RTL -synthesis operations. - -\subsection{Logical Gate Level} - -At the logical gate level the design is represented by a netlist that uses only -cells from a small number of single-bit cells, such as basic logic gates (AND, -OR, NOT, XOR, etc.) and registers (usually D-Type Flip-flops). - -A number of netlist formats exists that can be used on this level, e.g.~the Electronic Design -Interchange Format (EDIF), but for ease of simulation often a HDL netlist is used. The latter -is a HDL file (Verilog or VHDL) that only uses the most basic language constructs for instantiation -and connecting of cells. - -There are two challenges in logic synthesis: First finding opportunities for optimizations -within the gate level netlist and second the optimal (or at least good) mapping of the logic -gate netlist to an equivalent netlist of physically available gate types. - -The simplest approach to logic synthesis is {\it two-level logic synthesis}, where a logic function -is converted into a sum-of-products representation, e.g.~using a Karnaugh map. -This is a simple approach, but has exponential worst-case effort and cannot make efficient use of -physical gates other than AND/NAND-, OR/NOR- and NOT-Gates. - -Therefore modern logic synthesis tools utilize much more complicated {\it multi-level logic -synthesis} algorithms \cite{MultiLevelLogicSynth}. Most of these algorithms convert the -logic function to a Binary-Decision-Diagram (BDD) or And-Inverter-Graph (AIG) and work from that -representation. The former has the advantage that it has a unique normalized form. The latter has -much better worst case performance and is therefore better suited for the synthesis of large -logic functions. - -Good FOSS tools exists for multi-level logic synthesis \citeweblink{ABC} -\citeweblink{AIGER} \citeweblink{MVSIS}. - -Yosys contains basic logic synthesis functionality but can also use ABC -\citeweblink{ABC} for the logic synthesis step. Using ABC is recommended. - -\subsection{Physical Gate Level} - -On the physical gate level only gates are used that are physically available on -the target architecture. In some cases this may only be NAND, NOR and NOT gates as well as -D-Type registers. In other cases this might include cells that are more complex than the cells -used at the logical gate level (e.g.~complete half-adders). In the case of an FPGA-based -design the physical gate level representation is a netlist of LUTs with optional output -registers, as these are the basic building blocks of FPGA logic cells. - -For the synthesis tool chain this abstraction is usually the lowest level. In -case of an ASIC-based design the cell library might contain further information on -how the physical cells map to individual switches (transistors). - -\subsection{Switch Level} - -A switch level representation of a circuit is a netlist utilizing single transistors as cells. -Switch level modelling is possible in Verilog and VHDL, but is seldom used in modern designs, -as in modern digital ASIC or FPGA flows the physical gates are considered the atomic build blocks -of the logic circuit. - -\subsection{Yosys} - -Yosys is a Verilog HDL synthesis tool. This means that it takes a behavioural -design description as input and generates an RTL, logical gate or physical gate -level description of the design as output. Yosys' main strengths are behavioural -and RTL synthesis. A wide range of commands (synthesis passes) exist -within Yosys that can be used to perform a wide range of synthesis tasks within -the domain of behavioural, rtl and logic synthesis. Yosys is designed to be -extensible and therefore is a good basis for implementing custom synthesis -tools for specialised tasks. - -\section{Features of Synthesizable Verilog} - -The subset of Verilog \cite{Verilog2005} that is synthesizable is specified in -a separate IEEE standards document, the IEEE standard 1364.1-2002 \cite{VerilogSynth}. -This standard also describes how certain language constructs are to be interpreted in -the scope of synthesis. - -This section provides a quick overview of the most important features of -synthesizable Verilog, structured in order of increasing complexity. - -\subsection{Structural Verilog} - -{\it Structural Verilog} (also known as {\it Verilog Netlists}) is a Netlist in -Verilog syntax. Only the following language constructs are used in this case: - -\begin{itemize} -\item Constant values -\item Wire and port declarations -\item Static assignments of signals to other signals -\item Cell instantiations -\end{itemize} - -Many tools (especially at the back end of the synthesis chain) only support -structural Verilog as input. ABC is an example of such a tool. Unfortunately -there is no standard specifying what {\it Structural Verilog} actually is, -leading to some confusion about what syntax constructs are supported in -structural Verilog when it comes to features such as attributes or multi-bit -signals. - -\subsection{Expressions in Verilog} - -In all situations where Verilog accepts a constant value or signal name, -expressions using arithmetic operations such as -\lstinline[language=Verilog]{+}, \lstinline[language=Verilog]{-} and \lstinline[language=Verilog]{*}, -boolean operations such as -\lstinline[language=Verilog]{&} (AND), \lstinline[language=Verilog]{|} (OR) and \lstinline[language=Verilog]{^} (XOR) -and many others (comparison operations, unary operator, etc.) can also be used. - -During synthesis these operators are replaced by cells that implement the respective function. - -Many FOSS tools that claim to be able to process Verilog in fact only support -basic structural Verilog and simple expressions. Yosys can be used to convert -full featured synthesizable Verilog to this simpler subset, thus enabling such -applications to be used with a richer set of Verilog features. - -\subsection{Behavioural Modelling} - -Code that utilizes the Verilog {\tt always} statement is using {\it Behavioural -Modelling}. In behavioural modelling, a circuit is described by means of imperative -program code that is executed on certain events, namely any change, a rising -edge, or a falling edge of a signal. This is a very flexible construct during -simulation but is only synthesizable when one of the following is modelled: - -\begin{itemize} -\item {\bf Asynchronous or latched logic} \\ -In this case the sensitivity list must contain all expressions that are used within -the {\tt always} block. The syntax \lstinline[language=Verilog]{@*} can be used -for these cases. Examples of this kind include: - -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -// asynchronous -always @* begin - if (add_mode) - y <= a + b; - else - y <= a - b; -end - -// latched -always @* begin - if (!hold) - y <= a + b; -end -\end{lstlisting} - -Note that latched logic is often considered bad style and in many cases just -the result of sloppy HDL design. Therefore many synthesis tools generate warnings -whenever latched logic is generated. - -\item {\bf Synchronous logic (with optional synchronous reset)} \\ -This is logic with d-type flip-flops on the output. In this case the sensitivity -list must only contain the respective clock edge. Example: -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -// counter with synchronous reset -always @(posedge clk) begin - if (reset) - y <= 0; - else - y <= y + 1; -end -\end{lstlisting} - -\item {\bf Synchronous logic with asynchronous reset} \\ -This is logic with d-type flip-flops with asynchronous resets on the output. In -this case the sensitivity list must only contain the respective clock and reset edges. -The values assigned in the reset branch must be constant. Example: -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -// counter with asynchronous reset -always @(posedge clk, posedge reset) begin - if (reset) - y <= 0; - else - y <= y + 1; -end -\end{lstlisting} -\end{itemize} - -Many synthesis tools support a wider subset of flip-flops that can be modelled -using {\tt always}-statements (including Yosys). But only the ones listed above -are covered by the Verilog synthesis standard and when writing new designs one -should limit herself or himself to these cases. - -In behavioural modelling, blocking assignments (=) and non-blocking assignments -(<=) can be used. The concept of blocking vs.~non-blocking assignment is one -of the most misunderstood constructs in Verilog \cite{Cummings00}. - -The blocking assignment behaves exactly like an assignment in any imperative -programming language, while with the non-blocking assignment the right hand side -of the assignment is evaluated immediately but the actual update of the left -hand side register is delayed until the end of the time-step. For example the Verilog -code \lstinline[language=Verilog]{a <= b; b <= a;} exchanges the values of -the two registers. See Sec.~\ref{sec:blocking_nonblocking} for a more -detailed description of this behaviour. - -\subsection{Functions and Tasks} - -Verilog supports {\it Functions} and {\it Tasks} to bundle statements that are -used in multiple places (similar to {\it Procedures} in imperative programming). -Both constructs can be implemented easily by substituting the function/task-call -with the body of the function or task. - -\subsection{Conditionals, Loops and Generate-Statements} - -Verilog supports \lstinline[language=Verilog]{if-else}-statements and -\lstinline[language=Verilog]{for}-loops inside \lstinline[language=Verilog]{always}-statements. - -It also supports both features in \lstinline[language=Verilog]{generate}-statements -on the module level. This can be used to selectively enable or disable parts of the -module based on the module parameters (\lstinline[language=Verilog]{if-else}) -or to generate a set of similar subcircuits (\lstinline[language=Verilog]{for}). - -While the \lstinline[language=Verilog]{if-else}-statement -inside an always-block is part of behavioural modelling, the three other cases -are (at least for a synthesis tool) part of a built-in macro processor. Therefore it must -be possible for the synthesis tool to completely unroll all loops and evaluate the -condition in all \lstinline[language=Verilog]{if-else}-statement in -\lstinline[language=Verilog]{generate}-statements using const-folding. - -Examples for this can be found in Fig.~\ref{fig:StateOfTheArt_for} and -Fig.~\ref{fig:StateOfTheArt_gen} in App.~\ref{chapter:sota}. - -\subsection{Arrays and Memories} - -Verilog supports arrays. This is in general a synthesizable language feature. -In most cases arrays can be synthesized by generating addressable memories. -However, when complex or asynchronous access patterns are used, it is not -possible to model an array as memory. In these cases the array must -be modelled using individual signals for each word and all accesses to the array -must be implemented using large multiplexers. - -In some cases it would be possible to model an array using memories, but it -is not desired. Consider the following delay circuit: -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -module (clk, in_data, out_data); - -parameter BITS = 8; -parameter STAGES = 4; - -input clk; -input [BITS-1:0] in_data; -output [BITS-1:0] out_data; -reg [BITS-1:0] ffs [STAGES-1:0]; - -integer i; -always @(posedge clk) begin - ffs[0] <= in_data; - for (i = 1; i < STAGES; i = i+1) - ffs[i] <= ffs[i-1]; -end - -assign out_data = ffs[STAGES-1]; - -endmodule -\end{lstlisting} - -This could be implemented using an addressable memory with {\tt STAGES} input -and output ports. A better implementation would be to use a simple chain of flip-flops -(a so-called shift register). -This better implementation can either be obtained by first creating a memory-based -implementation and then optimizing it based on the static address signals for all ports -or directly identifying such situations in the language front end and converting -all memory accesses to direct accesses to the correct signals. - -\section{Challenges in Digital Circuit Synthesis} - -This section summarizes the most important challenges in digital circuit -synthesis. Tools can be characterized by how well they address these topics. - -\subsection{Standards Compliance} - -The most important challenge is compliance with the HDL standards in question (in case -of Verilog the IEEE Standards 1364.1-2002 and 1364-2005). This can be broken down in two -items: - -\begin{itemize} -\item Completeness of implementation of the standard -\item Correctness of implementation of the standard -\end{itemize} - -Completeness is mostly important to guarantee compatibility -with existing HDL code. Once a design has been verified and tested, HDL designers -are very reluctant regarding changes to the design, even if it is only about -a few minor changes to work around a missing feature in a new synthesis tool. - -Correctness is crucial. In some areas this is obvious (such as -correct synthesis of basic behavioural models). But it is also crucial for the -areas that concern minor details of the standard, such as the exact rules -for handling signed expressions, even when the HDL code does not target -different synthesis tools. This is because (unlike software source code that -is only processed by compilers), in most design flows HDL code is not only -processed by the synthesis tool but also by one or more simulators and sometimes -even a formal verification tool. It is key for this verification process -that all these tools use the same interpretation for the HDL code. - -\subsection{Optimizations} - -Generally it is hard to give a one-dimensional description of how well a synthesis tool -optimizes the design. First of all because not all optimizations are applicable to all -designs and all synthesis tasks. Some optimizations work (best) on a coarse-grained level -(with complex cells such as adders or multipliers) and others work (best) on a fine-grained -level (single bit gates). Some optimizations target area and others target speed. -Some work well on large designs while others don't scale well and can only be applied -to small designs. - -A good tool is capable of applying a wide range of optimizations at different -levels of abstraction and gives the designer control over which optimizations -are performed (or skipped) and what the optimization goals are. - -\subsection{Technology Mapping} - -Technology mapping is the process of converting the design into a netlist of -cells that are available in the target architecture. In an ASIC flow this might -be the process-specific cell library provided by the fab. In an FPGA flow this -might be LUT cells as well as special function units such as dedicated multipliers. -In a coarse-grain flow this might even be more complex special function units. - -An open and vendor independent tool is especially of interest if it supports -a wide range of different types of target architectures. - -\section{Script-Based Synthesis Flows} - -A digital design is usually started by implementing a high-level or -system-level simulation of the desired function. This description is then -manually transformed (or re-implemented) into a synthesizable lower-level -description (usually at the behavioural level) and the equivalence of the -two representations is verified by simulating both and comparing the simulation -results. - -Then the synthesizable description is transformed to lower-level -representations using a series of tools and the results are again verified -using simulation. This process is illustrated in Fig.~\ref{fig:Basics_flow}. - -\begin{figure}[t!] - \hfil - \begin{tikzpicture} - \tikzstyle{manual} = [draw, fill=green!10, rectangle, minimum height=2em, minimum width=8em, node distance=10em] - \tikzstyle{auto} = [draw, fill=orange!10, rectangle, minimum height=2em, minimum width=8em, node distance=10em] - - \node[manual] (sys) {\begin{minipage}{8em} - \center - System Level \\ - Model - \end{minipage}}; - \node[manual] (beh) [right of=sys] {\begin{minipage}{8em} - \center - Behavioral \\ - Model - \end{minipage}}; - \node[auto] (rtl) [right of=beh] {\begin{minipage}{8em} - \center - RTL \\ - Model - \end{minipage}}; - \node[auto] (gates) [right of=rtl] {\begin{minipage}{8em} - \center - Gate-Level \\ - Model - \end{minipage}}; - - \draw[-latex] (beh) edge[double, bend left] node[above] {synthesis} (rtl); - \draw[-latex] (rtl) edge[double, bend left] node[above] {synthesis} (gates); - - \draw[latex-latex] (sys) edge[bend right] node[below] {verify} (beh); - \draw[latex-latex] (beh) edge[bend right] node[below] {verify} (rtl); - \draw[latex-latex] (rtl) edge[bend right] node[below] {verify} (gates); - \end{tikzpicture} - \caption{Typical design flow. Green boxes represent manually created models. Orange boxes represent - models generated by synthesis tools.} - \label{fig:Basics_flow} -\end{figure} - -In this example the System Level Model and the Behavioural Model are both -manually written design files. After the equivalence of system level model -and behavioural model has been verified, the lower level representations of the -design can be generated using synthesis tools. Finally the RTL Model and -the Gate-Level Model are verified and the design process is finished. - -However, in any real-world design effort there will be multiple iterations for -this design process. The reason for this can be the late change of a design -requirement or the fact that the analysis of a low-abstraction model (e.g.~gate-level -timing analysis) revealed that a design change is required in order to meet -the design requirements (e.g.~maximum possible clock speed). - -Whenever the behavioural model or the system level model is -changed their equivalence must be re-verified by re-running the simulations -and comparing the results. Whenever the behavioural model is changed the -synthesis must be re-run and the synthesis results must be re-verified. - -In order to guarantee reproducibility it is important to be able to re-run all -automatic steps in a design project with a fixed set of settings easily. -Because of this, usually all programs used in a synthesis flow can be -controlled using scripts. This means that all functions are available via -text commands. When such a tool provides a GUI, this is complementary to, -and not instead of, a command line interface. - -Usually a synthesis flow in an UNIX/Linux environment would be controlled by a -shell script that calls all required tools (synthesis and simulation/verification -in this example) in the correct order. Each of these tools would be called with -a script file containing commands for the respective tool. All settings required -for the tool would be provided by these script files so that no manual interaction -would be necessary. These script files are considered design sources and should -be kept under version control just like the source code of the system level and the -behavioural model. - -\section{Methods from Compiler Design} - -Some parts of synthesis tools involve problem domains that are traditionally known from -compiler design. This section addresses some of these domains. - -\subsection{Lexing and Parsing} - -The best known concepts from compiler design are probably {\it lexing} and {\it parsing}. -These are two methods that together can be used to process complex computer languages -easily. \cite{Dragonbook} - -A {\it lexer} consumes single characters from the input and generates a stream of {\it lexical -tokens} that consist of a {\it type} and a {\it value}. For example the Verilog input -``\lstinline[language=Verilog]{assign foo = bar + 42;}'' might be translated by the lexer -to the list of lexical tokens given in Tab.~\ref{tab:Basics_tokens}. - -\begin{table}[t] -\hfil -\begin{tabular}{ll} -Token-Type & Token-Value \\ -\hline -\tt TOK\_ASSIGN & - \\ -\tt TOK\_IDENTIFIER & ``{\tt foo}'' \\ -\tt TOK\_EQ & - \\ -\tt TOK\_IDENTIFIER & ``{\tt bar}'' \\ -\tt TOK\_PLUS & - \\ -\tt TOK\_NUMBER & 42 \\ -\tt TOK\_SEMICOLON & - \\ -\end{tabular} -\caption{Exemplary token list for the statement ``\lstinline[language=Verilog]{assign foo = bar + 42;}''.} -\label{tab:Basics_tokens} -\end{table} - -The lexer is usually generated by a lexer generator (e.g.~{\tt flex} \citeweblink{flex}) from a -description file that is using regular expressions to specify the text pattern that should match -the individual tokens. - -The lexer is also responsible for skipping ignored characters (such as whitespace outside string -constants and comments in the case of Verilog) and converting the original text snippet to a token -value. - -Note that individual keywords use different token types (instead of a keyword type with different -token values). This is because the parser usually can only use the Token-Type to make a decision on -the grammatical role of a token. - -The parser then transforms the list of tokens into a parse tree that closely resembles the productions -from the computer languages grammar. As the lexer, the parser is also typically generated by a code -generator (e.g.~{\tt bison} \citeweblink{bison}) from a grammar description in Backus-Naur Form (BNF). - -Let's consider the following BNF (in Bison syntax): - -\begin{lstlisting}[numbers=left,frame=single] -assign_stmt: TOK_ASSIGN TOK_IDENTIFIER TOK_EQ expr TOK_SEMICOLON; -expr: TOK_IDENTIFIER | TOK_NUMBER | expr TOK_PLUS expr; -\end{lstlisting} - -\begin{figure}[b!] - \hfil - \begin{tikzpicture} - \tikzstyle{node} = [draw, fill=green!10, ellipse, minimum height=2em, minimum width=8em, node distance=10em] - - \draw (+0,+1) node[node] (n1) {\tt assign\_stmt}; - - \draw (-6,-1) node[node] (n11) {\tt TOK\_ASSIGN}; - \draw (-3,-2) node[node] (n12) {\tt TOK\_IDENTIFIER}; - \draw (+0,-1) node[node] (n13) {\tt TOK\_EQ}; - \draw (+3,-2) node[node] (n14) {\tt expr}; - \draw (+6,-1) node[node] (n15) {\tt TOK\_SEMICOLON}; - - \draw (-1,-4) node[node] (n141) {\tt expr}; - \draw (+3,-4) node[node] (n142) {\tt TOK\_PLUS}; - \draw (+7,-4) node[node] (n143) {\tt expr}; - - \draw (-1,-5.5) node[node] (n1411) {\tt TOK\_IDENTIFIER}; - \draw (+7,-5.5) node[node] (n1431) {\tt TOK\_NUMBER}; - - \draw[-latex] (n1) -- (n11); - \draw[-latex] (n1) -- (n12); - \draw[-latex] (n1) -- (n13); - \draw[-latex] (n1) -- (n14); - \draw[-latex] (n1) -- (n15); - - \draw[-latex] (n14) -- (n141); - \draw[-latex] (n14) -- (n142); - \draw[-latex] (n14) -- (n143); - - \draw[-latex] (n141) -- (n1411); - \draw[-latex] (n143) -- (n1431); - \end{tikzpicture} - \caption{Example parse tree for the Verilog expression ``\lstinline[language=Verilog]{assign foo = bar + 42;}''.} - \label{fig:Basics_parsetree} -\end{figure} - -The parser converts the token list to the parse tree in Fig.~\ref{fig:Basics_parsetree}. Note that the parse -tree never actually exists as a whole as data structure in memory. Instead the parser calls user-specified -code snippets (so-called {\it reduce-functions}) for all inner nodes of the parse tree in depth-first order. - -In some very simple applications (e.g.~code generation for stack machines) it is possible to perform the -task at hand directly in the reduce functions. But usually the reduce functions are only used to build an in-memory -data structure with the relevant information from the parse tree. This data structure is called an {\it abstract -syntax tree} (AST). - -The exact format for the abstract syntax tree is application specific (while the format of the parse tree and token -list are mostly dictated by the grammar of the language at hand). Figure~\ref{fig:Basics_ast} illustrates what an -AST for the parse tree in Fig.~\ref{fig:Basics_parsetree} could look like. - -Usually the AST is then converted into yet another representation that is more suitable for further processing. -In compilers this is often an assembler-like three-address-code intermediate representation. \cite{Dragonbook} - -\begin{figure}[t] - \hfil - \begin{tikzpicture} - \tikzstyle{node} = [draw, fill=green!10, ellipse, minimum height=2em, minimum width=8em, node distance=10em] - - \draw (+0,+0) node[node] (n1) {\tt ASSIGN}; - - \draw (-2,-2) node[node] (n11) {\tt ID: foo}; - \draw (+2,-2) node[node] (n12) {\tt PLUS}; - - \draw (+0,-4) node[node] (n121) {\tt ID: bar}; - \draw (+4,-4) node[node] (n122) {\tt CONST: 42}; - - \draw[-latex] (n1) -- (n11); - \draw[-latex] (n1) -- (n12); - - \draw[-latex] (n12) -- (n121); - \draw[-latex] (n12) -- (n122); - \end{tikzpicture} - \caption{Example abstract syntax tree for the Verilog expression ``\lstinline[language=Verilog]{assign foo = bar + 42;}''.} - \label{fig:Basics_ast} -\end{figure} - -\subsection{Multi-Pass Compilation} - -Complex problems are often best solved when split up into smaller problems. This is certainly true -for compilers as well as for synthesis tools. The components responsible for solving the smaller problems can -be connected in two different ways: through {\it Single-Pass Pipelining} and by using {\it Multiple Passes}. - -Traditionally a parser and lexer are connected using the pipelined approach: The lexer provides a function that -is called by the parser. This function reads data from the input until a complete lexical token has been read. Then -this token is returned to the parser. So the lexer does not first generate a complete list of lexical tokens -and then pass it to the parser. Instead they run concurrently and the parser can consume tokens as -the lexer produces them. - -The single-pass pipelining approach has the advantage of lower memory footprint (at no time must the complete design -be kept in memory) but has the disadvantage of tighter coupling between the interacting components. - -Therefore single-pass pipelining should only be used when the lower memory footprint is required or the -components are also conceptually tightly coupled. The latter certainly is the case for a parser and its lexer. -But when data is passed between two conceptually loosely coupled components it is often -beneficial to use a multi-pass approach. - -In the multi-pass approach the first component processes all the data and the result is stored in a in-memory -data structure. Then the second component is called with this data. This reduces complexity, as only one -component is running at a time. It also improves flexibility as components can be exchanged easier. - -Most modern compilers are multi-pass compilers. - -\iffalse -\subsection{Static Single Assignment Form} - -In imperative programming (and behavioural HDL design) it is possible to assign the same variable multiple times. -This can either mean that the variable is independently used in two different contexts or that the final value -of the variable depends on a condition. - -The following examples show C code in which one variable is used independently in two different contexts: - -\begin{minipage}{7.7cm} -\begin{lstlisting}[numbers=left,frame=single,language=C++] -void demo1() -{ - int a = 1; - printf("%d\n", a); - - a = 2; - printf("%d\n", a); -} -\end{lstlisting} -\end{minipage} -\hfil -\begin{minipage}{7.7cm} -\begin{lstlisting}[frame=single,language=C++] -void demo1() -{ - int a = 1; - printf("%d\n", a); - - int b = 2; - printf("%d\n", b); -} -\end{lstlisting} -\end{minipage} - -\begin{minipage}{7.7cm} -\begin{lstlisting}[numbers=left,frame=single,language=C++] -void demo2(bool foo) -{ - int a; - if (foo) { - a = 23; - printf("%d\n", a); - } else { - a = 42; - printf("%d\n", a); - } -} -\end{lstlisting} -\end{minipage} -\hfil -\begin{minipage}{7.7cm} -\begin{lstlisting}[frame=single,language=C++] -void demo2(bool foo) -{ - int a, b; - if (foo) { - a = 23; - printf("%d\n", a); - } else { - b = 42; - printf("%d\n", b); - } -} -\end{lstlisting} -\end{minipage} - -In both examples the left version (only variable \lstinline[language=C++]{a}) and the right version (variables -\lstinline[language=Verilog]{a} and \lstinline[language=Verilog]{b}) are equivalent. Therefore it is -desired for further processing to bring the code in an equivalent form for both cases. - -In the following example the variable is assigned twice but it cannot be easily replaced by two variables: - -\begin{lstlisting}[frame=single,language=C++] -void demo3(bool foo) -{ - int a = 23 - if (foo) - a = 42; - printf("%d\n", a); -} -\end{lstlisting} - -Static single assignment (SSA) form is a representation of imperative code that uses identical representations -for the left and right version of demos 1 and 2, but can still represent demo 3. In SSA form each assignment -assigns a new variable (usually written with an index). But it also introduces a special $\Phi$-function to -merge the different instances of a variable when needed. In C-pseudo-code the demo 3 would be written as follows -using SSA from: - -\begin{lstlisting}[frame=single,language=C++] -void demo3(bool foo) -{ - int a_1, a_2, a_3; - a_1 = 23 - if (foo) - a_2 = 42; - a_3 = phi(a_1, a_2); - printf("%d\n", a_3); -} -\end{lstlisting} - -The $\Phi$-function is usually interpreted as ``these variables must be stored -in the same memory location'' during code generation. Most modern compilers for imperative languages -such as C/C++ use SSA form for at least some of its passes as it is very easy to manipulate and analyse. -\fi - diff --git a/yosys/manual/CHAPTER_CellLib.tex b/yosys/manual/CHAPTER_CellLib.tex deleted file mode 100644 index cb1bcf1be..000000000 --- a/yosys/manual/CHAPTER_CellLib.tex +++ /dev/null @@ -1,499 +0,0 @@ - -\chapter{Internal Cell Library} -\label{chapter:celllib} - -Most of the passes in Yosys operate on netlists, i.e.~they only care about the RTLIL::Wire and RTLIL::Cell -objects in an RTLIL::Module. This chapter discusses the cell types used by Yosys to represent a behavioural -design internally. - -This chapter is split in two parts. In the first part the internal RTL cells are covered. These cells -are used to represent the design on a coarse grain level. Like in the original HDL code on this level the -cells operate on vectors of signals and complex cells like adders exist. In the second part the internal -gate cells are covered. These cells are used to represent the design on a fine-grain gate-level. All cells -from this category operate on single bit signals. - -\section{RTL Cells} - -Most of the RTL cells closely resemble the operators available in HDLs such as -Verilog or VHDL. Therefore Verilog operators are used in the following sections -to define the behaviour of the RTL cells. - -Note that all RTL cells have parameters indicating the size of inputs and outputs. When -passes modify RTL cells they must always keep the values of these parameters in sync with -the size of the signals connected to the inputs and outputs. - -Simulation models for the RTL cells can be found in the file {\tt techlibs/common/simlib.v} in the Yosys -source tree. - -\subsection{Unary Operators} - -All unary RTL cells have one input port \B{A} and one output port \B{Y}. They also -have the following parameters: - -\begin{itemize} -\item \B{A\_SIGNED} \\ -Set to a non-zero value if the input \B{A} is signed and therefore should be sign-extended -when needed. - -\item \B{A\_WIDTH} \\ -The width of the input port \B{A}. - -\item \B{Y\_WIDTH} \\ -The width of the output port \B{Y}. -\end{itemize} - -Table~\ref{tab:CellLib_unary} lists all cells for unary RTL operators. - -\begin{table}[t!] -\hfil -\begin{tabular}{ll} -Verilog & Cell Type \\ -\hline -\lstinline[language=Verilog]; Y = ~A ; & {\tt \$not} \\ -\lstinline[language=Verilog]; Y = +A ; & {\tt \$pos} \\ -\lstinline[language=Verilog]; Y = -A ; & {\tt \$neg} \\ -\hline -\lstinline[language=Verilog]; Y = &A ; & {\tt \$reduce\_and} \\ -\lstinline[language=Verilog]; Y = |A ; & {\tt \$reduce\_or} \\ -\lstinline[language=Verilog]; Y = ^A ; & {\tt \$reduce\_xor} \\ -\lstinline[language=Verilog]; Y = ~^A ; & {\tt \$reduce\_xnor} \\ -\hline -\lstinline[language=Verilog]; Y = |A ; & {\tt \$reduce\_bool} \\ -\lstinline[language=Verilog]; Y = !A ; & {\tt \$logic\_not} -\end{tabular} -\caption{Cell types for unary operators with their corresponding Verilog expressions.} -\label{tab:CellLib_unary} -\end{table} - -Note that {\tt \$reduce\_or} and {\tt \$reduce\_bool} actually represent the same -logic function. But the HDL frontends generate them in different situations. A -{\tt \$reduce\_or} cell is generated when the prefix {\tt |} operator is being used. A -{\tt \$reduce\_bool} cell is generated when a bit vector is used as a condition in -an {\tt if}-statement or {\tt ?:}-expression. - -\subsection{Binary Operators} - -All binary RTL cells have two input ports \B{A} and \B{B} and one output port \B{Y}. They -also have the following parameters: - -\begin{itemize} -\item \B{A\_SIGNED} \\ -Set to a non-zero value if the input \B{A} is signed and therefore should be sign-extended -when needed. - -\item \B{A\_WIDTH} \\ -The width of the input port \B{A}. - -\item \B{B\_SIGNED} \\ -Set to a non-zero value if the input \B{B} is signed and therefore should be sign-extended -when needed. - -\item \B{B\_WIDTH} \\ -The width of the input port \B{B}. - -\item \B{Y\_WIDTH} \\ -The width of the output port \B{Y}. -\end{itemize} - -Table~\ref{tab:CellLib_binary} lists all cells for binary RTL operators. - -\subsection{Multiplexers} - -Multiplexers are generated by the Verilog HDL frontend for {\tt -?:}-expressions. Multiplexers are also generated by the {\tt proc} pass to map the decision trees -from RTLIL::Process objects to logic. - -The simplest multiplexer cell type is {\tt \$mux}. Cells of this type have a \B{WIDTH} parameter -and data inputs \B{A} and \B{B} and a data output \B{Y}, all of the specified width. This cell also -has a single bit control input \B{S}. If \B{S} is 0 the value from the \B{A} input is sent to -the output, if it is 1 the value from the \B{B} input is sent to the output. So the {\tt \$mux} -cell implements the function \lstinline[language=Verilog]; Y = S ? B : A;. - -The {\tt \$pmux} cell is used to multiplex between many inputs using a one-hot select signal. Cells -of this type have a \B{WIDTH} and a \B{S\_WIDTH} parameter and inputs \B{A}, \B{B}, and \B{S} and -an output \B{Y}. The \B{S} input is \B{S\_WIDTH} bits wide. The \B{A} input and the output are both -\B{WIDTH} bits wide and the \B{B} input is \B{WIDTH}*\B{S\_WIDTH} bits wide. When all bits of -\B{S} are zero, the value from \B{A} input is sent to the output. If the $n$'th bit from \B{S} is -set, the value $n$'th \B{WIDTH} bits wide slice of the \B{B} input is sent to the output. When more -than one bit from \B{S} is set the output is undefined. Cells of this type are used to model -``parallel cases'' (defined by using the {\tt parallel\_case} attribute or detected by -an optimization). - -The {\tt \$tribuf} cell is used to implement tristate logic. Cells of this type have a \B{WIDTH} -parameter and inputs \B{A} and \B{EN} and an output \B{Y}. The \B{A} input and \B{Y} output are -\B{WIDTH} bits wide, and the \B{EN} input is one bit wide. When \B{EN} is 0, the output \B{Y} -is not driven. When \B{EN} is 1, the value from \B{A} input is sent to the \B{Y} output. Therefore, -the {\tt \$tribuf} cell implements the function \lstinline[language=Verilog]; Y = EN ? A : 'bz;. - -Behavioural code with cascaded {\tt if-then-else}- and {\tt case}-statements -usually results in trees of multiplexer cells. Many passes (from various -optimizations to FSM extraction) heavily depend on these multiplexer trees to -understand dependencies between signals. Therefore optimizations should not -break these multiplexer trees (e.g.~by replacing a multiplexer between a -calculated signal and a constant zero with an {\tt \$and} gate). - -\begin{table}[t!] -\hfil -\begin{tabular}[t]{ll} -Verilog & Cell Type \\ -\hline -\lstinline[language=Verilog]; Y = A & B; & {\tt \$and} \\ -\lstinline[language=Verilog]; Y = A | B; & {\tt \$or} \\ -\lstinline[language=Verilog]; Y = A ^ B; & {\tt \$xor} \\ -\lstinline[language=Verilog]; Y = A ~^ B; & {\tt \$xnor} \\ -\hline -\lstinline[language=Verilog]; Y = A << B; & {\tt \$shl} \\ -\lstinline[language=Verilog]; Y = A >> B; & {\tt \$shr} \\ -\lstinline[language=Verilog]; Y = A <<< B; & {\tt \$sshl} \\ -\lstinline[language=Verilog]; Y = A >>> B; & {\tt \$sshr} \\ -\hline -\lstinline[language=Verilog]; Y = A && B; & {\tt \$logic\_and} \\ -\lstinline[language=Verilog]; Y = A || B; & {\tt \$logic\_or} \\ -\hline -\lstinline[language=Verilog]; Y = A === B; & {\tt \$eqx} \\ -\lstinline[language=Verilog]; Y = A !== B; & {\tt \$nex} \\ -\end{tabular} -\hfil -\begin{tabular}[t]{ll} -Verilog & Cell Type \\ -\hline -\lstinline[language=Verilog]; Y = A < B; & {\tt \$lt} \\ -\lstinline[language=Verilog]; Y = A <= B; & {\tt \$le} \\ -\lstinline[language=Verilog]; Y = A == B; & {\tt \$eq} \\ -\lstinline[language=Verilog]; Y = A != B; & {\tt \$ne} \\ -\lstinline[language=Verilog]; Y = A >= B; & {\tt \$ge} \\ -\lstinline[language=Verilog]; Y = A > B; & {\tt \$gt} \\ -\hline -\lstinline[language=Verilog]; Y = A + B; & {\tt \$add} \\ -\lstinline[language=Verilog]; Y = A - B; & {\tt \$sub} \\ -\lstinline[language=Verilog]; Y = A * B; & {\tt \$mul} \\ -\lstinline[language=Verilog]; Y = A / B; & {\tt \$div} \\ -\lstinline[language=Verilog]; Y = A % B; & {\tt \$mod} \\ -\lstinline[language=Verilog]; Y = A ** B; & {\tt \$pow} \\ -\end{tabular} -\caption{Cell types for binary operators with their corresponding Verilog expressions.} -\label{tab:CellLib_binary} -\end{table} - -\subsection{Registers} - -D-Type Flip-Flops are represented by {\tt \$dff} cells. These cells have a clock port \B{CLK}, -an input port \B{D} and an output port \B{Q}. The following parameters are available for \$dff -cells: - -\begin{itemize} -\item \B{WIDTH} \\ -The width of input \B{D} and output \B{Q}. - -\item \B{CLK\_POLARITY} \\ -Clock is active on the positive edge if this parameter has the value {\tt 1'b1} and on the negative -edge if this parameter is {\tt 1'b0}. -\end{itemize} - -D-Type Flip-Flops with asynchronous resets are represented by {\tt \$adff} cells. As the {\tt \$dff} -cells they have \B{CLK}, \B{D} and \B{Q} ports. In addition they also have a single-bit \B{ARST} -input port for the reset pin and the following additional two parameters: - -\begin{itemize} -\item \B{ARST\_POLARITY} \\ -The asynchronous reset is high-active if this parameter has the value {\tt 1'b1} and low-active -if this parameter is {\tt 1'b0}. - -\item \B{ARST\_VALUE} \\ -The state of \B{Q} will be set to this value when the reset is active. -\end{itemize} - -Note that the {\tt \$adff} cell can only be used when the reset value is constant. - -\begin{sloppypar} -Usually these cells are generated by the {\tt proc} pass using the information -in the designs RTLIL::Process objects. -\end{sloppypar} - -\begin{fixme} -Add information about {\tt \$sr} cells (set-reset flip-flops) and d-type latches. -\end{fixme} - -\subsection{Memories} -\label{sec:memcells} - -Memories are either represented using RTLIL::Memory objects, {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} -cells, or by {\tt \$mem} cells alone. - -In the first alternative the RTLIL::Memory objects hold the general metadata for the memory (bit width, -size in number of words, etc.) and for each port a {\tt \$memrd} (read port) or {\tt \$memwr} (write port) -cell is created. Having individual cells for read and write ports has the advantage that they can be -consolidated using resource sharing passes. In some cases this drastically reduces the number of required -ports on the memory cell. In this alternative, memory initialization data is represented by {\tt \$meminit} cells, -which allow delaying constant folding for initialization addresses and data until after the frontend finishes. - -The {\tt \$memrd} cells have a clock input \B{CLK}, an enable input \B{EN}, an -address input \B{ADDR}, and a data output \B{DATA}. They also have the -following parameters: - -\begin{itemize} -\item \B{MEMID} \\ -The name of the RTLIL::Memory object that is associated with this read port. - -\item \B{ABITS} \\ -The number of address bits (width of the \B{ADDR} input port). - -\item \B{WIDTH} \\ -The number of data bits (width of the \B{DATA} output port). - -\item \B{CLK\_ENABLE} \\ -When this parameter is non-zero, the clock is used. Otherwise this read port is asynchronous and -the \B{CLK} input is not used. - -\item \B{CLK\_POLARITY} \\ -Clock is active on the positive edge if this parameter has the value {\tt 1'b1} and on the negative -edge if this parameter is {\tt 1'b0}. - -\item \B{TRANSPARENT} \\ -If this parameter is set to {\tt 1'b1}, a read and write to the same address in the same cycle will -return the new value. Otherwise the old value is returned. -\end{itemize} - -The {\tt \$memwr} cells have a clock input \B{CLK}, an enable input \B{EN} (one -enable bit for each data bit), an address input \B{ADDR} and a data input -\B{DATA}. They also have the following parameters: - -\begin{itemize} -\item \B{MEMID} \\ -The name of the RTLIL::Memory object that is associated with this write port. - -\item \B{ABITS} \\ -The number of address bits (width of the \B{ADDR} input port). - -\item \B{WIDTH} \\ -The number of data bits (width of the \B{DATA} output port). - -\item \B{CLK\_ENABLE} \\ -When this parameter is non-zero, the clock is used. Otherwise this write port is asynchronous and -the \B{CLK} input is not used. - -\item \B{CLK\_POLARITY} \\ -Clock is active on positive edge if this parameter has the value {\tt 1'b1} and on the negative -edge if this parameter is {\tt 1'b0}. - -\item \B{PRIORITY} \\ -The cell with the higher integer value in this parameter wins a write conflict. -\end{itemize} - -The {\tt \$meminit} cells have an address input \B{ADDR} and a data input \B{DATA}, with the width -of the \B{DATA} port equal to \B{WIDTH} parameter times \B{WORDS} parameter. Both of the inputs -must resolve to a constant for synthesis to succeed. - -\begin{itemize} -\item \B{MEMID} \\ -The name of the RTLIL::Memory object that is associated with this initialization cell. - -\item \B{ABITS} \\ -The number of address bits (width of the \B{ADDR} input port). - -\item \B{WIDTH} \\ -The number of data bits per memory location. - -\item \B{WORDS} \\ -The number of consecutive memory locations initialized by this cell. - -\item \B{PRIORITY} \\ -The cell with the higher integer value in this parameter wins an initialization conflict. -\end{itemize} - -The HDL frontend models a memory using RTLIL::Memory objects and asynchronous -{\tt \$memrd} and {\tt \$memwr} cells. The {\tt memory} pass (i.e.~its various sub-passes) migrates -{\tt \$dff} cells into the {\tt \$memrd} and {\tt \$memwr} cells making them synchronous, then -converts them to a single {\tt \$mem} cell and (optionally) maps this cell type -to {\tt \$dff} cells for the individual words and multiplexer-based address decoders for the read and -write interfaces. When the last step is disabled or not possible, a {\tt \$mem} cell is left in the design. - -The {\tt \$mem} cell provides the following parameters: - -\begin{itemize} -\item \B{MEMID} \\ -The name of the original RTLIL::Memory object that became this {\tt \$mem} cell. - -\item \B{SIZE} \\ -The number of words in the memory. - -\item \B{ABITS} \\ -The number of address bits. - -\item \B{WIDTH} \\ -The number of data bits per word. - -\item \B{INIT} \\ -The initial memory contents. - -\item \B{RD\_PORTS} \\ -The number of read ports on this memory cell. - -\item \B{RD\_CLK\_ENABLE} \\ -This parameter is \B{RD\_PORTS} bits wide, containing a clock enable bit for each read port. - -\item \B{RD\_CLK\_POLARITY} \\ -This parameter is \B{RD\_PORTS} bits wide, containing a clock polarity bit for each read port. - -\item \B{RD\_TRANSPARENT} \\ -This parameter is \B{RD\_PORTS} bits wide, containing a transparent bit for each read port. - -\item \B{WR\_PORTS} \\ -The number of write ports on this memory cell. - -\item \B{WR\_CLK\_ENABLE} \\ -This parameter is \B{WR\_PORTS} bits wide, containing a clock enable bit for each write port. - -\item \B{WR\_CLK\_POLARITY} \\ -This parameter is \B{WR\_PORTS} bits wide, containing a clock polarity bit for each write port. -\end{itemize} - -The {\tt \$mem} cell has the following ports: - -\begin{itemize} -\item \B{RD\_CLK} \\ -This input is \B{RD\_PORTS} bits wide, containing all clock signals for the read ports. - -\item \B{RD\_EN} \\ -This input is \B{RD\_PORTS} bits wide, containing all enable signals for the read ports. - -\item \B{RD\_ADDR} \\ -This input is \B{RD\_PORTS}*\B{ABITS} bits wide, containing all address signals for the read ports. - -\item \B{RD\_DATA} \\ -This input is \B{RD\_PORTS}*\B{WIDTH} bits wide, containing all data signals for the read ports. - -\item \B{WR\_CLK} \\ -This input is \B{WR\_PORTS} bits wide, containing all clock signals for the write ports. - -\item \B{WR\_EN} \\ -This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all enable signals for the write ports. - -\item \B{WR\_ADDR} \\ -This input is \B{WR\_PORTS}*\B{ABITS} bits wide, containing all address signals for the write ports. - -\item \B{WR\_DATA} \\ -This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all data signals for the write ports. -\end{itemize} - -The {\tt memory\_collect} pass can be used to convert discrete {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} cells -belonging to the same memory to a single {\tt \$mem} cell, whereas the {\tt memory\_unpack} pass performs the inverse operation. -The {\tt memory\_dff} pass can combine asynchronous memory ports that are fed by or feeding registers into synchronous memory ports. -The {\tt memory\_bram} pass can be used to recognize {\tt \$mem} cells that can be implemented with a block RAM resource on an FPGA. -The {\tt memory\_map} pass can be used to implement {\tt \$mem} cells as basic logic: word-wide DFFs and address decoders. - -\subsection{Finite State Machines} - -\begin{fixme} -Add a brief description of the {\tt \$fsm} cell type. -\end{fixme} - -\section{Gates} -\label{sec:celllib_gates} - -For gate level logic networks, fixed function single bit cells are used that do -not provide any parameters. - -Simulation models for these cells can be found in the file {\tt techlibs/common/simcells.v} in the Yosys -source tree. - -\begin{table}[t] -\hfil -\begin{tabular}[t]{ll} -Verilog & Cell Type \\ -\hline -\lstinline[language=Verilog]; Y = ~A; & {\tt \$\_NOT\_} \\ -\lstinline[language=Verilog]; Y = A & B; & {\tt \$\_AND\_} \\ -\lstinline[language=Verilog]; Y = ~(A & B); & {\tt \$\_NAND\_} \\ -\lstinline[language=Verilog]; Y = A & ~B; & {\tt \$\_ANDNOT\_} \\ -\lstinline[language=Verilog]; Y = A | B; & {\tt \$\_OR\_} \\ -\lstinline[language=Verilog]; Y = ~(A | B); & {\tt \$\_NOR\_} \\ -\lstinline[language=Verilog]; Y = A | ~B; & {\tt \$\_ORNOT\_} \\ -\lstinline[language=Verilog]; Y = A ^ B; & {\tt \$\_XOR\_} \\ -\lstinline[language=Verilog]; Y = ~(A ^ B); & {\tt \$\_XNOR\_} \\ -\lstinline[language=Verilog]; Y = S ? B : A; & {\tt \$\_MUX\_} \\ -\lstinline[language=Verilog]; Y = EN ? A : 'bz; & {\tt \$\_TBUF\_} \\ -\hline -\lstinline[language=Verilog]; always @(negedge C) Q <= D; & {\tt \$\_DFF\_N\_} \\ -\lstinline[language=Verilog]; always @(posedge C) Q <= D; & {\tt \$\_DFF\_P\_} \\ -\end{tabular} -\hfil -\begin{tabular}[t]{llll} -$ClkEdge$ & $RstLvl$ & $RstVal$ & Cell Type \\ -\hline -\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DFF\_NN0\_} \\ -\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DFF\_NN1\_} \\ -\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DFF\_NP0\_} \\ -\lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFF\_NP1\_} \\ -\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DFF\_PN0\_} \\ -\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DFF\_PN1\_} \\ -\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DFF\_PP0\_} \\ -\lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFF\_PP1\_} \\ -\end{tabular} -\caption{Cell types for gate level logic networks} -\label{tab:CellLib_gates} -\end{table} - -Table~\ref{tab:CellLib_gates} lists all cell types used for gate level logic. The cell types -{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_}, -{\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic. -The cell type {\tt \$\_TBUF\_} is used to model tristate logic. -The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops. - -The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_}, -{\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement -d-type flip-flops with asynchronous resets. The values in the table for these cell types relate to the -following Verilog code template, where \lstinline[mathescape,language=Verilog];$RstEdge$; is \lstinline[language=Verilog];posedge; -if \lstinline[mathescape,language=Verilog];$RstLvl$; if \lstinline[language=Verilog];1;, and \lstinline[language=Verilog];negedge; -otherwise. - -\begin{lstlisting}[mathescape,language=Verilog] - always @($ClkEdge$ C, $RstEdge$ R) - if (R == $RstLvl$) - Q <= $RstVal$; - else - Q <= D; -\end{lstlisting} - -In most cases gate level logic networks are created from RTL networks using the {\tt techmap} pass. The flip-flop cells -from the gate level logic network can be mapped to physical flip-flop cells from a Liberty file using the {\tt dfflibmap} -pass. The combinatorial logic cells can be mapped to physical cells from a Liberty file via ABC \citeweblink{ABC} -using the {\tt abc} pass. - -\begin{fixme} -Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}, {\tt \$cover}, {\tt \$equiv}, -{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$slice} and {\tt \$concat} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$lut} and {\tt \$sop} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$ff} and {\tt \$\_FF\_} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$dffe}, {\tt \$dffsr}, {\tt \$dlatch}, and {\tt \$dlatchsr} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells. -\end{fixme} - diff --git a/yosys/manual/CHAPTER_Eval.tex b/yosys/manual/CHAPTER_Eval.tex deleted file mode 100644 index f719618d5..000000000 --- a/yosys/manual/CHAPTER_Eval.tex +++ /dev/null @@ -1,209 +0,0 @@ - -\chapter{Evaluation, Conclusion, Future Work} -\label{chapter:eval} - -The Yosys source tree contains over 200 test cases\footnote{Most of this test -cases are copied from HANA \citeweblink{HANA} or the ASIC-WORLD website -\citeweblink{ASIC-WORLD}.} which are used in the {\tt make test} make-target. -Besides these there is an external Yosys benchmark and test case package that -contains a few larger designs \citeweblink{YosysTestsGit}. This package -contains the designs listed in Tab.~\ref{tab:yosys-test-designs}. - -\begin{table} - \hfil - \begin{tabular}{lrrp{8.5cm}} - Test-Design & Source & Gates\footnotemark & Description / Comments \\ - \hline - {\tt aes\_core} & IWLS2005 & $ 41{,}837 $ & \footnotesize AES Cipher written by Rudolf Usselmann \\ - {\tt i2c} & IWLS2005 & $ 1{,}072 $ & \footnotesize WISHBONE compliant I2C Master by Richard Herveille \\ - {\tt openmsp430} & OpenCores & $ 7{,}173 $ & \footnotesize MSP430 compatible CPU by Olivier Girard \\ - {\tt or1200} & OpenCores & $ 42{,}675 $ & \footnotesize The OpenRISC 1200 CPU by Damjan Lampret \\ - {\tt sasc} & IWLS2005 & $ 456 $ & \footnotesize Simple Async. Serial Comm. Device by Rudolf Usselmann \\ - {\tt simple\_spi} & IWLS2005 & $ 690 $ & \footnotesize MC68HC11E based SPI interface by Richard Herveille \\ - {\tt spi} & IWLS2005 & $ 2{,}478 $ & \footnotesize SPI IP core by Simon Srot \\ - {\tt ss\_pcm} & IWLS2005 & $ 279 $ & \footnotesize PCM IO Slave by Rudolf Usselmann \\ - {\tt systemcaes} & IWLS2005 & $ 6{,}893 $ & \footnotesize AES core (using SystemC to Verilog) by Javier Castillo \\ - {\tt usb\_phy} & IWLS2005 & $ 515 $ & \footnotesize USB 1.1 PHY by Rudolf Usselmann \\ - \end{tabular} - \caption{Tests included in the yosys-tests package.} - \label{tab:yosys-test-designs} -\end{table} - -\footnotetext{ -Number of gates determined using the Yosys synthesis script ``{\tt hierarchy -top \$top; proc; opt; memory; opt; techmap; opt; abc; opt; flatten \$top; hierarchy -top \$top; abc; opt; select -count */c:*}''. -} - -\section{Correctness of Synthesis Results} - -The following measures were taken to increase the confidence in the correctness of the Yosys synthesis results: - -\begin{itemize} -\item Yosys comes with a large selection\footnote{At the time of this writing -269 test cases.} of small test cases that are evaluated when the command {\tt -make test} is executed. During development of Yosys it was shown that this -collection of test cases is sufficient to catch most bugs. The following more -sophisticated test procedures only caught a few additional bugs. Whenever this -happened, an appropriate test case was added to the collection of small test -cases for {\tt make test} to ensure better testability of the feature in -question in the future. - -\item The designs listed in Tab.~\ref{tab:yosys-test-designs} where validated -using the formal verification tool Synopsys Formality\citeweblink{Formality}. -The Yosys synthesis scripts used to synthesize the individual designs for this -test are slightly different per design in order to broaden the coverage of -Yosys features. The large majority of all errors encountered using these tests -are false-negatives, mostly related to FSM encoding or signal naming in large -array logic (such as in memory blocks). Therefore the {\tt fsm\_recode} pass -was extended so it can be used to generate TCL commands for Synopsys Formality -that describe the relationship between old and new state encodings. Also the -method used to generate signal and cell names in the Verilog backend was -slightly modified in order to improve the automatic matching of net names in -Synopsys Formality. With these changes in place all designs in Tab.~\ref{tab:yosys-test-designs} -validate successfully using Formality. - -\item VlogHammer \citeweblink{VlogHammer} is a set of scripts that -auto-generate a large collection of test cases\footnote{At the time of this -writing over 6600 test cases.} and synthesize them using Yosys and the -following freely available proprietary synthesis tools. -\begin{itemize} -\item Xilinx Vivado WebPack (2013.2) \citeweblink{XilinxWebPACK} -\item Xilinx ISE (XST) WebPack (14.5) \citeweblink{XilinxWebPACK} -\item Altera Quartus II Web Edition (13.0) \citeweblink{QuartusWeb} -\end{itemize} -The built-in SAT solver of Yosys is used to formally -verify the Yosys RTL- and Gate-Level netlists against the netlists generated by -this other tools.\footnote{A SAT solver is a program that can solve the boolean -satisfiability problem. The built-in SAT solver in Yosys can be used for formal -equivalence checking, amongst other things. See Sec.~\ref{cmd:sat} for details.} -When differences are found, the input pattern that result in -different outputs are used for simulating the original Verilog code as well as -the synthesis results using the following Verilog simulators. -\begin{itemize} -\item Xilinx ISIM (from Xilinx ISE 14.5 \citeweblink{XilinxWebPACK}) -\item Modelsim 10.1d (from Quartus II 13.0 \citeweblink{QuartusWeb}) -\item Icarus Verilog (no specific version) -\end{itemize} -The set of tests performed by VlogHammer systematically verify the correct -behaviour of -\begin{itemize} -\item Yosys Verilog Frontend and RTL generation -\item Yosys Gate-Level Technology Mapping -\item Yosys SAT Models for RTL- and Gate-Level cells -\item Yosys Constant Evaluator Models for RTL- and Gate-Level cells -\end{itemize} -against the reference provided by the other tools. A few bugs related to sign -extensions and bit-width extensions where found (and have been fixed meanwhile) -using this approach. This test also revealed a small number of bugs in the -other tools (i.e.~Vivado, XST, Quartus, ISIM and Icarus Verilog; no bugs where -found in Modelsim using vlogHammer so far). -\end{itemize} - -Although complex software can never be expected to be fully bug-free -\cite{MURPHY}, it has been shown that Yosys is mature and feature-complete -enough to handle most real-world cases correctly. - -\section{Quality of synthesis results} - -In this section an attempt to evaluate the quality of Yosys synthesis results is made. To this end the -synthesis results of a commercial FPGA synthesis tool when presented with the original HDL code vs.~when -presented with the Yosys synthesis result are compared. - -The OpenMSP430 and the OpenRISC 1200 test cases were synthesized using the following Yosys synthesis script: - -\begin{lstlisting}[numbers=left,frame=single,mathescape] -hierarchy -check -proc; opt; fsm; opt; memory; opt -techmap; opt; abc; opt -\end{lstlisting} - -The original RTL and the Yosys output where both passed to the Xilinx XST 14.5 -FPGA synthesis tool. The following setting where used for XST: - -\begin{lstlisting}[numbers=left,frame=single,mathescape] --p artix7 --use_dsp48 NO --iobuf NO --ram_extract NO --rom_extract NO --fsm_extract YES --fsm_encoding Auto -\end{lstlisting} - -The results of this comparison is summarized in Tab.~\ref{tab:synth-test}. The -used FPGA resources (registers and LUTs) and performance (maximum frequency as -reported by XST) are given per module (indentation indicates module hierarchy, -the numbers are including all contained modules). - -For most modules the results are very similar between XST and Yosys. XST is -used in both cases for the final mapping of logic to LUTs. So this comparison -only compares the high-level synthesis functions (such as FSM extraction and -encoding) of Yosys and XST. - -\begin{table} - \def\nomhz{--- \phantom{MHz}} - \def\P#1 {(#1\hbox to 0px{)\hss}} - \hfil - \begin{tabular}{l|rrr|rrr} - & \multicolumn{3}{c|}{Without Yosys} & \multicolumn{3}{c}{With Yosys} \\ - Module & Regs & LUTs & Max. Freq. & Regs & LUTs & Max. Freq. \\ - \hline - {\tt openMSP430} & 689 & 2210 & 71 MHz & 719 & 2779 & 53 MHz \\ - {\tt \hskip1em omsp\_clock\_module} & 21 & 30 & 645 MHz & 21 & 30 & 644 MHz \\ - {\tt \hskip1em \hskip1em omsp\_sync\_cell} & 2 & --- & 1542 MHz & 2 & --- & 1542 MHz \\ - {\tt \hskip1em \hskip1em omsp\_sync\_reset} & 2 & --- & 1542 MHz & 2 & --- & 1542 MHz \\ - {\tt \hskip1em omsp\_dbg} & 143 & 344 & 292 MHz & 149 & 430 & 353 MHz \\ - {\tt \hskip1em \hskip1em omsp\_dbg\_uart} & 76 & 135 & 377 MHz & 79 & 139 & 389 MHz \\ - {\tt \hskip1em omsp\_execution\_unit} & 266 & 911 & 80 MHz & 266 & 1034 & 137 MHz \\ - {\tt \hskip1em \hskip1em omsp\_alu} & --- & 202 & \nomhz & --- & 263 & \nomhz \\ - {\tt \hskip1em \hskip1em omsp\_register\_file} & 231 & 478 & 285 MHz & 231 & 506 & 293 MHz \\ - {\tt \hskip1em omsp\_frontend} & 115 & 340 & 178 MHz & 118 & 527 & 206 MHz \\ - {\tt \hskip1em omsp\_mem\_backbone} & 38 & 141 & 1087 MHz & 38 & 144 & 1087 MHz \\ - {\tt \hskip1em omsp\_multiplier} & 73 & 397 & 129 MHz & 102 & 1053 & 55 MHz \\ - {\tt \hskip1em omsp\_sfr} & 6 & 18 & 1023 MHz & 6 & 20 & 1023 MHz \\ - {\tt \hskip1em omsp\_watchdog} & 24 & 53 & 362 MHz & 24 & 70 & 360 MHz \\ - \hline - {\tt or1200\_top} & 7148 & 9969 & 135 MHz & 7173 & 10238 & 108 MHz \\ - {\tt \hskip1em or1200\_alu} & --- & 681 & \nomhz & --- & 641 & \nomhz \\ - {\tt \hskip1em or1200\_cfgr} & --- & 11 & \nomhz & --- & 11 & \nomhz \\ - {\tt \hskip1em or1200\_ctrl} & 175 & 186 & 464 MHz & 174 & 279 & 377 MHz \\ - {\tt \hskip1em or1200\_except} & 241 & 451 & 313 MHz & 241 & 353 & 301 MHz \\ - {\tt \hskip1em or1200\_freeze} & 6 & 18 & 507 MHz & 6 & 16 & 515 MHz \\ - {\tt \hskip1em or1200\_if} & 68 & 143 & 806 MHz & 68 & 139 & 790 MHz \\ - {\tt \hskip1em or1200\_lsu} & 8 & 138 & \nomhz & 12 & 205 & 1306 MHz \\ - {\tt \hskip1em \hskip1em or1200\_mem2reg} & --- & 60 & \nomhz & --- & 66 & \nomhz \\ - {\tt \hskip1em \hskip1em or1200\_reg2mem} & --- & 29 & \nomhz & --- & 29 & \nomhz \\ - {\tt \hskip1em or1200\_mult\_mac} & 394 & 2209 & 240 MHz & 394 & 2230 & 241 MHz \\ - {\tt \hskip1em \hskip1em or1200\_amultp2\_32x32} & 256 & 1783 & 240 MHz & 256 & 1770 & 241 MHz \\ - {\tt \hskip1em or1200\_operandmuxes} & 65 & 129 & 1145 MHz & 65 & 129 & 1145 MHz \\ - {\tt \hskip1em or1200\_rf} & 1041 & 1722 & 822 MHz & 1042 & 1722 & 581 MHz \\ - {\tt \hskip1em or1200\_sprs} & 18 & 432 & 724 MHz & 18 & 469 & 722 MHz \\ - {\tt \hskip1em or1200\_wbmux} & 33 & 93 & \nomhz & 33 & 78 & \nomhz \\ - {\tt \hskip1em or1200\_dc\_top} & --- & 5 & \nomhz & --- & 5 & \nomhz \\ - {\tt \hskip1em or1200\_dmmu\_top} & 2445 & 1004 & \nomhz & 2445 & 1043 & \nomhz \\ - {\tt \hskip1em \hskip1em or1200\_dmmu\_tlb} & 2444 & 975 & \nomhz & 2444 & 1013 & \nomhz \\ - {\tt \hskip1em or1200\_du} & 67 & 56 & 859 MHz & 67 & 56 & 859 MHz \\ - {\tt \hskip1em or1200\_ic\_top} & 39 & 100 & 527 MHz & 41 & 136 & 514 MHz \\ - {\tt \hskip1em \hskip1em or1200\_ic\_fsm} & 40 & 42 & 408 MHz & 40 & 75 & 484 MHz \\ - {\tt \hskip1em or1200\_pic} & 38 & 50 & 1169 MHz & 38 & 50 & 1177 MHz \\ - {\tt \hskip1em or1200\_tt} & 64 & 112 & 370 MHz & 64 & 186 & 437 MHz \\ - \end{tabular} - \caption{Synthesis results (as reported by XST) for OpenMSP430 and OpenRISC 1200} - \label{tab:synth-test} -\end{table} - -\section{Conclusion and Future Work} - -Yosys is capable of correctly synthesizing real-world Verilog designs. The -generated netlists are of a decent quality. However, in cases where dedicated -hardware resources should be used for certain functions it is of course -necessary to implement proper technology mapping for these functions in -Yosys. This can be as easy as calling the {\tt techmap} pass with an -architecture-specific mapping file in the synthesis script. As no such thing -has been done in the above tests, it is only natural that the resulting designs -cannot benefit from these dedicated hardware resources. - -Therefore future work includes the implementation of architecture-specific -technology mappings besides additional frontends (VHDL), backends (EDIF), -and above all else, application specific passes. After all, this was -the main motivation for the development of Yosys in the first place. - diff --git a/yosys/manual/CHAPTER_Eval/grep-it.sh b/yosys/manual/CHAPTER_Eval/grep-it.sh deleted file mode 100644 index 0f4f95ae5..000000000 --- a/yosys/manual/CHAPTER_Eval/grep-it.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash - -openmsp430_mods=" -omsp_alu -omsp_clock_module -omsp_dbg -omsp_dbg_uart -omsp_execution_unit -omsp_frontend -omsp_mem_backbone -omsp_multiplier -omsp_register_file -omsp_sfr -omsp_sync_cell -omsp_sync_reset -omsp_watchdog -openMSP430" - -or1200_mods=" -or1200_alu -or1200_amultp2_32x32 -or1200_cfgr -or1200_ctrl -or1200_dc_top -or1200_dmmu_tlb -or1200_dmmu_top -or1200_du -or1200_except -or1200_fpu -or1200_freeze -or1200_ic_fsm -or1200_ic_ram -or1200_ic_tag -or1200_ic_top -or1200_if -or1200_immu_tlb -or1200_lsu -or1200_mem2reg -or1200_mult_mac -or1200_operandmuxes -or1200_pic -or1200_pm -or1200_qmem_top -or1200_reg2mem -or1200_rf -or1200_sb -or1200_sprs -or1200_top -or1200_tt -or1200_wbmux" - -grep_regs() { - x=$(grep '^ Number of Slice Registers:' $1.syr | sed 's/.*: *//;' | cut -f1 -d' ') - echo $x | sed 's,^ *$,-1,' -} - -grep_luts() { - x=$(grep '^ Number of Slice LUTs:' $1.syr | sed 's/.*: *//;' | cut -f1 -d' ') - echo $x | sed 's,^ *$,-1,' -} - -grep_freq() { - x=$(grep 'Minimum period.*Maximum Frequency' $1.syr | sed 's/\.[0-9]*MHz.*//;' | cut -f3 -d:) - echo $x | sed 's,^ *$,-1,' -} - -for mod in $openmsp430_mods $or1200_mods; do - printf '%-30s s,$, \\& %6d \\& %6d \\& %4d MHz \\& %6d \\& %6d \\& %4d MHz \\\\\\\\,;\n' "/${mod//_/\\\\_}}/" \ - $(grep_regs ${mod}) $(grep_luts ${mod}) $(grep_freq ${mod}) \ - $(grep_regs ${mod}_ys) $(grep_luts ${mod}_ys) $(grep_freq ${mod}_ys) -done - -# for mod in $openmsp430_mods $or1200_mods; do -# [ $mod = "or1200_top" -o $mod = "or1200_dmmu_top" -o $mod = or1200_dmmu_tlb -o $mod = or1200_immu_tlb ] && continue -# regs=$(grep_regs ${mod}) regs_ys=$(grep_regs ${mod}_ys) -# luts=$(grep_luts ${mod}) luts_ys=$(grep_luts ${mod}_ys) -# freq=$(grep_freq ${mod}) freq_ys=$(grep_freq ${mod}_ys) -# if [ $regs -gt 0 -a $regs_ys -gt 0 ]; then regs_p=$(( 100*regs_ys / regs )); else regs_p=NaN; fi -# if [ $luts -gt 0 -a $luts_ys -gt 0 ]; then luts_p=$(( 100*luts_ys / luts )); else luts_p=NaN; fi -# if [ $freq -gt 0 -a $freq_ys -gt 0 ]; then freq_p=$(( 100*freq_ys / freq )); else freq_p=NaN; fi -# printf '%-30s %3s %3s %3s\n' $mod $regs_p $luts_p $freq_p -# -# done - diff --git a/yosys/manual/CHAPTER_Eval/openmsp430.prj b/yosys/manual/CHAPTER_Eval/openmsp430.prj deleted file mode 100644 index cb8cd2714..000000000 --- a/yosys/manual/CHAPTER_Eval/openmsp430.prj +++ /dev/null @@ -1,14 +0,0 @@ -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_sync_cell.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_sync_reset.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_register_file.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_dbg_uart.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_alu.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_watchdog.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_sfr.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_multiplier.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_mem_backbone.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_frontend.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_execution_unit.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_dbg.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/omsp_clock_module.v" -verilog work "../../../../../Work/yosys-tests/openmsp430/rtl/openMSP430.v" diff --git a/yosys/manual/CHAPTER_Eval/openmsp430_ys.prj b/yosys/manual/CHAPTER_Eval/openmsp430_ys.prj deleted file mode 100644 index 0009c99dc..000000000 --- a/yosys/manual/CHAPTER_Eval/openmsp430_ys.prj +++ /dev/null @@ -1 +0,0 @@ -verilog work "openmsp430_ys.v" diff --git a/yosys/manual/CHAPTER_Eval/or1200.prj b/yosys/manual/CHAPTER_Eval/or1200.prj deleted file mode 100644 index 9496874e0..000000000 --- a/yosys/manual/CHAPTER_Eval/or1200.prj +++ /dev/null @@ -1,37 +0,0 @@ -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_spram.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_reg2mem.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_mem2reg.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_dpram.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_amultp2_32x32.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_wbmux.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_sprs.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_rf.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_operandmuxes.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_mult_mac.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_lsu.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_immu_tlb.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_if.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_ic_tag.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_ic_ram.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_ic_fsm.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_genpc.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_freeze.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_fpu.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_except.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_dmmu_tlb.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_ctrl.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_cfgr.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_alu.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_wb_biu.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_tt.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_sb.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_qmem_top.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_pm.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_pic.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_immu_top.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_ic_top.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_du.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_dmmu_top.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_dc_top.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_cpu.v" -verilog work "../../../../../Work/yosys-tests/or1200/rtl/or1200_top.v" diff --git a/yosys/manual/CHAPTER_Eval/or1200_ys.prj b/yosys/manual/CHAPTER_Eval/or1200_ys.prj deleted file mode 100644 index 4dd5f41a0..000000000 --- a/yosys/manual/CHAPTER_Eval/or1200_ys.prj +++ /dev/null @@ -1 +0,0 @@ -verilog work "or1200_ys.v" diff --git a/yosys/manual/CHAPTER_Eval/run-it.sh b/yosys/manual/CHAPTER_Eval/run-it.sh deleted file mode 100644 index b4a67cebd..000000000 --- a/yosys/manual/CHAPTER_Eval/run-it.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -openmsp430_mods=" -omsp_alu -omsp_clock_module -omsp_dbg -omsp_dbg_uart -omsp_execution_unit -omsp_frontend -omsp_mem_backbone -omsp_multiplier -omsp_register_file -omsp_sfr -omsp_sync_cell -omsp_sync_reset -omsp_watchdog -openMSP430" - -or1200_mods=" -or1200_alu -or1200_amultp2_32x32 -or1200_cfgr -or1200_ctrl -or1200_dc_top -or1200_dmmu_tlb -or1200_dmmu_top -or1200_du -or1200_except -or1200_fpu -or1200_freeze -or1200_ic_fsm -or1200_ic_ram -or1200_ic_tag -or1200_ic_top -or1200_if -or1200_immu_tlb -or1200_lsu -or1200_mem2reg -or1200_mult_mac -or1200_operandmuxes -or1200_pic -or1200_pm -or1200_qmem_top -or1200_reg2mem -or1200_rf -or1200_sb -or1200_sprs -or1200_top -or1200_tt -or1200_wbmux" - -yosys_cmds="hierarchy -check; proc; opt; fsm; opt; memory; opt; techmap; opt; abc; opt" - -yosys -p "$yosys_cmds" -o openmsp430_ys.v $( cut -f2 -d'"' openmsp430.prj ) -yosys -p "$yosys_cmds" -o or1200_ys.v $( cut -f2 -d'"' or1200.prj ) - -. /opt/Xilinx/14.5/ISE_DS/settings64.sh - -run_single() { - prj_file=$1 top_module=$2 out_file=$3 - sed "s/@prj_file@/$prj_file/g; s/@out_file@/$out_file/g; s/@top_module@/$top_module/g;" < settings.xst > ${out_file}.xst - xst -ifn ${out_file}.xst -ofn ${out_file}.syr -} - -for mod in $openmsp430_mods; do - run_single openmsp430.prj ${mod} ${mod} - run_single openmsp430_ys.prj ${mod} ${mod}_ys -done - -for mod in $or1200_mods; do - run_single or1200.prj ${mod} ${mod} - run_single or1200_ys.prj ${mod} ${mod}_ys -done - diff --git a/yosys/manual/CHAPTER_Eval/settings.xst b/yosys/manual/CHAPTER_Eval/settings.xst deleted file mode 100644 index 2f381d09d..000000000 --- a/yosys/manual/CHAPTER_Eval/settings.xst +++ /dev/null @@ -1,2 +0,0 @@ -run -ifn @prj_file@ -ofn @out_file@ -ofmt NGC -top @top_module@ -p artix7 --use_dsp48 NO -iobuf NO -ram_extract NO -rom_extract NO -fsm_extract YES -fsm_encoding Auto diff --git a/yosys/manual/CHAPTER_Intro.tex b/yosys/manual/CHAPTER_Intro.tex deleted file mode 100644 index 76e5d847b..000000000 --- a/yosys/manual/CHAPTER_Intro.tex +++ /dev/null @@ -1,98 +0,0 @@ - -\chapter{Introduction} -\label{chapter:intro} - -This document presents the Free and Open Source (FOSS) Verilog HDL synthesis tool ``Yosys''. -Its design and implementation as well as its performance on real-world designs -is discussed in this document. - -\section{History of Yosys} - -A Hardware Description Language (HDL) is a computer language used to describe -circuits. A HDL synthesis tool is a computer program that takes a formal -description of a circuit written in an HDL as input and generates a netlist -that implements the given circuit as output. - -Currently the most widely used and supported HDLs for digital circuits are -Verilog \cite{Verilog2005}\cite{VerilogSynth} and -VHDL\footnote{VHDL is an acronym for ``VHSIC hardware description language'' -and VHSIC is an acronym for ``Very-High-Speed Integrated -Circuits''.} \cite{VHDL}\cite{VHDLSynth}. -Both HDLs are used for test and verification purposes as well as logic -synthesis, resulting in a set of synthesizable and a set of non-synthesizable -language features. In this document we only look at the synthesizable subset -of the language features. - -In recent work on heterogeneous coarse-grain reconfigurable -logic \cite{intersynth} the need for a custom application-specific HDL synthesis -tool emerged. It was soon realised that a synthesis tool that understood Verilog -or VHDL would be preferred over a synthesis tool for a custom HDL. Given an -existing Verilog or VHDL front end, the work for writing the necessary -additional features and integrating them in an existing tool can be estimated to be -about the same as writing a new tool with support for a minimalistic custom HDL. - -The proposed custom HDL synthesis tool should be licensed under a Free -and Open Source Software (FOSS) licence. So an existing FOSS Verilog or VHDL -synthesis tool would have been needed as basis to build upon. The main advantages -of choosing Verilog or VHDL is the ability to synthesize existing HDL code and -to mitigate the requirement for circuit-designers to learn a new language. In order to take full advantage of any existing FOSS Verilog or VHDL tool, -such a tool would have to provide a feature-complete implementation of the -synthesizable HDL subset. - -Basic RTL synthesis is a well understood field \cite{LogicSynthesis}. Lexing, -parsing and processing of computer languages \cite{Dragonbook} is a thoroughly -researched field. All the information required to write such tools has been openly -available for a long time, and it is therefore likely that a FOSS HDL synthesis tool -with a feature-complete Verilog or VHDL front end must exist which can be used as a basis for a custom RTL synthesis tool. - -Due to the author's preference for Verilog over VHDL it was decided early -on to go for Verilog instead of VHDL\footnote{A quick investigation into FOSS -VHDL tools yielded similar grim results for FOSS VHDL synthesis tools.}. -So the existing FOSS Verilog synthesis tools were evaluated (see -App.~\ref{chapter:sota}). The results of this evaluation are utterly -devastating. Therefore a completely new Verilog synthesis tool was implemented -and is recommended as basis for custom synthesis tools. This is the tool that -is discussed in this document. - -\section{Structure of this Document} - -The structure of this document is as follows: - -Chapter~\ref{chapter:intro} is this introduction. - -Chapter~\ref{chapter:basics} covers a short introduction to the world of HDL -synthesis. Basic principles and the terminology are outlined in this chapter. - -Chapter~\ref{chapter:approach} gives the quickest possible outline to how the -problem of implementing a HDL synthesis tool is approached in the case of -Yosys. - -Chapter~\ref{chapter:overview} contains a more detailed overview of the -implementation of Yosys. This chapter covers the data structures used in -Yosys to represent a design in detail and is therefore recommended reading -for everyone who is interested in understanding the Yosys internals. - -Chapter~\ref{chapter:celllib} covers the internal cell library used by Yosys. -This is especially important knowledge for anyone who wants to understand the -intermediate netlists used internally by Yosys. - -Chapter~ \ref{chapter:prog} gives a tour to the internal APIs of Yosys. This -is recommended reading for everyone who actually wants to read or write -Yosys source code. The chapter concludes with an example loadable module -for Yosys. - -Chapters~\ref{chapter:verilog}, \ref{chapter:opt}, and \ref{chapter:techmap} -cover three important pieces of the synthesis pipeline: The Verilog frontend, -the optimization passes and the technology mapping to the target architecture, -respectively. - -Chapter~\ref{chapter:eval} covers the evaluation of the performance -(correctness and quality) of Yosys on real-world input data. -The chapter concludes the main part of this document with conclusions and -outlook to future work. - -Various appendices, including a command reference manual -(App.~\ref{commandref}) and an evaluation of pre-existing FOSS Verilog -synthesis tools (App.~\ref{chapter:sota}) complete this document. - - diff --git a/yosys/manual/CHAPTER_Optimize.tex b/yosys/manual/CHAPTER_Optimize.tex deleted file mode 100644 index eee92ef5c..000000000 --- a/yosys/manual/CHAPTER_Optimize.tex +++ /dev/null @@ -1,324 +0,0 @@ - -\chapter{Optimizations} -\label{chapter:opt} - -Yosys employs a number of optimizations to generate better and cleaner results. -This chapter outlines these optimizations. - -\section{Simple Optimizations} - -The Yosys pass {\tt opt} runs a number of simple optimizations. This includes removing unused -signals and cells and const folding. It is recommended to run this pass after each major step -in the synthesis script. At the time of this writing the {\tt opt} pass executes the following -passes that each perform a simple optimization: - -\begin{itemize} -\item Once at the beginning of {\tt opt}: -\begin{itemize} -\item {\tt opt\_expr} -\item {\tt opt\_merge -nomux} -\end{itemize} -\item Repeat until result is stable: -\begin{itemize} -\item {\tt opt\_muxtree} -\item {\tt opt\_reduce} -\item {\tt opt\_merge} -\item {\tt opt\_rmdff} -\item {\tt opt\_clean} -\item {\tt opt\_expr} -\end{itemize} -\end{itemize} - -The following section describes each of the {\tt opt\_*} passes. - -\subsection{The opt\_expr pass} - -This pass performs const folding on the internal combinational cell types -described in Chap.~\ref{chapter:celllib}. This means a cell with all constant -inputs is replaced with the constant value this cell drives. In some cases -this pass can also optimize cells with some constant inputs. - -\begin{table} - \hfil - \begin{tabular}{cc|c} - A-Input & B-Input & Replacement \\ - \hline - any & 0 & 0 \\ - 0 & any & 0 \\ - 1 & 1 & 1 \\ - \hline - X/Z & X/Z & X \\ - 1 & X/Z & X \\ - X/Z & 1 & X \\ - \hline - any & X/Z & 0 \\ - X/Z & any & 0 \\ - \hline - $a$ & 1 & $a$ \\ - 1 & $b$ & $b$ \\ - \end{tabular} - \caption{Const folding rules for {\tt\$\_AND\_} cells as used in {\tt opt\_expr}.} - \label{tab:opt_expr_and} -\end{table} - -Table~\ref{tab:opt_expr_and} shows the replacement rules used for optimizing -an {\tt\$\_AND\_} gate. The first three rules implement the obvious const folding -rules. Note that `any' might include dynamic values calculated by other parts -of the circuit. The following three lines propagate undef (X) states. -These are the only three cases in which it is allowed to propagate an undef -according to Sec.~5.1.10 of IEEE Std. 1364-2005 \cite{Verilog2005}. - -The next two lines assume the value 0 for undef states. These two rules are only -used if no other substitutions are possible in the current module. If other substitutions -are possible they are performed first, in the hope that the `any' will change to -an undef value or a 1 and therefore the output can be set to undef. - -The last two lines simply replace an {\tt\$\_AND\_} gate with one constant-1 -input with a buffer. - -Besides this basic const folding the {\tt opt\_expr} pass can replace 1-bit wide -{\tt \$eq} and {\tt \$ne} cells with buffers or not-gates if one input is constant. - -The {\tt opt\_expr} pass is very conservative regarding optimizing {\tt \$mux} cells, -as these cells are often used to model decision-trees and breaking these trees can -interfere with other optimizations. - -\subsection{The opt\_muxtree pass} - -This pass optimizes trees of multiplexer cells by analyzing the select inputs. -Consider the following simple example: - -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -module uut(a, y); -input a; -output [1:0] y = a ? (a ? 1 : 2) : 3; -endmodule -\end{lstlisting} - -The output can never be 2, as this would require \lstinline[language=Verilog];a; -to be 1 for the outer multiplexer and 0 for the inner multiplexer. The {\tt -opt\_muxtree} pass detects this contradiction and replaces the inner multiplexer -with a constant 1, yielding the logic for \lstinline[language=Verilog];y = a ? 1 : 3;. - -\subsection{The opt\_reduce pass} - -\begin{sloppypar} -This is a simple optimization pass that identifies and consolidates identical input -bits to {\tt \$reduce\_and} and {\tt \$reduce\_or} cells. It also sorts the input -bits to ease identification of shareable {\tt \$reduce\_and} and {\tt \$reduce\_or} cells -in other passes. -\end{sloppypar} - -This pass also identifies and consolidates identical inputs to multiplexer cells. In this -case the new shared select bit is driven using a {\tt \$reduce\_or} cell that combines -the original select bits. - -Lastly this pass consolidates trees of {\tt \$reduce\_and} cells and trees of -{\tt \$reduce\_or} cells to single large {\tt \$reduce\_and} or {\tt \$reduce\_or} cells. - -These three simple optimizations are performed in a loop until a stable result is -produced. - -\subsection{The opt\_rmdff pass} - -This pass identifies single-bit d-type flip-flops ({\tt \$\_DFF\_*}, {\tt \$dff}, and {\tt -\$adff} cells) with a constant data input and replaces them with a constant driver. - -\subsection{The opt\_clean pass} - -This pass identifies unused signals and cells and removes them from the design. It also -creates an \B{unused\_bits} attribute on wires with unused bits. This attribute can be -used for debugging or by other optimization passes. - -\subsection{The opt\_merge pass} - -This pass performs trivial resource sharing. This means that this pass identifies cells -with identical inputs and replaces them with a single instance of the cell. - -The option {\tt -nomux} can be used to disable resource sharing for multiplexer -cells ({\tt \$mux} and {\tt \$pmux}. This can be useful as -it prevents multiplexer trees to be merged, which might prevent {\tt opt\_muxtree} -to identify possible optimizations. - -\section{FSM Extraction and Encoding} - -The {\tt fsm} pass performs finite-state-machine (FSM) extraction and recoding. The {\tt fsm} -pass simply executes the following other passes: - -\begin{itemize} -\item Identify and extract FSMs: -\begin{itemize} -\item {\tt fsm\_detect} -\item {\tt fsm\_extract} -\end{itemize} - -\item Basic optimizations: -\begin{itemize} -\item {\tt fsm\_opt} -\item {\tt opt\_clean} -\item {\tt fsm\_opt} -\end{itemize} - -\item Expanding to nearby gate-logic (if called with {\tt -expand}): -\begin{itemize} -\item {\tt fsm\_expand} -\item {\tt opt\_clean} -\item {\tt fsm\_opt} -\end{itemize} - -\item Re-code FSM states (unless called with {\tt -norecode}): -\begin{itemize} -\item {\tt fsm\_recode} -\end{itemize} - -\item Print information about FSMs: -\begin{itemize} -\item {\tt fsm\_info} -\end{itemize} - -\item Export FSMs in KISS2 file format (if called with {\tt -export}): -\begin{itemize} -\item {\tt fsm\_export} -\end{itemize} - -\item Map FSMs to RTL cells (unless called with {\tt -nomap}): -\begin{itemize} -\item {\tt fsm\_map} -\end{itemize} -\end{itemize} - -The {\tt fsm\_detect} pass identifies FSM state registers and marks them using the -\B{fsm\_encoding}{\tt = "auto"} attribute. The {\tt fsm\_extract} extracts all -FSMs marked using the \B{fsm\_encoding} attribute (unless \B{fsm\_encoding} is -set to {\tt "none"}) and replaces the corresponding RTL cells with a {\tt \$fsm} -cell. All other {\tt fsm\_*} passes operate on these {\tt \$fsm} cells. The -{\tt fsm\_map} call finally replaces the {\tt \$fsm} cells with RTL cells. - -Note that these optimizations operate on an RTL netlist. I.e.~the {\tt fsm} pass -should be executed after the {\tt proc} pass has transformed all -{\tt RTLIL::Process} objects to RTL cells. - -The algorithms used for FSM detection and extraction are influenced by a more -general reported technique \cite{fsmextract}. - -\subsection{FSM Detection} - -The {\tt fsm\_detect} pass identifies FSM state registers. It sets the -\B{fsm\_encoding}{\tt = "auto"} attribute on any (multi-bit) wire that matches -the following description: - -\begin{itemize} -\item Does not already have the \B{fsm\_encoding} attribute. -\item Is not an output of the containing module. -\item Is driven by single {\tt \$dff} or {\tt \$adff} cell. -\item The \B{D}-Input of this {\tt \$dff} or {\tt \$adff} cell is driven by a multiplexer -tree that only has constants or the old state value on its leaves. -\item The state value is only used in the said multiplexer tree or by simple relational -cells that compare the state value to a constant (usually {\tt \$eq} cells). -\end{itemize} - -This heuristic has proven to work very well. It is possible to overwrite it by setting -\B{fsm\_encoding}{\tt = "auto"} on registers that should be considered FSM state registers -and setting \B{fsm\_encoding}{\tt = "none"} on registers that match the above criteria -but should not be considered FSM state registers. - -Note however that marking state registers with \B{fsm\_encoding} that are not -suitable for FSM recoding can cause synthesis to fail or produce invalid -results. - -\subsection{FSM Extraction} - -The {\tt fsm\_extract} pass operates on all state signals marked with the -\B{fsm\_encoding} ({\tt != "none"}) attribute. For each state signal the following -information is determined: - -\begin{itemize} -\item The state registers -\item The asynchronous reset state if the state registers use asynchronous reset -\item All states and the control input signals used in the state transition functions -\item The control output signals calculated from the state signals and control inputs -\item A table of all state transitions and corresponding control inputs- and outputs -\end{itemize} - -The state registers (and asynchronous reset state, if applicable) is simply determined -by identifying the driver for the state signal. - -From there the {\tt \$mux}-tree driving the state register inputs is -recursively traversed. All select inputs are control signals and the leaves of the -{\tt \$mux}-tree are the states. The algorithm fails if a non-constant leaf -that is not the state signal itself is found. - -The list of control outputs is initialized with the bits from the state signal. -It is then extended by adding all values that are calculated by cells that -compare the state signal with a constant value. - -In most cases this will cover all uses of the state register, thus rendering the -state encoding arbitrary. If however a design uses e.g.~a single bit of the state -value to drive a control output directly, this bit of the state signal will be -transformed to a control output of the same value. - -Finally, a transition table for the FSM is generated. This is done by using the -{\tt ConstEval} C++ helper class (defined in {\tt kernel/consteval.h}) that can -be used to evaluate parts of the design. The {\tt ConstEval} class can be asked -to calculate a given set of result signals using a set of signal-value -assignments. It can also be passed a list of stop-signals that abort the {\tt -ConstEval} algorithm if the value of a stop-signal is needed in order to -calculate the result signals. - -The {\tt fsm\_extract} pass uses the {\tt ConstEval} class in the following way -to create a transition table. For each state: - -\begin{enumerate} -\item Create a {\tt ConstEval} object for the module containing the FSM -\item Add all control inputs to the list of stop signals -\item Set the state signal to the current state -\item Try to evaluate the next state and control output \label{enum:fsm_extract_cealg_try} -\item If step~\ref{enum:fsm_extract_cealg_try} was not successful: -\begin{itemize} -\item Recursively goto step~\ref{enum:fsm_extract_cealg_try} with the offending stop-signal set to 0. -\item Recursively goto step~\ref{enum:fsm_extract_cealg_try} with the offending stop-signal set to 1. -\end{itemize} -\item If step~\ref{enum:fsm_extract_cealg_try} was successful: Emit transition -\end{enumerate} - -Finally a {\tt \$fsm} cell is created with the generated transition table and added to the -module. This new cell is connected to the control signals and the old drivers for the -control outputs are disconnected. - -\subsection{FSM Optimization} - -The {\tt fsm\_opt} pass performs basic optimizations on {\tt \$fsm} cells (not including state -recoding). The following optimizations are performed (in this order): - -\begin{itemize} -\item Unused control outputs are removed from the {\tt \$fsm} cell. The attribute \B{unused\_bits} -(that is usually set by the {\tt opt\_clean} pass) is used to determine which control -outputs are unused. -\item Control inputs that are connected to the same driver are merged. -\item When a control input is driven by a control output, the control input is removed and the transition -table altered to give the same performance without the external feedback path. -\item Entries in the transition table that yield the same output and only -differ in the value of a single control input bit are merged and the different bit is removed -from the sensitivity list (turned into a don't-care bit). -\item Constant inputs are removed and the transition table is altered to give an unchanged behaviour. -\item Unused inputs are removed. -\end{itemize} - -\subsection{FSM Recoding} - -The {\tt fsm\_recode} pass assigns new bit pattern to the states. Usually this -also implies a change in the width of the state signal. At the moment of this -writing only one-hot encoding with all-zero for the reset state is supported. - -The {\tt fsm\_recode} pass can also write a text file with the changes performed -by it that can be used when verifying designs synthesized by Yosys using Synopsys -Formality \citeweblink{Formality}. - -\section{Logic Optimization} - -Yosys can perform multi-level combinational logic optimization on gate-level netlists using the -external program ABC \citeweblink{ABC}. The {\tt abc} pass extracts the combinational gate-level -parts of the design, passes it through ABC, and re-integrates the results. The {\tt abc} pass -can also be used to perform other operations using ABC, such as technology mapping (see -Sec.~\ref{sec:techmap_extern} for details). - diff --git a/yosys/manual/CHAPTER_Overview.tex b/yosys/manual/CHAPTER_Overview.tex deleted file mode 100644 index 3009bf2c0..000000000 --- a/yosys/manual/CHAPTER_Overview.tex +++ /dev/null @@ -1,539 +0,0 @@ - -\chapter{Implementation Overview} -\label{chapter:overview} - -Yosys is an extensible open source hardware synthesis tool. It is aimed at -designers who are looking for an easily accessible, universal, and -vendor-independent synthesis tool, as well as scientists who do research in -electronic design automation (EDA) and are looking for an open synthesis -framework that can be used to test algorithms on complex real-world designs. - -Yosys can synthesize a large subset of Verilog 2005 and has been tested with a -wide range of real-world designs, including the OpenRISC 1200 CPU -\citeweblink{OR1200}, the openMSP430 CPU \citeweblink{openMSP430}, the -OpenCores I$^2$C master \citeweblink{i2cmaster} and the k68 CPU \citeweblink{k68}. - -As of this writing a Yosys VHDL frontend is in development. - -Yosys is written in C++ (using some features from the new C++11 standard). This -chapter describes some of the fundamental Yosys data structures. For the sake -of simplicity the C++ type names used in the Yosys implementation are used in -this chapter, even though the chapter only explains the conceptual idea behind -it and can be used as reference to implement a similar system in any language. - -\section{Simplified Data Flow} - -Figure~\ref{fig:Overview_flow} shows the simplified data flow within Yosys. -Rectangles in the figure represent program modules and ellipses internal -data structures that are used to exchange design data between the program -modules. - -Design data is read in using one of the frontend modules. The high-level HDL -frontends for Verilog and VHDL code generate an abstract syntax tree (AST) that -is then passed to the AST frontend. Note that both HDL frontends use the same -AST representation that is powerful enough to cover the Verilog HDL and VHDL -language. - -The AST Frontend then compiles the AST to Yosys's main internal data format, -the RTL Intermediate Language (RTLIL). A more detailed description of this format -is given in the next section. - -There is also a text representation of the RTLIL data structure that can be -parsed using the ILANG Frontend. - -The design data may then be transformed using a series of passes that all -operate on the RTLIL representation of the design. - -Finally the design in RTLIL representation is converted back to text by one -of the backends, namely the Verilog Backend for generating Verilog netlists -and the ILANG Backend for writing the RTLIL data in the same format that is -understood by the ILANG Frontend. - -With the exception of the AST Frontend, which is called by the high-level HDL -frontends and can't be called directly by the user, all program modules are -called by the user (usually using a synthesis script that contains text -commands for Yosys). - -By combining passes in different ways and/or adding additional passes to Yosys -it is possible to adapt Yosys to a wide range of applications. For this to be -possible it is key that (1) all passes operate on the same data structure -(RTLIL) and (2) that this data structure is powerful enough to represent the design -in different stages of the synthesis. - -\begin{figure}[t] - \hfil - \begin{tikzpicture} - \tikzstyle{process} = [draw, fill=green!10, rectangle, minimum height=3em, minimum width=10em, node distance=15em] - \tikzstyle{data} = [draw, fill=blue!10, ellipse, minimum height=3em, minimum width=7em, node distance=15em] - \node[process] (vlog) {Verilog Frontend}; - \node[process, dashed, fill=green!5] (vhdl) [right of=vlog] {VHDL Frontend}; - \node[process] (ilang) [right of=vhdl] {ILANG Frontend}; - \node[data] (ast) [below of=vlog, node distance=5em, xshift=7.5em] {AST}; - \node[process] (astfe) [below of=ast, node distance=5em] {AST Frontend}; - \node[data] (rtlil) [below of=astfe, node distance=5em, xshift=7.5em] {RTLIL}; - \node[process] (pass) [right of=rtlil, node distance=5em, xshift=7.5em] {Passes}; - \node[process] (vlbe) [below of=rtlil, node distance=7em, xshift=-13em] {Verilog Backend}; - \node[process] (ilangbe) [below of=rtlil, node distance=7em, xshift=0em] {ILANG Backend}; - \node[process, dashed, fill=green!5] (otherbe) [below of=rtlil, node distance=7em, xshift=+13em] {Other Backends}; - - \draw[-latex] (vlog) -- (ast); - \draw[-latex] (vhdl) -- (ast); - \draw[-latex] (ast) -- (astfe); - \draw[-latex] (astfe) -- (rtlil); - \draw[-latex] (ilang) -- (rtlil); - \draw[latex-latex] (rtlil) -- (pass); - \draw[-latex] (rtlil) -- (vlbe); - \draw[-latex] (rtlil) -- (ilangbe); - \draw[-latex] (rtlil) -- (otherbe); - \end{tikzpicture} - \caption{Yosys simplified data flow (ellipses: data structures, rectangles: program modules)} - \label{fig:Overview_flow} -\end{figure} - -\section{The RTL Intermediate Language} - -All frontends, passes and backends in Yosys operate on a design in RTLIL\footnote{The {\it Language} in {\it RTL Intermediate Language} -refers to the fact, that RTLIL also has a text representation, usually referred to as {\it Intermediate Language} (ILANG).} representation. -The only exception are the high-level frontends that use the AST representation as an intermediate step before generating RTLIL -data. - -In order to avoid reinventing names for the RTLIL classes, they are simply referred to by their full C++ name, i.e.~including -the {\tt RTLIL::} namespace prefix, in this document. - -Figure~\ref{fig:Overview_RTLIL} shows a simplified Entity-Relationship Diagram (ER Diagram) of RTLIL. In $1:N$ relationships the arrow -points from the $N$ side to the $1$. For example one RTLIL::Design contains $N$ (zero to many) instances of RTLIL::Module. -A two-pointed arrow indicates a $1:1$ relationship. - -The RTLIL::Design is the root object of the RTLIL data structure. There is always one ``current design'' in memory -which passes operate on, frontends add data to and backends convert to exportable formats. But in some cases passes -internally generate additional RTLIL::Design objects. For example when a pass is reading an auxiliary Verilog file such -as a cell library, it might create an additional RTLIL::Design object and call the Verilog frontend with this -other object to parse the cell library. - -\begin{figure}[t] - \hfil - \begin{tikzpicture} - \tikzstyle{entity} = [draw, fill=gray!10, rectangle, minimum height=3em, minimum width=7em, node distance=5em, font={\ttfamily}] - \node[entity] (design) {RTLIL::Design}; - \node[entity] (module) [right of=design, node distance=11em] {RTLIL::Module} edge [-latex] node[above] {\tiny 1 \hskip3em N} (design); - - \node[entity] (process) [fill=green!10, right of=module, node distance=10em] {RTLIL::Process} (process.west) edge [-latex] (module); - \node[entity] (memory) [fill=red!10, below of=process] {RTLIL::Memory} edge [-latex] (module); - \node[entity] (wire) [fill=blue!10, above of=process] {RTLIL::Wire} (wire.west) edge [-latex] (module); - \node[entity] (cell) [fill=blue!10, above of=wire] {RTLIL::Cell} (cell.west) edge [-latex] (module); - - \node[entity] (case) [fill=green!10, right of=process, node distance=10em] {RTLIL::CaseRule} edge [latex-latex] (process); - \node[entity] (sync) [fill=green!10, above of=case] {RTLIL::SyncRule} edge [-latex] (process); - \node[entity] (switch) [fill=green!10, below of=case] {RTLIL::SwitchRule} edge [-latex] (case); - \draw[latex-] (switch.east) -- ++(1em,0) |- (case.east); - \end{tikzpicture} - \caption{Simplified RTLIL Entity-Relationship Diagram} - \label{fig:Overview_RTLIL} -\end{figure} - -There is only one active RTLIL::Design object that is used by all frontends, -passes and backends called by the user, e.g.~using a synthesis script. The RTLIL::Design then contains -zero to many RTLIL::Module objects. This corresponds to modules in Verilog or entities in VHDL. Each -module in turn contains objects from three different categories: - -\begin{itemize} -\item RTLIL::Cell and RTLIL::Wire objects represent classical netlist data. -\item RTLIL::Process objects represent the decision trees (if-then-else statements, etc.) and synchronization -declarations (clock signals and sensitivity) from Verilog {\tt always} and VHDL {\tt process} blocks. -\item RTLIL::Memory objects represent addressable memories (arrays). -\end{itemize} - -\begin{sloppypar} -Usually the output of the synthesis procedure is a netlist, i.e. all -RTLIL::Process and RTLIL::Memory objects must be replaced by RTLIL::Cell and -RTLIL::Wire objects by synthesis passes. -\end{sloppypar} - -All features of the HDL that cannot be mapped directly to these RTLIL classes must be -transformed to an RTLIL-compatible representation by the HDL frontend. This includes -Verilog-features such as generate-blocks, loops and parameters. - -The following sections contain a more detailed description of the different -parts of RTLIL and rationale behind some of the design decisions. - -\subsection{RTLIL Identifiers} - -All identifiers in RTLIL (such as module names, port names, signal names, cell -types, etc.) follow the following naming convention: they must either start with -a backslash (\textbackslash) or a dollar sign (\$). - -Identifiers starting with a backslash are public visible identifiers. Usually -they originate from one of the HDL input files. For example the signal name ``{\tt \textbackslash sig42}'' -is most likely a signal that was declared using the name ``{\tt sig42}'' in an HDL input file. -On the other hand the signal name ``{\tt \$sig42}'' is an auto-generated signal name. The backends -convert all identifiers that start with a dollar sign to identifiers that do not collide with -identifiers that start with a backslash. - -This has three advantages: - -\begin{itemize} -\item First, it is impossible that an auto-generated identifier collides with -an identifier that was provided by the user. -\item Second, the information about which identifiers were originally -provided by the user is always available which can help guide some optimizations. For example the ``opt\_rmunused'' -tries to preserve signals with a user-provided name but doesn't hesitate to delete signals that have -auto-generated names when they just duplicate other signals. -\item Third, the delicate job of finding suitable auto-generated public visible -names is deferred to one central location. Internally auto-generated names that -may hold important information for Yosys developers can be used without -disturbing external tools. For example the Verilog backend assigns names in the form {\tt \_{\it integer}\_}. -\end{itemize} - -In order to avoid programming errors, the RTLIL data structures check if all -identifiers start with either a backslash or a dollar sign and generate a -runtime error if this rule is violated. - -All RTLIL identifiers are case sensitive. - -\subsection{RTLIL::Design and RTLIL::Module} - -The RTLIL::Design object is basically just a container for RTLIL::Module objects. In addition to -a list of RTLIL::Module objects the RTLIL::Design also keeps a list of {\it selected objects}, i.e. -the objects that passes should operate on. In most cases the whole design is selected and therefore -passes operate on the whole design. But this mechanism can be useful for more complex synthesis jobs -in which only parts of the design should be affected by certain passes. - -Besides the objects shown in the ER diagram in Fig.~\ref{fig:Overview_RTLIL} an RTLIL::Module object -contains the following additional properties: - -\begin{itemize} -\item The module name -\item A list of attributes -\item A list of connections between wires -\item An optional frontend callback used to derive parametrized variations of the module -\end{itemize} - -The attributes can be Verilog attributes imported by the Verilog frontend or attributes assigned -by passes. They can be used to store additional metadata about modules or just mark them to be -used by certain part of the synthesis script but not by others. - -Verilog and VHDL both support parametric modules (known as ``generic entities'' in VHDL). The RTLIL -format does not support parametric modules itself. Instead each module contains a callback function -into the AST frontend to generate a parametrized variation of the RTLIL::Module as needed. This -callback then returns the auto-generated name of the parametrized variation of the module. (A hash -over the parameters and the module name is used to prohibit the same parametrized variation from being -generated twice. For modules with only a few parameters, a name directly containing all parameters -is generated instead of a hash string.) - -\subsection{RTLIL::Cell and RTLIL::Wire} - -A module contains zero to many RTLIL::Cell and RTLIL::Wire objects. Objects of -these types are used to model netlists. Usually the goal of all synthesis efforts is to convert -all modules to a state where the functionality of the module is implemented only by cells -from a given cell library and wires to connect these cells with each other. Note that module -ports are just wires with a special property. - -An RTLIL::Wire object has the following properties: - -\begin{itemize} -\item The wire name -\item A list of attributes -\item A width (buses are just wires with a width > 1) -\item If the wire is a port: port number and direction (input/output/inout) -\end{itemize} - -As with modules, the attributes can be Verilog attributes imported by the -Verilog frontend or attributes assigned by passes. - -In Yosys, busses (signal vectors) are represented using a single wire object -with a width > 1. So Yosys does not convert signal vectors to individual signals. -This makes some aspects of RTLIL more complex but enables Yosys to be used for -coarse grain synthesis where the cells of the target architecture operate on -entire signal vectors instead of single bit wires. - -An RTLIL::Cell object has the following properties: - -\begin{itemize} -\item The cell name and type -\item A list of attributes -\item A list of parameters (for parametric cells) -\item Cell ports and the connections of ports to wires and constants -\end{itemize} - -The connections of ports to wires are coded by assigning an RTLIL::SigSpec -to each cell port. The RTLIL::SigSpec data type is described in the next section. - -\subsection{RTLIL::SigSpec} - -A ``signal'' is everything that can be applied to a cell port. I.e. - -\begin{itemize} -\item Any constant value of arbitrary bit-width \\ -\null\hskip1em For example: \lstinline[language=Verilog]{1337, 16'b0000010100111001, 1'b1, 1'bx} -\item All bits of a wire or a selection of bits from a wire \\ -\null\hskip1em For example: \lstinline[language=Verilog]{mywire, mywire[24], mywire[15:8]} -\item Concatenations of the above \\ -\null\hskip1em For example: \lstinline[language=Verilog]|{16'd1337, mywire[15:8]}| -\end{itemize} - -The RTLIL::SigSpec data type is used to represent signals. The RTLIL::Cell -object contains one RTLIL::SigSpec for each cell port. - -In addition, connections between wires are represented using a pair of -RTLIL::SigSpec objects. Such pairs are needed in different locations. Therefore -the type name RTLIL::SigSig was defined for such a pair. - -\subsection{RTLIL::Process} - -When a high-level HDL frontend processes behavioural code it splits it up into -data path logic (e.g.~the expression {\tt a + b} is replaced by the output of an -adder that takes {\tt a} and {\tt b} as inputs) and an RTLIL::Process that models -the control logic of the behavioural code. Let's consider a simple example: - -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -module ff_with_en_and_async_reset(clock, reset, enable, d, q); -input clock, reset, enable, d; -output reg q; -always @(posedge clock, posedge reset) - if (reset) - q <= 0; - else if (enable) - q <= d; -endmodule -\end{lstlisting} - -In this example there is no data path and therefore the RTLIL::Module generated by -the frontend only contains a few RTLIL::Wire objects and an RTLIL::Process. -The RTLIL::Process in ILANG syntax: - -\begin{lstlisting}[numbers=left,frame=single,language=rtlil] -process $proc$ff_with_en_and_async_reset.v:4$1 - assign $0\q[0:0] \q - switch \reset - case 1'1 - assign $0\q[0:0] 1'0 - case - switch \enable - case 1'1 - assign $0\q[0:0] \d - case - end - end - sync posedge \clock - update \q $0\q[0:0] - sync posedge \reset - update \q $0\q[0:0] -end -\end{lstlisting} - -This RTLIL::Process contains two RTLIL::SyncRule objects, two RTLIL::SwitchRule -objects and five RTLIL::CaseRule objects. The wire {\tt \$0\textbackslash{}q[0:0]} -is an automatically created wire that holds the next value of {\tt \textbackslash{}q}. The lines -$2 \dots 12$ describe how {\tt \$0\textbackslash{}q[0:0]} should be calculated. The -lines $13 \dots 16$ describe how the value of {\tt \$0\textbackslash{}q[0:0]} is used -to update {\tt \textbackslash{}q}. - -An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and -exactly one RTLIL::CaseRule object, which is called the {\it root case}. - -An RTLIL::SyncRule object contains an (optional) synchronization condition (signal and edge-type) and zero or -more assignments (RTLIL::SigSig). The {\tt always} synchronization condition is used to break combinatorial -loops when a latch should be inferred instead. - -An RTLIL::CaseRule is a container for zero or more assignments (RTLIL::SigSig) -and zero or more RTLIL::SwitchRule objects. An RTLIL::SwitchRule objects is a -container for zero or more RTLIL::CaseRule objects. - -In the above example the lines $2 \dots 12$ are the root case. Here {\tt \$0\textbackslash{}q[0:0]} is first -assigned the old value {\tt \textbackslash{}q} as default value (line 2). The root case -also contains an RTLIL::SwitchRule object (lines $3 \dots 12$). Such an object is very similar to the C {\tt switch} -statement as it uses a control signal ({\tt \textbackslash{}reset} in this case) to determine -which of its cases should be active. The RTLIL::SwitchRule object then contains one RTLIL::CaseRule -object per case. In this example there is a case\footnote{The -syntax {\tt 1'1} in the ILANG code specifies a constant with a length of one bit (the first ``1''), -and this bit is a one (the second ``1'').} for {\tt \textbackslash{}reset == 1} that causes -{\tt \$0\textbackslash{}q[0:0]} to be set (lines 4 and 5) and a default case that in turn contains a switch that -sets {\tt \$0\textbackslash{}q[0:0]} to the value of {\tt \textbackslash{}d} if {\tt -\textbackslash{}enable} is active (lines $6 \dots 11$). - -A case can specify zero or more compare values that will determine whether it matches. Each of the compare values -must be the exact same width as the control signal. When more than one compare value is specified, the case matches -if any of them matches the control signal; when zero compare values are specified, the case always matches (i.e. -it is the default case). - -A switch prioritizes cases from first to last: multiple cases can match, but only the first matched case becomes -active. This normally synthesizes to a priority encoder. The {\tt parallel\_case} attribute allows passes to assume -that no more than one case will match, and {\tt full\_case} attribute allows passes to assume that exactly one -case will match; if these invariants are ever dynamically violated, the behavior is undefined. These attributes -are useful when an invariant invisible to the synthesizer causes the control signal to never take certain -bit patterns. - -The lines $13 \dots 16$ then cause {\tt \textbackslash{}q} to be updated whenever there is -a positive clock edge on {\tt \textbackslash{}clock} or {\tt \textbackslash{}reset}. - -In order to generate such a representation, the language frontend must be able to handle blocking -and nonblocking assignments correctly. However, the language frontend does not need to identify -the correct type of storage element for the output signal or generate multiplexers for the -decision tree. This is done by passes that work on the RTLIL representation. Therefore it is -relatively easy to substitute these steps with other algorithms that target different target -architectures or perform optimizations or other transformations on the decision trees before -further processing them. - -One of the first actions performed on a design in RTLIL representation in most -synthesis scripts is identifying asynchronous resets. This is usually done using the {\tt proc\_arst} -pass. This pass transforms the above example to the following RTLIL::Process: - -\begin{lstlisting}[numbers=left,frame=single,language=rtlil] -process $proc$ff_with_en_and_async_reset.v:4$1 - assign $0\q[0:0] \q - switch \enable - case 1'1 - assign $0\q[0:0] \d - case - end - sync posedge \clock - update \q $0\q[0:0] - sync high \reset - update \q 1'0 -end -\end{lstlisting} - -This pass has transformed the outer RTLIL::SwitchRule into a modified RTLIL::SyncRule object -for the {\tt \textbackslash{}reset} signal. Further processing converts the RTLIL::Process -into e.g.~a d-type flip-flop with asynchronous reset and a multiplexer for the enable signal: - -\begin{lstlisting}[numbers=left,frame=single,language=rtlil] -cell $adff $procdff$6 - parameter \ARST_POLARITY 1'1 - parameter \ARST_VALUE 1'0 - parameter \CLK_POLARITY 1'1 - parameter \WIDTH 1 - connect \ARST \reset - connect \CLK \clock - connect \D $0\q[0:0] - connect \Q \q -end -cell $mux $procmux$3 - parameter \WIDTH 1 - connect \A \q - connect \B \d - connect \S \enable - connect \Y $0\q[0:0] -end -\end{lstlisting} - -Different combinations of passes may yield different results. Note that {\tt \$adff} and {\tt -\$mux} are internal cell types that still need to be mapped to cell types from the -target cell library. - -Some passes refuse to operate on modules that still contain RTLIL::Process objects as the -presence of these objects in a module increases the complexity. Therefore the passes to translate -processes to a netlist of cells are usually called early in a synthesis script. The {\tt proc} -pass calls a series of other passes that together perform this conversion in a way that is suitable -for most synthesis tasks. - -\subsection{RTLIL::Memory} - -For every array (memory) in the HDL code an RTLIL::Memory object is created. A -memory object has the following properties: - -\begin{itemize} -\item The memory name -\item A list of attributes -\item The width of an addressable word -\item The size of the memory in number of words -\end{itemize} - -All read accesses to the memory are transformed to {\tt \$memrd} cells and all write accesses to -{\tt \$memwr} cells by the language frontend. These cells consist of independent read- and write-ports -to the memory. Memory initialization is transformed to {\tt \$meminit} cells by the language frontend. -The \B{MEMID} parameter on these cells is used to link them together and to the RTLIL::Memory object they belong to. - -The rationale behind using separate cells for the individual ports versus -creating a large multiport memory cell right in the language frontend is that -the separate {\tt \$memrd} and {\tt \$memwr} cells can be consolidated using resource sharing. -As resource sharing is a non-trivial optimization problem where different synthesis tasks -can have different requirements it lends itself to do the optimisation in separate passes and merge -the RTLIL::Memory objects and {\tt \$memrd} and {\tt \$memwr} cells to multiport memory blocks after resource sharing is completed. - -The {\tt memory} pass performs this conversion and can (depending on the options passed -to it) transform the memories directly to d-type flip-flops and address logic or yield -multiport memory blocks (represented using {\tt \$mem} cells). - -See Sec.~\ref{sec:memcells} for details about the memory cell types. - -\section{Command Interface and Synthesis Scripts} - -Yosys reads and processes commands from synthesis scripts, command line arguments and -an interactive command prompt. Yosys commands consist of a command name and an optional -whitespace separated list of arguments. Commands are terminated using the newline character -or a semicolon ({\tt ;}). Empty lines and lines starting with the hash sign ({\tt \#}) are ignored. -See Sec.~\ref{sec:typusecase} for an example synthesis script. - -The command {\tt help} can be used to access the command reference manual. - -Most commands can operate not only on the entire design but also specifically on {\it selected} -parts of the design. For example the command {\tt dump} will print all selected objects -in the current design while {\tt dump foobar} will only print the module {\tt foobar} -and {\tt dump *} will print the entire design regardless of the current selection. - -The selection mechanism is very powerful. For example the command {\tt dump */t:\$add -\%x:+[A] */w:* \%i} will print all wires that are connected to the \B{A} port of -a {\tt \$add} cell. Detailed documentation of the select framework can be -found in the command reference for the {\tt select} command. - -\section{Source Tree and Build System} - -The Yosys source tree is organized into the following top-level directories: - -\begin{itemize} - -\item {\tt backends/} \\ -This directory contains a subdirectory for each of the backend modules. - -\item {\tt frontends/} \\ -This directory contains a subdirectory for each of the frontend modules. - -\item {\tt kernel/} \\ -This directory contains all the core functionality of Yosys. This includes the -functions and definitions for working with the RTLIL data structures ({\tt -rtlil.h} and {\tt rtlil.cc}), the main() function ({\tt driver.cc}), the -internal framework for generating log messages ({\tt log.h} and {\tt log.cc}), -the internal framework for registering and calling passes ({\tt register.h} and -{\tt register.cc}), some core commands that are not really passes ({\tt -select.cc}, {\tt show.cc}, \dots) and a couple of other small utility libraries. - -\item {\tt passes/} \\ -This directory contains a subdirectory for each pass or group of passes. For example as -of this writing the directory {\tt passes/opt/} contains the code for seven -passes: {\tt opt}, {\tt opt\_expr}, {\tt opt\_muxtree}, {\tt opt\_reduce}, -{\tt opt\_rmdff}, {\tt opt\_rmunused} and {\tt opt\_merge}. - -\item {\tt techlibs/} \\ -This directory contains simulation models and standard implementations for the -cells from the internal cell library. - -\item {\tt tests/} \\ -This directory contains a couple of test cases. Most of the smaller tests are executed -automatically when {\tt make test} is called. The larger tests must be executed -manually. Most of the larger tests require downloading external HDL source code -and/or external tools. The tests range from comparing simulation results of the synthesized -design to the original sources to logic equivalence checking of entire CPU cores. - -\end{itemize} - -\begin{sloppypar} -The top-level Makefile includes {\tt frontends/*/Makefile.inc}, {\tt passes/*/Makefile.inc} -and {\tt backends/*/Makefile.inc}. So when extending Yosys it is enough to create -a new directory in {\tt frontends/}, {\tt passes/} or {\tt backends/} with your sources -and a {\tt Makefile.inc}. The Yosys kernel automatically detects all commands linked with -Yosys. So it is not needed to add additional commands to a central list of commands. -\end{sloppypar} - -Good starting points for reading example source code to learn how to write passes -are {\tt passes/opt/opt\_rmdff.cc} and {\tt passes/opt/opt\_merge.cc}. - -See the top-level README file for a quick {\it Getting Started} guide and build -instructions. The Yosys build is based solely on Makefiles. - -Users of the Qt Creator IDE can generate a QT Creator project file using {\tt -make qtcreator}. Users of the Eclipse IDE can use the ``Makefile Project with -Existing Code'' project type in the Eclipse ``New Project'' dialog (only -available after the CDT plugin has been installed) to create an Eclipse project -in order to programming extensions to Yosys or just browse the Yosys code base. - diff --git a/yosys/manual/CHAPTER_Prog.tex b/yosys/manual/CHAPTER_Prog.tex deleted file mode 100644 index 3cbc95a19..000000000 --- a/yosys/manual/CHAPTER_Prog.tex +++ /dev/null @@ -1,26 +0,0 @@ - -\chapter{Programming Yosys Extensions} -\label{chapter:prog} - -This chapter contains some bits and pieces of information about programming -yosys extensions. Also consult the section on programming in the ``Yosys -Presentation'' (can be downloaded from the Yosys website as PDF) and don't -be afraid to ask questions on the Yosys Subreddit. - -\section{The ``CodingReadme'' File} - -The following is an excerpt of the {\tt CodingReadme} file from the Yosys source tree. - -\lstinputlisting[title=CodingReadme,rangeprefix=--,rangesuffix=--,includerangemarker=false,linerange=snip-snap,numbers=left,frame=single]{../CodingReadme} - -\section{The ``stubsnets'' Example Module} - -The following is the complete code of the ``stubsnets'' example module. It is included in the Yosys source distribution as {\tt manual/CHAPTER\_Prog/stubnets.cc}. - - -\lstinputlisting[title=stubnets.cc,numbers=left,frame=single,language=C++]{CHAPTER_Prog/stubnets.cc} - -\lstinputlisting[title=Makefile,numbers=left,frame=single,language=make]{CHAPTER_Prog/Makefile} - -\lstinputlisting[title=test.v,numbers=left,frame=single,language=Verilog]{CHAPTER_Prog/test.v} - diff --git a/yosys/manual/CHAPTER_Prog/.gitignore b/yosys/manual/CHAPTER_Prog/.gitignore deleted file mode 100644 index fa83c3212..000000000 --- a/yosys/manual/CHAPTER_Prog/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -stubnets.so -stubnets.d -*.log diff --git a/yosys/manual/CHAPTER_Prog/Makefile b/yosys/manual/CHAPTER_Prog/Makefile deleted file mode 100644 index 8e326bdc2..000000000 --- a/yosys/manual/CHAPTER_Prog/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -test: stubnets.so - yosys -ql test1.log -m ./stubnets.so test.v -p "stubnets" - yosys -ql test2.log -m ./stubnets.so test.v -p "opt; stubnets" - yosys -ql test3.log -m ./stubnets.so test.v -p "techmap; opt; stubnets -report_bits" - tail test1.log test2.log test3.log - -stubnets.so: stubnets.cc - yosys-config --exec --cxx --cxxflags --ldflags -o $@ -shared $^ --ldlibs - -clean: - rm -f test1.log test2.log test3.log - rm -f stubnets.so stubnets.d diff --git a/yosys/manual/CHAPTER_Prog/stubnets.cc b/yosys/manual/CHAPTER_Prog/stubnets.cc deleted file mode 100644 index 8123e63db..000000000 --- a/yosys/manual/CHAPTER_Prog/stubnets.cc +++ /dev/null @@ -1,130 +0,0 @@ -// This is free and unencumbered software released into the public domain. -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -#include -#include -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -// this function is called for each module in the design -static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool report_bits) -{ - // use a SigMap to convert nets to a unique representation - SigMap sigmap(module); - - // count how many times a single-bit signal is used - std::map bit_usage_count; - - // count output lines for this module (needed only for summary output at the end) - int line_count = 0; - - log("Looking for stub wires in module %s:\n", RTLIL::id2cstr(module->name)); - - // For all ports on all cells - for (auto &cell_iter : module->cells_) - for (auto &conn : cell_iter.second->connections()) - { - // Get the signals on the port - // (use sigmap to get a uniqe signal name) - RTLIL::SigSpec sig = sigmap(conn.second); - - // add each bit to bit_usage_count, unless it is a constant - for (auto &bit : sig) - if (bit.wire != NULL) - bit_usage_count[bit]++; - } - - // for each wire in the module - for (auto &wire_iter : module->wires_) - { - RTLIL::Wire *wire = wire_iter.second; - - // .. but only selected wires - if (!design->selected(module, wire)) - continue; - - // add +1 usage if this wire actually is a port - int usage_offset = wire->port_id > 0 ? 1 : 0; - - // we will record which bits of the (possibly multi-bit) wire are stub signals - std::set stub_bits; - - // get a signal description for this wire and split it into separate bits - RTLIL::SigSpec sig = sigmap(wire); - - // for each bit (unless it is a constant): - // check if it is used at least two times and add to stub_bits otherwise - for (int i = 0; i < GetSize(sig); i++) - if (sig[i].wire != NULL && (bit_usage_count[sig[i]] + usage_offset) < 2) - stub_bits.insert(i); - - // continue if no stub bits found - if (stub_bits.size() == 0) - continue; - - // report stub bits and/or stub wires, don't report single bits - // if called with report_bits set to false. - if (GetSize(stub_bits) == GetSize(sig)) { - log(" found stub wire: %s\n", RTLIL::id2cstr(wire->name)); - } else { - if (!report_bits) - continue; - log(" found wire with stub bits: %s [", RTLIL::id2cstr(wire->name)); - for (int bit : stub_bits) - log("%s%d", bit == *stub_bits.begin() ? "" : ", ", bit); - log("]\n"); - } - - // we have outputted a line, increment summary counter - line_count++; - } - - // report summary - if (report_bits) - log(" found %d stub wires or wires with stub bits.\n", line_count); - else - log(" found %d stub wires.\n", line_count); -} - -// each pass contains a singleton object that is derived from Pass -struct StubnetsPass : public Pass { - StubnetsPass() : Pass("stubnets") { } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - // variables to mirror information from passed options - bool report_bits = 0; - - log_header(design, "Executing STUBNETS pass (find stub nets).\n"); - - // parse options - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-report_bits") { - report_bits = true; - continue; - } - break; - } - - // handle extra options (e.g. selection) - extra_args(args, argidx, design); - - // call find_stub_nets() for each module that is either - // selected as a whole or contains selected objects. - for (auto &it : design->modules_) - if (design->selected_module(it.first)) - find_stub_nets(design, it.second, report_bits); - } -} StubnetsPass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/manual/CHAPTER_Prog/test.v b/yosys/manual/CHAPTER_Prog/test.v deleted file mode 100644 index 201f75006..000000000 --- a/yosys/manual/CHAPTER_Prog/test.v +++ /dev/null @@ -1,8 +0,0 @@ -module uut(in1, in2, in3, out1, out2); - -input [8:0] in1, in2, in3; -output [8:0] out1, out2; - -assign out1 = in1 + in2 + (in3 >> 4); - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt.tex b/yosys/manual/CHAPTER_StateOfTheArt.tex deleted file mode 100644 index 2d0c77a01..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt.tex +++ /dev/null @@ -1,289 +0,0 @@ - -\chapter{Evaluation of other OSS Verilog Synthesis Tools} -\label{chapter:sota} - -In this appendix\footnote{This appendix is an updated version of an -unpublished student research paper. \cite{VerilogFossEval}} -the existing FOSS Verilog synthesis tools\footnote{To the -author's best knowledge, all relevant tools that existed at the time of this -writing are included. But as there is no formal channel through which such -tools are published it is hard to give any guarantees in that matter.} are -evaluated. Extremely limited or application specific tools (e.g.~pure Verilog -Netlist parsers) as well as Verilog simulators are not included. These existing -solutions are tested using a set of representative Verilog code snippets. It is -shown that no existing FOSS tool implements even close to a sufficient subset -of Verilog to be usable as synthesis tool for a wide range existing Verilog code. - -The packages evaluated are: - -\begin{itemize} -\item Icarus Verilog \citeweblink{Icarus}\footnote{Icarus Verilog is mainly a simulation -tool but also supported synthesis up to version 0.8. Therefore version 0.8.7 is used -for this evaluation.)} -\item Verilog-to-Routing (VTR) / Odin-II \cite{vtr2012}\cite{Odin}\citeweblink{VTR} -\item HDL Analyzer and Netlist Architect (HANA) \citeweblink{HANA} -\item Verilog front-end to VIS (vl2mv) \cite{Cheng93vl2mv:a}\citeweblink{VIS} -\end{itemize} - -In each of the following sections Verilog modules that test a certain Verilog -language feature are presented and the support for these features is tested in all -the tools mentioned above. It is evaluated whether the tools under test -successfully generate netlists for the Verilog input and whether these netlists -match the simulation behavior of the designs using testbenches. - -All test cases are verified to be synthesizeable using Xilinx XST from the Xilinx -WebPACK \citeweblink{XilinxWebPACK} suite. - -Trivial features such as support for simple structural Verilog are not explicitly tested. - -Vl2mv and Odin-II generate output in the BLIF (Berkeley Logic Interchange -Format) and BLIF-MV (an extended version of BLIF) formats respectively. -ABC \citeweblink{ABC} is used to convert this output to Verilog for verification -using testbenches. - -Icarus Verilog generates EDIF (Electronic Design Interchange Format) output -utilizing LPM (Library of Parameterized Modules) cells. The EDIF files are -converted to Verilog using edif2ngd and netgen from Xilinx WebPACK. A -hand-written implementation of the LPM cells utilized by the generated netlists -is used for verification. - -Following these functional tests, a quick analysis of the extensibility of the tools -under test is provided in a separate section. - -The last section of this chapter finally concludes these series of evaluations -with a summary of the results. - -\begin{figure}[t!] - \begin{minipage}{7.7cm} - \lstinputlisting[numbers=left,frame=single,language=Verilog]{CHAPTER_StateOfTheArt/always01_pub.v} - \end{minipage} - \hfill - \begin{minipage}{7.7cm} - \lstinputlisting[frame=single,language=Verilog]{CHAPTER_StateOfTheArt/always02_pub.v} - \end{minipage} - \caption{1st and 2nd Verilog always examples} - \label{fig:StateOfTheArt_always12} -\end{figure} - -\begin{figure}[!] - \lstinputlisting[numbers=left,frame=single,language=Verilog]{CHAPTER_StateOfTheArt/always03.v} - \caption{3rd Verilog always example} - \label{fig:StateOfTheArt_always3} -\end{figure} - -\section{Always blocks and blocking vs.~nonblocking assignments} -\label{sec:blocking_nonblocking} - -The ``always''-block is one of the most fundamental non-trivial Verilog -language features. It can be used to model a combinatorial path (with optional -registers on the outputs) in a way that mimics a regular programming language. - -Within an always block, if- and case-statements can be used to model multiplexers. -Blocking assignments ($=$) and nonblocking assignments ($<=$) are used to populate the -leaf-nodes of these multiplexer trees. Unassigned leaf-nodes default to feedback -paths that cause the output register to hold the previous value. More advanced -synthesis tools often convert these feedback paths to register enable signals or -even generate circuits with clock gating. - -Registers assigned with nonblocking assignments ($<=$) behave differently from -variables in regular programming languages: In a simulation they are not -updated immediately after being assigned. Instead the right-hand sides are -evaluated and the results stored in temporary memory locations. After all -pending updates have been prepared in this way they are executed, thus yielding -semi-parallel execution of all nonblocking assignments. - -For synthesis this means that every occurrence of that register in an expression -addresses the output port of the corresponding register regardless of the question whether the register -has been assigned a new value in an earlier command in the same always block. -Therefore with nonblocking assignments the order of the assignments has no effect -on the resulting circuit as long as the left-hand sides of the assignments are -unique. - -The three example codes in Fig.~\ref{fig:StateOfTheArt_always12} and -Fig.~\ref{fig:StateOfTheArt_always3} use all these features and can thus be used -to test the synthesis tools capabilities to synthesize always blocks correctly. - -The first example is only using the most fundamental Verilog features. All -tools under test were able to successfully synthesize this design. - -\begin{figure}[b!] - \lstinputlisting[numbers=left,frame=single,language=Verilog]{CHAPTER_StateOfTheArt/arrays01.v} - \caption{Verilog array example} - \label{fig:StateOfTheArt_arrays} -\end{figure} - -The 2nd example is functionally identical to the 1st one but is using an -if-statement inside the always block. Odin-II fails to synthesize it and -instead produces the following error message: - -\begin{verbatim} -ERROR: (File: always02.v) (Line number: 13) -You've defined the driver "count~0" twice -\end{verbatim} - -Vl2mv does not produce an error message but outputs an invalid synthesis result -that is not using the reset input at all. - -Icarus Verilog also doesn't produce an error message but generates an invalid output -for this 2nd example. The code generated by Icarus Verilog only implements the reset -path for the count register, effectively setting the output to constant 0. - -So of all tools under test only HANA was able to create correct synthesis results -for the 2nd example. - -The 3rd example is using blocking and nonblocking assignments and many if statements. -Odin also fails to synthesize this example: - -\begin{verbatim} -ERROR: (File: always03.v) (Line number: 8) -ODIN doesn't handle blocking statements in Sequential blocks -\end{verbatim} - -HANA, Icarus Verilog and vl2mv create invalid synthesis results for the 3rd example. - -So unfortunately none of the tools under test provide a complete and correct -implementation of blocking and nonblocking assignments. - -\section{Arrays for memory modelling} - -Verilog arrays are part of the synthesizeable subset of Verilog and are -commonly used to model addressable memory. The Verilog code in -Fig.~\ref{fig:StateOfTheArt_arrays} demonstrates this by implementing a single -port memory. - -For this design HANA, vl2m and ODIN-II generate error messages indicating that -arrays are not supported. - -\begin{figure}[t!] - \lstinputlisting[numbers=left,frame=single,language=Verilog]{CHAPTER_StateOfTheArt/forgen01.v} - \caption{Verilog for loop example} - \label{fig:StateOfTheArt_for} -\end{figure} - -Icarus Verilog produces an invalid output that is using the address only for -reads. Instead of using the address input for writes, the generated design -simply loads the data to all memory locations whenever the write-enable input -is active, effectively turning the design into a single 4-bit D-Flip-Flop with -enable input. - -As all tools under test already fail this simple test, there is nothing to gain -by continuing tests on this aspect of Verilog synthesis such as synthesis of dual port -memories, correct handling of write collisions, and so forth. - -\begin{figure}[t!] - \lstinputlisting[numbers=left,frame=single,language=Verilog]{CHAPTER_StateOfTheArt/forgen02.v} - \caption{Verilog generate example} - \label{fig:StateOfTheArt_gen} -\end{figure} - -\section{For-loops and generate blocks} - -For-loops and generate blocks are more advanced Verilog features. These features -allow the circuit designer to add program code to her design that is evaluated -during synthesis to generate (parts of) the circuits description; something that -could only be done using a code generator otherwise. - -For-loops are only allowed in synthesizeable Verilog if they can be completely -unrolled. Then they can be a powerful tool to generate array logic or static -lookup tables. The code in Fig.~\ref{fig:StateOfTheArt_for} generates a circuit that -tests a 5 bit value for being a prime number using a static lookup table. - -Generate blocks can be used to model array logic in complex parametric designs. The -code in Fig.~\ref{fig:StateOfTheArt_gen} implements a ripple-carry adder with -parametric width from simple assign-statements and logic operations using a Verilog -generate block. - -All tools under test failed to synthesize both test cases. HANA creates invalid -output in both cases. Icarus Verilog creates invalid output for the first -test and fails with an error for the second case. The other two tools fail with -error messages for both tests. - -\section{Extensibility} - -This section briefly discusses the extensibility of the tools under test and -their internal data- and control-flow. As all tools under test already failed -to synthesize simple Verilog always-blocks correctly, not much resources have -been spent on evaluating the extensibility of these tools and therefore only a -very brief discussion of the topic is provided here. - -HANA synthesizes for a built-in library of standard cells using two passes over -an AST representation of the Verilog input. This approach executes fast but -limits the extensibility as everything happens in only two comparable complex -AST walks and there is no universal intermediate representation that is flexible -enough to be used in arbitrary optimizations. - -Odin-II and vl2m are both front ends to existing synthesis flows. As such they -only try to quickly convert the Verilog input into the internal representation -of their respective flows (BLIF). So extensibility is less of an issue here as -potential extensions would likely be implemented in other components of the -flow. - -Icarus Verilog is clearly designed to be a simulation tool rather than a -synthesis tool. The synthesis part of Icarus Verilog is an ad-hoc add-on to -Icarus Verilog that aims at converting an internal representation that is meant -for generation of a virtual machine based simulation code to netlists. - -\section{Summary and Outlook} - -Table~\ref{tab:StateOfTheArt_sum} summarizes the tests performed. Clearly none -of the tools under test make a serious attempt at providing a feature-complete -implementation of Verilog. It can be argued that Odin-II performed best in the -test as it never generated incorrect code but instead produced error messages -indicating that unsupported Verilog features where used in the Verilog input. - -In conclusion, to the best knowledge of the author, there is no FOSS Verilog -synthesis tool other than Yosys that is anywhere near feature completeness and -therefore there is no other candidate for a generic Verilog front end and/or -synthesis framework to be used as a basis for custom synthesis tools. - -Yosys could also replace vl2m and/or Odin-II in their respective flows or -function as a pre-compiler that can translate full-featured Verilog code to the -simple subset of Verilog that is understood by vl2m and Odin-II. - -Yosys is designed for extensibility. It can be used as-is to synthesize Verilog -code to netlists, but its main purpose is to be used as basis for custom tools. -Yosys is structured in a language dependent Verilog front end and language -independent synthesis code (which is in itself structured in independent -passes). This architecture will simplify implementing additional HDL front -ends and/or additional synthesis passes. - -Chapter~\ref{chapter:eval} contains a more detailed evaluation of Yosys using real-world -designs that are far out of reach for any of the other tools discussed in this appendix. - -\vskip2cm -\begin{table}[h] - % yosys hana vis icarus odin - % always01 ok ok ok ok ok - % always02 ok ok failed failed error - % always03 ok failed failed missing error - % arrays01 ok error error failed error - % forgen01 ok failed error failed error - % forgen02 ok failed error error error - \def\ok{\ding{52}} - \def\error{\ding{56}} - \def\failed{$\skull$} - \def\missing{$\skull$} - \rowcolors{2}{gray!25}{white} - \centerline{ - \begin{tabular}{|l|cccc|c|} - \hline - & \bf HANA & \bf VIS / vl2m & \bf Icarus Verilog & \bf Odin-II & \bf Yosys \\ - \hline - \tt always01 & \ok & \ok & \ok & \ok & \ok \\ - \tt always02 & \ok & \failed & \failed & \error & \ok \\ - \tt always03 & \failed & \failed & \missing & \error & \ok \\ - \tt arrays01 & \error & \error & \failed & \error & \ok \\ - \tt forgen01 & \failed & \error & \failed & \error & \ok \\ - \tt forgen02 & \failed & \error & \error & \error & \ok \\ - \hline - \end{tabular} - } - \centerline{ - \ding{52} \dots passed \hskip2em - \ding{56} \dots produced error \hskip2em - $\skull$ \dots incorrect output - } - \caption{Summary of all test results} - \label{tab:StateOfTheArt_sum} -\end{table} - diff --git a/yosys/manual/CHAPTER_StateOfTheArt/always01.v b/yosys/manual/CHAPTER_StateOfTheArt/always01.v deleted file mode 100644 index 4719ed47e..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/always01.v +++ /dev/null @@ -1,12 +0,0 @@ -module uut_always01(clock, reset, c3, c2, c1, c0); - -input clock, reset; -output c3, c2, c1, c0; -reg [3:0] count; - -assign {c3, c2, c1, c0} = count; - -always @(posedge clock) - count <= reset ? 0 : count + 1; - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt/always01_pub.v b/yosys/manual/CHAPTER_StateOfTheArt/always01_pub.v deleted file mode 100644 index 6a6a4b231..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/always01_pub.v +++ /dev/null @@ -1,14 +0,0 @@ -module uut_always01(clock, - reset, count); - -input clock, reset; -output [3:0] count; -reg [3:0] count; - -always @(posedge clock) - count <= reset ? - 0 : count + 1; - - - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt/always02.v b/yosys/manual/CHAPTER_StateOfTheArt/always02.v deleted file mode 100644 index 63f1ce317..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/always02.v +++ /dev/null @@ -1,15 +0,0 @@ -module uut_always02(clock, reset, c3, c2, c1, c0); - -input clock, reset; -output c3, c2, c1, c0; -reg [3:0] count; - -assign {c3, c2, c1, c0} = count; - -always @(posedge clock) begin - count <= count + 1; - if (reset) - count <= 0; -end - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt/always02_pub.v b/yosys/manual/CHAPTER_StateOfTheArt/always02_pub.v deleted file mode 100644 index 91f1ca16d..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/always02_pub.v +++ /dev/null @@ -1,14 +0,0 @@ -module uut_always02(clock, - reset, count); - -input clock, reset; -output [3:0] count; -reg [3:0] count; - -always @(posedge clock) begin - count <= count + 1; - if (reset) - count <= 0; -end - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt/always03.v b/yosys/manual/CHAPTER_StateOfTheArt/always03.v deleted file mode 100644 index 53386acd6..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/always03.v +++ /dev/null @@ -1,23 +0,0 @@ -module uut_always03(clock, in1, in2, in3, in4, in5, in6, in7, - out1, out2, out3); - -input clock, in1, in2, in3, in4, in5, in6, in7; -output out1, out2, out3; -reg out1, out2, out3; - -always @(posedge clock) begin - out1 = in1; - if (in2) - out1 = !out1; - out2 <= out1; - if (in3) - out2 <= out2; - if (in4) - if (in5) - out3 <= in6; - else - out3 <= in7; - out1 = out1 ^ out2; -end - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt/arrays01.v b/yosys/manual/CHAPTER_StateOfTheArt/arrays01.v deleted file mode 100644 index bd0eda294..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/arrays01.v +++ /dev/null @@ -1,16 +0,0 @@ -module uut_arrays01(clock, we, addr, wr_data, rd_data); - -input clock, we; -input [3:0] addr, wr_data; -output [3:0] rd_data; -reg [3:0] rd_data; - -reg [3:0] memory [15:0]; - -always @(posedge clock) begin - if (we) - memory[addr] <= wr_data; - rd_data <= memory[addr]; -end - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt/cmp_tbdata.c b/yosys/manual/CHAPTER_StateOfTheArt/cmp_tbdata.c deleted file mode 100644 index b188144dd..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/cmp_tbdata.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include -#include - -int line = 0; -char buffer1[1024]; -char buffer2[1024]; - -void check(bool ok) -{ - if (ok) - return; - // fprintf(stderr, "Error in testbench output compare (line=%d):\n-%s\n+%s\n", line, buffer1, buffer2); - exit(1); -} - -int main(int argc, char **argv) -{ - FILE *f1, *f2; - bool eof1, eof2; - int i; - - check(argc == 3); - - f1 = fopen(argv[1], "r"); - f2 = fopen(argv[2], "r"); - - check(f1 && f2); - - while (!feof(f1) && !feof(f2)) - { - line++; - buffer1[0] = 0; - buffer2[0] = 0; - - eof1 = fgets(buffer1, 1024, f1) == NULL; - eof2 = fgets(buffer2, 1024, f2) == NULL; - - if (*buffer1 && buffer1[strlen(buffer1)-1] == '\n') - buffer1[strlen(buffer1)-1] = 0; - - if (*buffer2 && buffer2[strlen(buffer2)-1] == '\n') - buffer2[strlen(buffer2)-1] = 0; - - check(eof1 == eof2); - - for (i = 0; buffer1[i] || buffer2[i]; i++) - { - check(buffer1[i] != 0 && buffer2[i] != 0); - - // first argument is the reference. An 'z' or 'x' - // here means we don't care about the result. - if (buffer1[i] == 'z' || buffer1[i] == 'x') - continue; - - check(buffer1[i] == buffer2[i]); - } - } - - check(feof(f1) && feof(f2)); - - fclose(f1); - fclose(f2); - return 0; -} - diff --git a/yosys/manual/CHAPTER_StateOfTheArt/forgen01.v b/yosys/manual/CHAPTER_StateOfTheArt/forgen01.v deleted file mode 100644 index 70ee7e667..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/forgen01.v +++ /dev/null @@ -1,20 +0,0 @@ -module uut_forgen01(a, y); - -input [4:0] a; -output y; - -integer i, j; -reg [31:0] lut; - -initial begin - for (i = 0; i < 32; i = i+1) begin - lut[i] = i > 1; - for (j = 2; j*j <= i; j = j+1) - if (i % j == 0) - lut[i] = 0; - end -end - -assign y = lut[a]; - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt/forgen02.v b/yosys/manual/CHAPTER_StateOfTheArt/forgen02.v deleted file mode 100644 index 14af070c3..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/forgen02.v +++ /dev/null @@ -1,30 +0,0 @@ -module uut_forgen02(a, b, cin, y, cout); - -parameter WIDTH = 8; - -input [WIDTH-1:0] a, b; -input cin; - -output [WIDTH-1:0] y; -output cout; - -genvar i; -wire [WIDTH-1:0] carry; - -generate - for (i = 0; i < WIDTH; i=i+1) begin:adder - wire [2:0] D; - assign D[1:0] = { a[i], b[i] }; - if (i == 0) begin:chain - assign D[2] = cin; - end else begin:chain - assign D[2] = carry[i-1]; - end - assign y[i] = ^D; - assign carry[i] = &D[1:0] | (^D[1:0] & D[2]); - end -endgenerate - -assign cout = carry[WIDTH-1]; - -endmodule diff --git a/yosys/manual/CHAPTER_StateOfTheArt/iverilog-0.8.7-buildfixes.patch b/yosys/manual/CHAPTER_StateOfTheArt/iverilog-0.8.7-buildfixes.patch deleted file mode 100644 index 63a03e595..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/iverilog-0.8.7-buildfixes.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- ./elab_net.cc.orig 2012-10-27 22:11:05.345688820 +0200 -+++ ./elab_net.cc 2012-10-27 22:12:23.398075860 +0200 -@@ -29,6 +29,7 @@ - - # include - # include -+# include - - /* - * This is a state flag that determines whether an elaborate_net must ---- ./syn-rules.y.orig 2012-10-27 22:25:38.890020489 +0200 -+++ ./syn-rules.y 2012-10-27 22:25:49.146071350 +0200 -@@ -25,6 +25,7 @@ - # include "config.h" - - # include -+# include - - /* - * This file implements synthesis based on matching threads and diff --git a/yosys/manual/CHAPTER_StateOfTheArt/mvsis-1.3.6-buildfixes.patch b/yosys/manual/CHAPTER_StateOfTheArt/mvsis-1.3.6-buildfixes.patch deleted file mode 100644 index 4b44320f8..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/mvsis-1.3.6-buildfixes.patch +++ /dev/null @@ -1,36 +0,0 @@ ---- ./helpers/config.sub.orig 2012-10-27 22:09:04.429089223 +0200 -+++ ./helpers/config.sub 2012-10-27 22:09:11.501124295 +0200 -@@ -158,6 +158,7 @@ - | sparc | sparclet | sparclite | sparc64) - basic_machine=$basic_machine-unknown - ;; -+ x86_64-pc) ;; - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. ---- ./src/base/ntki/ntkiFrames.c.orig 2012-10-27 22:09:26.961200963 +0200 -+++ ./src/base/ntki/ntkiFrames.c 2012-10-27 22:09:32.901230409 +0200 -@@ -23,7 +23,7 @@ - //////////////////////////////////////////////////////////////////////// - - static void Ntk_NetworkAddFrame( Ntk_Network_t * pNetNew, Ntk_Network_t * pNet, int iFrame ); --static void Ntk_NetworkReorderCiCo( Ntk_Network_t * pNet ); -+// static void Ntk_NetworkReorderCiCo( Ntk_Network_t * pNet ); - - extern int Ntk_NetworkVerifyVariables( Ntk_Network_t * pNet1, Ntk_Network_t * pNet2, int fVerbose ); - ---- ./src/graph/wn/wnStrashBin.c.orig 2012-10-27 22:27:29.966571294 +0200 -+++ ./src/graph/wn/wnStrashBin.c 2012-10-27 22:27:55.898699881 +0200 -@@ -76,8 +76,10 @@ - // assert( RetValue ); - - // clean the data of the nodes in the window -- Ntk_NetworkForEachNodeSpecial( pWnd->pNet, pNode ) -- pNode->pCopy = (Ntk_Node_t *)pNode->pData = NULL; -+ Ntk_NetworkForEachNodeSpecial( pWnd->pNet, pNode ) { -+ pNode->pData = NULL; -+ pNode->pCopy = NULL; -+ } - - // set the leaves - pgInputs = Sh_ManagerReadVars( pMan ); diff --git a/yosys/manual/CHAPTER_StateOfTheArt/simlib_hana.v b/yosys/manual/CHAPTER_StateOfTheArt/simlib_hana.v deleted file mode 100644 index 7fb54fa49..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/simlib_hana.v +++ /dev/null @@ -1,1139 +0,0 @@ -/* -Copyright (C) 2009-2010 Parvez Ahmad -Written by Parvez Ahmad . - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . */ - - -module BUF (input in, output out); - -assign out = in; - -endmodule - -module TRIBUF(input in, enable, output out); - -assign out = enable ? in : 1'bz; - -endmodule - -module INV(input in, output out); - -assign out = ~in; - -endmodule - -module AND2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out); - -assign out = ∈ - -endmodule - -module AND3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out); - -assign out = ∈ - -endmodule - -module AND4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out); - -assign out = ∈ - -endmodule - -module OR2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out); - -assign out = |in; - -endmodule - -module OR3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out); - -assign out = |in; - -endmodule - -module OR4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out); - -assign out = |in; - -endmodule - - -module NAND2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out); - -assign out = ~∈ - -endmodule - -module NAND3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out); - -assign out = ~∈ - -endmodule - -module NAND4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out); - -assign out = ~∈ - -endmodule - -module NOR2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out); - -assign out = ~|in; - -endmodule - -module NOR3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out); - -assign out = ~|in; - -endmodule - -module NOR4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out); - -assign out = ~|in; - -endmodule - - -module XOR2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out); - -assign out = ^in; - -endmodule - -module XOR3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out); - -assign out = ^in; - -endmodule - -module XOR4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out); - -assign out = ^in; - -endmodule - - -module XNOR2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output out); - -assign out = ~^in; - -endmodule - -module XNOR3 #(parameter SIZE = 3) (input [SIZE-1:0] in, output out); - -assign out = ~^in; - -endmodule - -module XNOR4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output out); - -assign out = ~^in; - -endmodule - -module DEC1 (input in, enable, output reg [1:0] out); - -always @(in or enable) - if(!enable) - out = 2'b00; - else begin - case (in) - 1'b0 : out = 2'b01; - 1'b1 : out = 2'b10; - endcase - end -endmodule - -module DEC2 (input [1:0] in, input enable, output reg [3:0] out); - -always @(in or enable) - if(!enable) - out = 4'b0000; - else begin - case (in) - 2'b00 : out = 4'b0001; - 2'b01 : out = 4'b0010; - 2'b10 : out = 4'b0100; - 2'b11 : out = 4'b1000; - endcase - end -endmodule - -module DEC3 (input [2:0] in, input enable, output reg [7:0] out); - -always @(in or enable) - if(!enable) - out = 8'b00000000; - else begin - case (in) - 3'b000 : out = 8'b00000001; - 3'b001 : out = 8'b00000010; - 3'b010 : out = 8'b00000100; - 3'b011 : out = 8'b00001000; - 3'b100 : out = 8'b00010000; - 3'b101 : out = 8'b00100000; - 3'b110 : out = 8'b01000000; - 3'b111 : out = 8'b10000000; - endcase - end -endmodule - -module DEC4 (input [3:0] in, input enable, output reg [15:0] out); - -always @(in or enable) - if(!enable) - out = 16'b0000000000000000; - else begin - case (in) - 4'b0000 : out = 16'b0000000000000001; - 4'b0001 : out = 16'b0000000000000010; - 4'b0010 : out = 16'b0000000000000100; - 4'b0011 : out = 16'b0000000000001000; - 4'b0100 : out = 16'b0000000000010000; - 4'b0101 : out = 16'b0000000000100000; - 4'b0110 : out = 16'b0000000001000000; - 4'b0111 : out = 16'b0000000010000000; - 4'b1000 : out = 16'b0000000100000000; - 4'b1001 : out = 16'b0000001000000000; - 4'b1010 : out = 16'b0000010000000000; - 4'b1011 : out = 16'b0000100000000000; - 4'b1100 : out = 16'b0001000000000000; - 4'b1101 : out = 16'b0010000000000000; - 4'b1110 : out = 16'b0100000000000000; - 4'b1111 : out = 16'b1000000000000000; - endcase - end -endmodule -module DEC5 (input [4:0] in, input enable, output reg [31:0] out); - -always @(in or enable) - if(!enable) - out = 32'b00000000000000000000000000000000; - else begin - case (in) - 5'b00000 : out = 32'b00000000000000000000000000000001; - 5'b00001 : out = 32'b00000000000000000000000000000010; - 5'b00010 : out = 32'b00000000000000000000000000000100; - 5'b00011 : out = 32'b00000000000000000000000000001000; - 5'b00100 : out = 32'b00000000000000000000000000010000; - 5'b00101 : out = 32'b00000000000000000000000000100000; - 5'b00110 : out = 32'b00000000000000000000000001000000; - 5'b00111 : out = 32'b00000000000000000000000010000000; - 5'b01000 : out = 32'b00000000000000000000000100000000; - 5'b01001 : out = 32'b00000000000000000000001000000000; - 5'b01010 : out = 32'b00000000000000000000010000000000; - 5'b01011 : out = 32'b00000000000000000000100000000000; - 5'b01100 : out = 32'b00000000000000000001000000000000; - 5'b01101 : out = 32'b00000000000000000010000000000000; - 5'b01110 : out = 32'b00000000000000000100000000000000; - 5'b01111 : out = 32'b00000000000000001000000000000000; - 5'b10000 : out = 32'b00000000000000010000000000000000; - 5'b10001 : out = 32'b00000000000000100000000000000000; - 5'b10010 : out = 32'b00000000000001000000000000000000; - 5'b10011 : out = 32'b00000000000010000000000000000000; - 5'b10100 : out = 32'b00000000000100000000000000000000; - 5'b10101 : out = 32'b00000000001000000000000000000000; - 5'b10110 : out = 32'b00000000010000000000000000000000; - 5'b10111 : out = 32'b00000000100000000000000000000000; - 5'b11000 : out = 32'b00000001000000000000000000000000; - 5'b11001 : out = 32'b00000010000000000000000000000000; - 5'b11010 : out = 32'b00000100000000000000000000000000; - 5'b11011 : out = 32'b00001000000000000000000000000000; - 5'b11100 : out = 32'b00010000000000000000000000000000; - 5'b11101 : out = 32'b00100000000000000000000000000000; - 5'b11110 : out = 32'b01000000000000000000000000000000; - 5'b11111 : out = 32'b10000000000000000000000000000000; - endcase - end -endmodule - -module DEC6 (input [5:0] in, input enable, output reg [63:0] out); - -always @(in or enable) - if(!enable) - out = 64'b0000000000000000000000000000000000000000000000000000000000000000; - else begin - case (in) - 6'b000000 : out = 64'b0000000000000000000000000000000000000000000000000000000000000001; - 6'b000001 : out = 64'b0000000000000000000000000000000000000000000000000000000000000010; - 6'b000010 : out = 64'b0000000000000000000000000000000000000000000000000000000000000100; - 6'b000011 : out = 64'b0000000000000000000000000000000000000000000000000000000000001000; - 6'b000100 : out = 64'b0000000000000000000000000000000000000000000000000000000000010000; - 6'b000101 : out = 64'b0000000000000000000000000000000000000000000000000000000000100000; - 6'b000110 : out = 64'b0000000000000000000000000000000000000000000000000000000001000000; - 6'b000111 : out = 64'b0000000000000000000000000000000000000000000000000000000010000000; - 6'b001000 : out = 64'b0000000000000000000000000000000000000000000000000000000100000000; - 6'b001001 : out = 64'b0000000000000000000000000000000000000000000000000000001000000000; - 6'b001010 : out = 64'b0000000000000000000000000000000000000000000000000000010000000000; - 6'b001011 : out = 64'b0000000000000000000000000000000000000000000000000000100000000000; - 6'b001100 : out = 64'b0000000000000000000000000000000000000000000000000001000000000000; - 6'b001101 : out = 64'b0000000000000000000000000000000000000000000000000010000000000000; - 6'b001110 : out = 64'b0000000000000000000000000000000000000000000000000100000000000000; - 6'b001111 : out = 64'b0000000000000000000000000000000000000000000000001000000000000000; - 6'b010000 : out = 64'b0000000000000000000000000000000000000000000000010000000000000000; - 6'b010001 : out = 64'b0000000000000000000000000000000000000000000000100000000000000000; - 6'b010010 : out = 64'b0000000000000000000000000000000000000000000001000000000000000000; - 6'b010011 : out = 64'b0000000000000000000000000000000000000000000010000000000000000000; - 6'b010100 : out = 64'b0000000000000000000000000000000000000000000100000000000000000000; - 6'b010101 : out = 64'b0000000000000000000000000000000000000000001000000000000000000000; - 6'b010110 : out = 64'b0000000000000000000000000000000000000000010000000000000000000000; - 6'b010111 : out = 64'b0000000000000000000000000000000000000000100000000000000000000000; - 6'b011000 : out = 64'b0000000000000000000000000000000000000001000000000000000000000000; - 6'b011001 : out = 64'b0000000000000000000000000000000000000010000000000000000000000000; - 6'b011010 : out = 64'b0000000000000000000000000000000000000100000000000000000000000000; - 6'b011011 : out = 64'b0000000000000000000000000000000000001000000000000000000000000000; - 6'b011100 : out = 64'b0000000000000000000000000000000000010000000000000000000000000000; - 6'b011101 : out = 64'b0000000000000000000000000000000000100000000000000000000000000000; - 6'b011110 : out = 64'b0000000000000000000000000000000001000000000000000000000000000000; - 6'b011111 : out = 64'b0000000000000000000000000000000010000000000000000000000000000000; - - 6'b100000 : out = 64'b0000000000000000000000000000000100000000000000000000000000000000; - 6'b100001 : out = 64'b0000000000000000000000000000001000000000000000000000000000000000; - 6'b100010 : out = 64'b0000000000000000000000000000010000000000000000000000000000000000; - 6'b100011 : out = 64'b0000000000000000000000000000100000000000000000000000000000000000; - 6'b100100 : out = 64'b0000000000000000000000000001000000000000000000000000000000000000; - 6'b100101 : out = 64'b0000000000000000000000000010000000000000000000000000000000000000; - 6'b100110 : out = 64'b0000000000000000000000000100000000000000000000000000000000000000; - 6'b100111 : out = 64'b0000000000000000000000001000000000000000000000000000000000000000; - 6'b101000 : out = 64'b0000000000000000000000010000000000000000000000000000000000000000; - 6'b101001 : out = 64'b0000000000000000000000100000000000000000000000000000000000000000; - 6'b101010 : out = 64'b0000000000000000000001000000000000000000000000000000000000000000; - 6'b101011 : out = 64'b0000000000000000000010000000000000000000000000000000000000000000; - 6'b101100 : out = 64'b0000000000000000000100000000000000000000000000000000000000000000; - 6'b101101 : out = 64'b0000000000000000001000000000000000000000000000000000000000000000; - 6'b101110 : out = 64'b0000000000000000010000000000000000000000000000000000000000000000; - 6'b101111 : out = 64'b0000000000000000100000000000000000000000000000000000000000000000; - 6'b110000 : out = 64'b0000000000000001000000000000000000000000000000000000000000000000; - 6'b110001 : out = 64'b0000000000000010000000000000000000000000000000000000000000000000; - 6'b110010 : out = 64'b0000000000000100000000000000000000000000000000000000000000000000; - 6'b110011 : out = 64'b0000000000001000000000000000000000000000000000000000000000000000; - 6'b110100 : out = 64'b0000000000010000000000000000000000000000000000000000000000000000; - 6'b110101 : out = 64'b0000000000100000000000000000000000000000000000000000000000000000; - 6'b110110 : out = 64'b0000000001000000000000000000000000000000000000000000000000000000; - 6'b110111 : out = 64'b0000000010000000000000000000000000000000000000000000000000000000; - 6'b111000 : out = 64'b0000000100000000000000000000000000000000000000000000000000000000; - 6'b111001 : out = 64'b0000001000000000000000000000000000000000000000000000000000000000; - 6'b111010 : out = 64'b0000010000000000000000000000000000000000000000000000000000000000; - 6'b111011 : out = 64'b0000100000000000000000000000000000000000000000000000000000000000; - 6'b111100 : out = 64'b0001000000000000000000000000000000000000000000000000000000000000; - 6'b111101 : out = 64'b0010000000000000000000000000000000000000000000000000000000000000; - 6'b111110 : out = 64'b0100000000000000000000000000000000000000000000000000000000000000; - 6'b111111 : out = 64'b1000000000000000000000000000000000000000000000000000000000000000; - endcase - end -endmodule - - -module MUX2(input [1:0] in, input select, output reg out); - -always @( in or select) - case (select) - 0: out = in[0]; - 1: out = in[1]; - endcase -endmodule - - -module MUX4(input [3:0] in, input [1:0] select, output reg out); - -always @( in or select) - case (select) - 0: out = in[0]; - 1: out = in[1]; - 2: out = in[2]; - 3: out = in[3]; - endcase -endmodule - - -module MUX8(input [7:0] in, input [2:0] select, output reg out); - -always @( in or select) - case (select) - 0: out = in[0]; - 1: out = in[1]; - 2: out = in[2]; - 3: out = in[3]; - 4: out = in[4]; - 5: out = in[5]; - 6: out = in[6]; - 7: out = in[7]; - endcase -endmodule - -module MUX16(input [15:0] in, input [3:0] select, output reg out); - -always @( in or select) - case (select) - 0: out = in[0]; - 1: out = in[1]; - 2: out = in[2]; - 3: out = in[3]; - 4: out = in[4]; - 5: out = in[5]; - 6: out = in[6]; - 7: out = in[7]; - 8: out = in[8]; - 9: out = in[9]; - 10: out = in[10]; - 11: out = in[11]; - 12: out = in[12]; - 13: out = in[13]; - 14: out = in[14]; - 15: out = in[15]; - endcase -endmodule - -module MUX32(input [31:0] in, input [4:0] select, output reg out); - -always @( in or select) - case (select) - 0: out = in[0]; - 1: out = in[1]; - 2: out = in[2]; - 3: out = in[3]; - 4: out = in[4]; - 5: out = in[5]; - 6: out = in[6]; - 7: out = in[7]; - 8: out = in[8]; - 9: out = in[9]; - 10: out = in[10]; - 11: out = in[11]; - 12: out = in[12]; - 13: out = in[13]; - 14: out = in[14]; - 15: out = in[15]; - 16: out = in[16]; - 17: out = in[17]; - 18: out = in[18]; - 19: out = in[19]; - 20: out = in[20]; - 21: out = in[21]; - 22: out = in[22]; - 23: out = in[23]; - 24: out = in[24]; - 25: out = in[25]; - 26: out = in[26]; - 27: out = in[27]; - 28: out = in[28]; - 29: out = in[29]; - 30: out = in[30]; - 31: out = in[31]; - endcase -endmodule - -module MUX64(input [63:0] in, input [5:0] select, output reg out); - -always @( in or select) - case (select) - 0: out = in[0]; - 1: out = in[1]; - 2: out = in[2]; - 3: out = in[3]; - 4: out = in[4]; - 5: out = in[5]; - 6: out = in[6]; - 7: out = in[7]; - 8: out = in[8]; - 9: out = in[9]; - 10: out = in[10]; - 11: out = in[11]; - 12: out = in[12]; - 13: out = in[13]; - 14: out = in[14]; - 15: out = in[15]; - 16: out = in[16]; - 17: out = in[17]; - 18: out = in[18]; - 19: out = in[19]; - 20: out = in[20]; - 21: out = in[21]; - 22: out = in[22]; - 23: out = in[23]; - 24: out = in[24]; - 25: out = in[25]; - 26: out = in[26]; - 27: out = in[27]; - 28: out = in[28]; - 29: out = in[29]; - 30: out = in[30]; - 31: out = in[31]; - 32: out = in[32]; - 33: out = in[33]; - 34: out = in[34]; - 35: out = in[35]; - 36: out = in[36]; - 37: out = in[37]; - 38: out = in[38]; - 39: out = in[39]; - 40: out = in[40]; - 41: out = in[41]; - 42: out = in[42]; - 43: out = in[43]; - 44: out = in[44]; - 45: out = in[45]; - 46: out = in[46]; - 47: out = in[47]; - 48: out = in[48]; - 49: out = in[49]; - 50: out = in[50]; - 51: out = in[51]; - 52: out = in[52]; - 53: out = in[53]; - 54: out = in[54]; - 55: out = in[55]; - 56: out = in[56]; - 57: out = in[57]; - 58: out = in[58]; - 59: out = in[59]; - 60: out = in[60]; - 61: out = in[61]; - 62: out = in[62]; - 63: out = in[63]; - endcase -endmodule - -module ADD1(input in1, in2, cin, output out, cout); - -assign {cout, out} = in1 + in2 + cin; - -endmodule - -module ADD2 #(parameter SIZE = 2)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 + in2 + cin; - -endmodule - -module ADD4 #(parameter SIZE = 4)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 + in2 + cin; - -endmodule - -module ADD8 #(parameter SIZE = 8)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 + in2 + cin; - -endmodule - -module ADD16 #(parameter SIZE = 16)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 + in2 + cin; - -endmodule - -module ADD32 #(parameter SIZE = 32)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 + in2 + cin; - -endmodule -module ADD64 #(parameter SIZE = 64)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 + in2 + cin; - -endmodule - -module SUB1(input in1, in2, cin, output out, cout); - -assign {cout, out} = in1 - in2 - cin; - -endmodule - -module SUB2 #(parameter SIZE = 2)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 - in2 - cin; - -endmodule - -module SUB4 #(parameter SIZE = 4)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 - in2 - cin; - -endmodule - -module SUB8 #(parameter SIZE = 8)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 - in2 - cin; - -endmodule - -module SUB16 #(parameter SIZE = 16)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 - in2 - cin; - -endmodule - -module SUB32 #(parameter SIZE = 32)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 - in2 - cin; - -endmodule -module SUB64 #(parameter SIZE = 64)(input [SIZE-1:0] in1, in2, - input cin, output [SIZE-1:0] out, output cout); - -assign {cout, out} = in1 - in2 - cin; - -endmodule - -module MUL1 #(parameter SIZE = 1)(input in1, in2, output [2*SIZE-1:0] out); - -assign out = in1*in2; - -endmodule - -module MUL2 #(parameter SIZE = 2)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out); - -assign out = in1*in2; - -endmodule - -module MUL4 #(parameter SIZE = 4)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out); - -assign out = in1*in2; - -endmodule - -module MUL8 #(parameter SIZE = 8)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out); - -assign out = in1*in2; - -endmodule - -module MUL16 #(parameter SIZE = 16)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out); - -assign out = in1*in2; - -endmodule - -module MUL32 #(parameter SIZE = 32)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out); - -assign out = in1*in2; - -endmodule - -module MUL64 #(parameter SIZE = 64)(input [SIZE-1:0] in1, in2, output [2*SIZE-1:0] out); - -assign out = in1*in2; - -endmodule - -module DIV1 #(parameter SIZE = 1)(input in1, in2, output out, rem); - -assign out = in1/in2; -assign rem = in1%in2; - -endmodule - -module DIV2 #(parameter SIZE = 2)(input [SIZE-1:0] in1, in2, - output [SIZE-1:0] out, rem); - -assign out = in1/in2; -assign rem = in1%in2; - -endmodule - -module DIV4 #(parameter SIZE = 4)(input [SIZE-1:0] in1, in2, - output [SIZE-1:0] out, rem); - -assign out = in1/in2; -assign rem = in1%in2; - -endmodule - -module DIV8 #(parameter SIZE = 8)(input [SIZE-1:0] in1, in2, - output [SIZE-1:0] out, rem); - -assign out = in1/in2; -assign rem = in1%in2; - -endmodule - -module DIV16 #(parameter SIZE = 16)(input [SIZE-1:0] in1, in2, - output [SIZE-1:0] out, rem); - -assign out = in1/in2; -assign rem = in1%in2; - -endmodule - -module DIV32 #(parameter SIZE = 32)(input [SIZE-1:0] in1, in2, - output [SIZE-1:0] out, rem); - -assign out = in1/in2; -assign rem = in1%in2; - -endmodule - -module DIV64 #(parameter SIZE = 64)(input [SIZE-1:0] in1, in2, - output [SIZE-1:0] out, rem); - -assign out = in1/in2; -assign rem = in1%in2; - -endmodule - -module FF (input d, clk, output reg q); -always @( posedge clk) - q <= d; -endmodule - - -module RFF(input d, clk, reset, output reg q); -always @(posedge clk or posedge reset) - if(reset) - q <= 0; - else - q <= d; -endmodule - -module SFF(input d, clk, set, output reg q); -always @(posedge clk or posedge set) - if(set) - q <= 1; - else - q <= d; -endmodule - -module RSFF(input d, clk, set, reset, output reg q); -always @(posedge clk or posedge reset or posedge set) - if(reset) - q <= 0; - else if(set) - q <= 1; - else - q <= d; -endmodule - -module SRFF(input d, clk, set, reset, output reg q); -always @(posedge clk or posedge set or posedge reset) - if(set) - q <= 1; - else if(reset) - q <= 0; - else - q <= d; -endmodule - -module LATCH(input d, enable, output reg q); -always @( d or enable) - if(enable) - q <= d; -endmodule - -module RLATCH(input d, reset, enable, output reg q); -always @( d or enable or reset) - if(enable) - if(reset) - q <= 0; - else - q <= d; -endmodule - -module LSHIFT1 #(parameter SIZE = 1)(input in, shift, val, output reg out); - -always @ (in, shift, val) begin - if(shift) - out = val; - else - out = in; -end - -endmodule - - -module LSHIFT2 #(parameter SIZE = 2)(input [SIZE-1:0] in, - input [SIZE-1:0] shift, input val, - output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in << shift; - if(val) - out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift)); -end -endmodule - -module LSHIFT4 #(parameter SIZE = 4)(input [SIZE-1:0] in, - input [2:0] shift, input val, output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in << shift; - if(val) - out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift)); -end -endmodule - - -module LSHIFT8 #(parameter SIZE = 8)(input [SIZE-1:0] in, - input [3:0] shift, input val, output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in << shift; - if(val) - out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift)); -end -endmodule - -module LSHIFT16 #(parameter SIZE = 16)(input [SIZE-1:0] in, - input [4:0] shift, input val, output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in << shift; - if(val) - out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift)); -end -endmodule - -module LSHIFT32 #(parameter SIZE = 32)(input [SIZE-1:0] in, - input [5:0] shift, input val, output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in << shift; - if(val) - out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift)); -end -endmodule - -module LSHIFT64 #(parameter SIZE = 64)(input [SIZE-1:0] in, - input [6:0] shift, input val, output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in << shift; - if(val) - out = out | ({SIZE-1 {1'b1} } >> (SIZE-1-shift)); -end -endmodule - -module RSHIFT1 #(parameter SIZE = 1)(input in, shift, val, output reg out); - -always @ (in, shift, val) begin - if(shift) - out = val; - else - out = in; -end - -endmodule - -module RSHIFT2 #(parameter SIZE = 2)(input [SIZE-1:0] in, - input [SIZE-1:0] shift, input val, - output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in >> shift; - if(val) - out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift)); -end - -endmodule - - -module RSHIFT4 #(parameter SIZE = 4)(input [SIZE-1:0] in, - input [2:0] shift, input val, - output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in >> shift; - if(val) - out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift)); -end -endmodule - -module RSHIFT8 #(parameter SIZE = 8)(input [SIZE-1:0] in, - input [3:0] shift, input val, - output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in >> shift; - if(val) - out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift)); -end - -endmodule - -module RSHIFT16 #(parameter SIZE = 16)(input [SIZE-1:0] in, - input [4:0] shift, input val, - output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in >> shift; - if(val) - out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift)); -end -endmodule - - -module RSHIFT32 #(parameter SIZE = 32)(input [SIZE-1:0] in, - input [5:0] shift, input val, - output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in >> shift; - if(val) - out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift)); -end -endmodule - -module RSHIFT64 #(parameter SIZE = 64)(input [SIZE-1:0] in, - input [6:0] shift, input val, - output reg [SIZE-1:0] out); - -always @(in or shift or val) begin - out = in >> shift; - if(val) - out = out | ({SIZE-1 {1'b1} } << (SIZE-1-shift)); -end -endmodule - -module CMP1 #(parameter SIZE = 1) (input in1, in2, - output reg equal, unequal, greater, lesser); - -always @ (in1 or in2) begin - if(in1 == in2) begin - equal = 1; - unequal = 0; - greater = 0; - lesser = 0; - end - else begin - equal = 0; - unequal = 1; - - if(in1 < in2) begin - greater = 0; - lesser = 1; - end - else begin - greater = 1; - lesser = 0; - end - end -end -endmodule - - -module CMP2 #(parameter SIZE = 2) (input [SIZE-1:0] in1, in2, - output reg equal, unequal, greater, lesser); - -always @ (in1 or in2) begin - if(in1 == in2) begin - equal = 1; - unequal = 0; - greater = 0; - lesser = 0; - end - else begin - equal = 0; - unequal = 1; - - if(in1 < in2) begin - greater = 0; - lesser = 1; - end - else begin - greater = 1; - lesser = 0; - end - end -end -endmodule - -module CMP4 #(parameter SIZE = 4) (input [SIZE-1:0] in1, in2, - output reg equal, unequal, greater, lesser); - -always @ (in1 or in2) begin - if(in1 == in2) begin - equal = 1; - unequal = 0; - greater = 0; - lesser = 0; - end - else begin - equal = 0; - unequal = 1; - - if(in1 < in2) begin - greater = 0; - lesser = 1; - end - else begin - greater = 1; - lesser = 0; - end - end -end -endmodule - -module CMP8 #(parameter SIZE = 8) (input [SIZE-1:0] in1, in2, - output reg equal, unequal, greater, lesser); - -always @ (in1 or in2) begin - if(in1 == in2) begin - equal = 1; - unequal = 0; - greater = 0; - lesser = 0; - end - else begin - equal = 0; - unequal = 1; - - if(in1 < in2) begin - greater = 0; - lesser = 1; - end - else begin - greater = 1; - lesser = 0; - end - end -end -endmodule - -module CMP16 #(parameter SIZE = 16) (input [SIZE-1:0] in1, in2, - output reg equal, unequal, greater, lesser); - -always @ (in1 or in2) begin - if(in1 == in2) begin - equal = 1; - unequal = 0; - greater = 0; - lesser = 0; - end - else begin - equal = 0; - unequal = 1; - - if(in1 < in2) begin - greater = 0; - lesser = 1; - end - else begin - greater = 1; - lesser = 0; - end - end -end -endmodule - -module CMP32 #(parameter SIZE = 32) (input [SIZE-1:0] in1, in2, - output reg equal, unequal, greater, lesser); - -always @ (in1 or in2) begin - if(in1 == in2) begin - equal = 1; - unequal = 0; - greater = 0; - lesser = 0; - end - else begin - equal = 0; - unequal = 1; - - if(in1 < in2) begin - greater = 0; - lesser = 1; - end - else begin - greater = 1; - lesser = 0; - end - end -end -endmodule - -module CMP64 #(parameter SIZE = 64) (input [SIZE-1:0] in1, in2, - output reg equal, unequal, greater, lesser); - -always @ (in1 or in2) begin - if(in1 == in2) begin - equal = 1; - unequal = 0; - greater = 0; - lesser = 0; - end - else begin - equal = 0; - unequal = 1; - - if(in1 < in2) begin - greater = 0; - lesser = 1; - end - else begin - greater = 1; - lesser = 0; - end - end -end -endmodule - -module VCC (output supply1 out); -endmodule - -module GND (output supply0 out); -endmodule - - -module INC1 #(parameter SIZE = 1) (input in, output [SIZE:0] out); - -assign out = in + 1; - -endmodule - -module INC2 #(parameter SIZE = 2) (input [SIZE-1:0] in, output [SIZE:0] out); - -assign out = in + 1; - -endmodule - -module INC4 #(parameter SIZE = 4) (input [SIZE-1:0] in, output [SIZE:0] out); -assign out = in + 1; - -endmodule - -module INC8 #(parameter SIZE = 8) (input [SIZE-1:0] in, output [SIZE:0] out); -assign out = in + 1; - -endmodule - -module INC16 #(parameter SIZE = 16) (input [SIZE-1:0] in, output [SIZE:0] out); -assign out = in + 1; - -endmodule - -module INC32 #(parameter SIZE = 32) (input [SIZE-1:0] in, output [SIZE:0] out); -assign out = in + 1; - -endmodule -module INC64 #(parameter SIZE = 64) (input [SIZE-1:0] in, output [SIZE:0] out); -assign out = in + 1; - -endmodule - diff --git a/yosys/manual/CHAPTER_StateOfTheArt/simlib_icarus.v b/yosys/manual/CHAPTER_StateOfTheArt/simlib_icarus.v deleted file mode 100644 index fdd7ef61f..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/simlib_icarus.v +++ /dev/null @@ -1,224 +0,0 @@ - -module cell0(Result0); -output Result0; -assign Result0 = 0; -endmodule - -module cell1(Result0); -output Result0; -assign Result0 = 1; -endmodule - -module ADD4( - DataA0, DataA1, DataA2, DataA3, - DataB0, DataB1, DataB2, DataB3, - Result0, Result1, Result2, Result3, Cout -); -input DataA0, DataA1, DataA2, DataA3; -input DataB0, DataB1, DataB2, DataB3; -output Result0, Result1, Result2, Result3, Cout; -assign {Cout, Result3, Result2, Result1, Result0} = {DataA3, DataA2, DataA1, DataA0} + {DataB3, DataB2, DataB1, DataB0}; -endmodule - -module BUF(DATA, RESULT); -input DATA; -output RESULT; -assign RESULT = DATA; -endmodule - -module INV(DATA, RESULT); -input DATA; -output RESULT; -assign RESULT = ~DATA; -endmodule - -module fd4( - Clock, - Data0, Data1, Data2, Data3, - Q0, Q1, Q2, Q3 -); -input Clock; -input Data0, Data1, Data2, Data3; -output reg Q0, Q1, Q2, Q3; -always @(posedge Clock) - {Q0, Q1, Q2, Q3} <= {Data0, Data1, Data2, Data3}; -endmodule - -module fdce1( - Clock, Enable, - Data0, - Q0 -); -input Clock, Enable; -input Data0; -output reg Q0; -always @(posedge Clock) - if (Enable) - Q0 <= Data0; -endmodule - -module fdce4( - Clock, Enable, - Data0, Data1, Data2, Data3, - Q0, Q1, Q2, Q3 -); -input Clock, Enable; -input Data0, Data1, Data2, Data3; -output reg Q0, Q1, Q2, Q3; -always @(posedge Clock) - if (Enable) - {Q0, Q1, Q2, Q3} <= {Data0, Data1, Data2, Data3}; -endmodule - -module mux4_1_2( - Sel0, - Data0x0, Data0x1, Data0x2, Data0x3, - Data1x0, Data1x1, Data1x2, Data1x3, - Result0, Result1, Result2, Result3 -); -input Sel0; -input Data0x0, Data0x1, Data0x2, Data0x3; -input Data1x0, Data1x1, Data1x2, Data1x3; -output Result0, Result1, Result2, Result3; -assign {Result0, Result1, Result2, Result3} = Sel0 ? {Data1x0, Data1x1, Data1x2, Data1x3} : {Data0x0, Data0x1, Data0x2, Data0x3}; -endmodule - -module mux1_1_2( - Sel0, - Data0x0, - Data1x0, - Result0 -); -input Sel0; -input Data0x0; -input Data1x0; -output Result0; -assign Result0 = Sel0 ? Data1x0 : Data0x0; -endmodule - -module xor2( - DATA0X0, - DATA1X0, - RESULT0 -); -input DATA0X0; -input DATA1X0; -output RESULT0; -assign RESULT0 = DATA1X0 ^ DATA0X0; -endmodule - -module fdce64( - Clock, Enable, - Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, Data24, Data25, Data26, Data27, Data28, Data29, Data30, Data31, Data32, Data33, Data34, Data35, Data36, Data37, Data38, Data39, Data40, Data41, Data42, Data43, Data44, Data45, Data46, Data47, Data48, Data49, Data50, Data51, Data52, Data53, Data54, Data55, Data56, Data57, Data58, Data59, Data60, Data61, Data62, Data63, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, Q32, Q33, Q34, Q35, Q36, Q37, Q38, Q39, Q40, Q41, Q42, Q43, Q44, Q45, Q46, Q47, Q48, Q49, Q50, Q51, Q52, Q53, Q54, Q55, Q56, Q57, Q58, Q59, Q60, Q61, Q62, Q63 -); -input Clock, Enable; -input Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, Data24, Data25, Data26, Data27, Data28, Data29, Data30, Data31, Data32, Data33, Data34, Data35, Data36, Data37, Data38, Data39, Data40, Data41, Data42, Data43, Data44, Data45, Data46, Data47, Data48, Data49, Data50, Data51, Data52, Data53, Data54, Data55, Data56, Data57, Data58, Data59, Data60, Data61, Data62, Data63; -output reg Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, Q32, Q33, Q34, Q35, Q36, Q37, Q38, Q39, Q40, Q41, Q42, Q43, Q44, Q45, Q46, Q47, Q48, Q49, Q50, Q51, Q52, Q53, Q54, Q55, Q56, Q57, Q58, Q59, Q60, Q61, Q62, Q63; -always @(posedge Clock) - if (Enable) - { Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, Q32, Q33, Q34, Q35, Q36, Q37, Q38, Q39, Q40, Q41, Q42, Q43, Q44, Q45, Q46, Q47, Q48, Q49, Q50, Q51, Q52, Q53, Q54, Q55, Q56, Q57, Q58, Q59, Q60, Q61, Q62, Q63 } <= { Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, Data24, Data25, Data26, Data27, Data28, Data29, Data30, Data31, Data32, Data33, Data34, Data35, Data36, Data37, Data38, Data39, Data40, Data41, Data42, Data43, Data44, Data45, Data46, Data47, Data48, Data49, Data50, Data51, Data52, Data53, Data54, Data55, Data56, Data57, Data58, Data59, Data60, Data61, Data62, Data63 }; -endmodule - -module mux4_4_16( - Sel0, Sel1, Sel2, Sel3, - Result0, Result1, Result2, Result3, - Data0x0, Data0x1, Data0x2, Data0x3, - Data1x0, Data1x1, Data1x2, Data1x3, - Data2x0, Data2x1, Data2x2, Data2x3, - Data3x0, Data3x1, Data3x2, Data3x3, - Data4x0, Data4x1, Data4x2, Data4x3, - Data5x0, Data5x1, Data5x2, Data5x3, - Data6x0, Data6x1, Data6x2, Data6x3, - Data7x0, Data7x1, Data7x2, Data7x3, - Data8x0, Data8x1, Data8x2, Data8x3, - Data9x0, Data9x1, Data9x2, Data9x3, - Data10x0, Data10x1, Data10x2, Data10x3, - Data11x0, Data11x1, Data11x2, Data11x3, - Data12x0, Data12x1, Data12x2, Data12x3, - Data13x0, Data13x1, Data13x2, Data13x3, - Data14x0, Data14x1, Data14x2, Data14x3, - Data15x0, Data15x1, Data15x2, Data15x3 -); -input Sel0, Sel1, Sel2, Sel3; -output Result0, Result1, Result2, Result3; -input Data0x0, Data0x1, Data0x2, Data0x3; -input Data1x0, Data1x1, Data1x2, Data1x3; -input Data2x0, Data2x1, Data2x2, Data2x3; -input Data3x0, Data3x1, Data3x2, Data3x3; -input Data4x0, Data4x1, Data4x2, Data4x3; -input Data5x0, Data5x1, Data5x2, Data5x3; -input Data6x0, Data6x1, Data6x2, Data6x3; -input Data7x0, Data7x1, Data7x2, Data7x3; -input Data8x0, Data8x1, Data8x2, Data8x3; -input Data9x0, Data9x1, Data9x2, Data9x3; -input Data10x0, Data10x1, Data10x2, Data10x3; -input Data11x0, Data11x1, Data11x2, Data11x3; -input Data12x0, Data12x1, Data12x2, Data12x3; -input Data13x0, Data13x1, Data13x2, Data13x3; -input Data14x0, Data14x1, Data14x2, Data14x3; -input Data15x0, Data15x1, Data15x2, Data15x3; -assign {Result0, Result1, Result2, Result3} = - {Sel3, Sel2, Sel1, Sel0} == 0 ? { Data0x0, Data0x1, Data0x2, Data0x3 } : - {Sel3, Sel2, Sel1, Sel0} == 1 ? { Data1x0, Data1x1, Data1x2, Data1x3 } : - {Sel3, Sel2, Sel1, Sel0} == 2 ? { Data2x0, Data2x1, Data2x2, Data2x3 } : - {Sel3, Sel2, Sel1, Sel0} == 3 ? { Data3x0, Data3x1, Data3x2, Data3x3 } : - {Sel3, Sel2, Sel1, Sel0} == 4 ? { Data4x0, Data4x1, Data4x2, Data4x3 } : - {Sel3, Sel2, Sel1, Sel0} == 5 ? { Data5x0, Data5x1, Data5x2, Data5x3 } : - {Sel3, Sel2, Sel1, Sel0} == 6 ? { Data6x0, Data6x1, Data6x2, Data6x3 } : - {Sel3, Sel2, Sel1, Sel0} == 7 ? { Data7x0, Data7x1, Data7x2, Data7x3 } : - {Sel3, Sel2, Sel1, Sel0} == 8 ? { Data8x0, Data8x1, Data8x2, Data8x3 } : - {Sel3, Sel2, Sel1, Sel0} == 9 ? { Data9x0, Data9x1, Data9x2, Data9x3 } : - {Sel3, Sel2, Sel1, Sel0} == 10 ? { Data10x0, Data10x1, Data10x2, Data10x3 } : - {Sel3, Sel2, Sel1, Sel0} == 11 ? { Data11x0, Data11x1, Data11x2, Data11x3 } : - {Sel3, Sel2, Sel1, Sel0} == 12 ? { Data12x0, Data12x1, Data12x2, Data12x3 } : - {Sel3, Sel2, Sel1, Sel0} == 13 ? { Data13x0, Data13x1, Data13x2, Data13x3 } : - {Sel3, Sel2, Sel1, Sel0} == 14 ? { Data14x0, Data14x1, Data14x2, Data14x3 } : - {Sel3, Sel2, Sel1, Sel0} == 15 ? { Data15x0, Data15x1, Data15x2, Data15x3 } : 'bx; -endmodule - -module mux1_5_32( - Sel0, Sel1, Sel2, Sel3, Sel4, - Data0x0, Data1x0, Data2x0, Data3x0, Data4x0, Data5x0, Data6x0, Data7x0, Data8x0, Data9x0, Data10x0, Data11x0, Data12x0, Data13x0, Data14x0, Data15x0, - Data16x0, Data17x0, Data18x0, Data19x0, Data20x0, Data21x0, Data22x0, Data23x0, Data24x0, Data25x0, Data26x0, Data27x0, Data28x0, Data29x0, Data30x0, Data31x0, - Result0 -); -input Sel0, Sel1, Sel2, Sel3, Sel4; -input Data0x0, Data1x0, Data2x0, Data3x0, Data4x0, Data5x0, Data6x0, Data7x0, Data8x0, Data9x0, Data10x0, Data11x0, Data12x0, Data13x0, Data14x0, Data15x0; -input Data16x0, Data17x0, Data18x0, Data19x0, Data20x0, Data21x0, Data22x0, Data23x0, Data24x0, Data25x0, Data26x0, Data27x0, Data28x0, Data29x0, Data30x0, Data31x0; -output Result0; -assign Result0 = - {Sel4, Sel3, Sel2, Sel1, Sel0} == 0 ? Data0x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 1 ? Data1x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 2 ? Data2x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 3 ? Data3x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 4 ? Data4x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 5 ? Data5x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 6 ? Data6x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 7 ? Data7x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 8 ? Data8x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 9 ? Data9x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 10 ? Data10x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 11 ? Data11x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 12 ? Data12x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 13 ? Data13x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 14 ? Data14x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 15 ? Data15x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 16 ? Data16x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 17 ? Data17x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 18 ? Data18x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 19 ? Data19x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 20 ? Data20x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 21 ? Data21x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 22 ? Data22x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 23 ? Data23x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 24 ? Data24x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 25 ? Data25x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 26 ? Data26x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 27 ? Data27x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 28 ? Data28x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 29 ? Data29x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 30 ? Data30x0 : - {Sel4, Sel3, Sel2, Sel1, Sel0} == 31 ? Data31x0 : 'bx; -endmodule - diff --git a/yosys/manual/CHAPTER_StateOfTheArt/simlib_yosys.v b/yosys/manual/CHAPTER_StateOfTheArt/simlib_yosys.v deleted file mode 100644 index 454c9a83f..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/simlib_yosys.v +++ /dev/null @@ -1,166 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * The internal logic cell simulation library. - * - * This Verilog library contains simple simulation models for the internal - * logic cells (_NOT_, _AND_, ...) that are generated by the default technology - * mapper (see "stdcells.v" in this directory) and expected by the "abc" pass. - * - */ - -module _NOT_(A, Y); -input A; -output Y; -assign Y = ~A; -endmodule - -module _AND_(A, B, Y); -input A, B; -output Y; -assign Y = A & B; -endmodule - -module _OR_(A, B, Y); -input A, B; -output Y; -assign Y = A | B; -endmodule - -module _XOR_(A, B, Y); -input A, B; -output Y; -assign Y = A ^ B; -endmodule - -module _MUX_(A, B, S, Y); -input A, B, S; -output reg Y; -always @* begin - if (S) - Y = B; - else - Y = A; -end -endmodule - -module _DFF_N_(D, Q, C); -input D, C; -output reg Q; -always @(negedge C) begin - Q <= D; -end -endmodule - -module _DFF_P_(D, Q, C); -input D, C; -output reg Q; -always @(posedge C) begin - Q <= D; -end -endmodule - -module _DFF_NN0_(D, Q, C, R); -input D, C, R; -output reg Q; -always @(negedge C or negedge R) begin - if (R == 0) - Q <= 0; - else - Q <= D; -end -endmodule - -module _DFF_NN1_(D, Q, C, R); -input D, C, R; -output reg Q; -always @(negedge C or negedge R) begin - if (R == 0) - Q <= 1; - else - Q <= D; -end -endmodule - -module _DFF_NP0_(D, Q, C, R); -input D, C, R; -output reg Q; -always @(negedge C or posedge R) begin - if (R == 1) - Q <= 0; - else - Q <= D; -end -endmodule - -module _DFF_NP1_(D, Q, C, R); -input D, C, R; -output reg Q; -always @(negedge C or posedge R) begin - if (R == 1) - Q <= 1; - else - Q <= D; -end -endmodule - -module _DFF_PN0_(D, Q, C, R); -input D, C, R; -output reg Q; -always @(posedge C or negedge R) begin - if (R == 0) - Q <= 0; - else - Q <= D; -end -endmodule - -module _DFF_PN1_(D, Q, C, R); -input D, C, R; -output reg Q; -always @(posedge C or negedge R) begin - if (R == 0) - Q <= 1; - else - Q <= D; -end -endmodule - -module _DFF_PP0_(D, Q, C, R); -input D, C, R; -output reg Q; -always @(posedge C or posedge R) begin - if (R == 1) - Q <= 0; - else - Q <= D; -end -endmodule - -module _DFF_PP1_(D, Q, C, R); -input D, C, R; -output reg Q; -always @(posedge C or posedge R) begin - if (R == 1) - Q <= 1; - else - Q <= D; -end -endmodule - diff --git a/yosys/manual/CHAPTER_StateOfTheArt/sis-1.3.6-buildfixes.patch b/yosys/manual/CHAPTER_StateOfTheArt/sis-1.3.6-buildfixes.patch deleted file mode 100644 index ad957d6b8..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/sis-1.3.6-buildfixes.patch +++ /dev/null @@ -1,113 +0,0 @@ -Some minor build fixes for sis-1.3.6 as it can be downloaded from -http://www-cad.eecs.berkeley.edu/~pchong/sis.html or -http://embedded.eecs.berkeley.edu/Alumni/pchong/sis.html - -diff --git a/sis/io/read_kiss.c b/sis/io/read_kiss.c -index 814e526..c862892 100644 ---- a/sis/io/read_kiss.c -+++ b/sis/io/read_kiss.c -@@ -10,7 +10,6 @@ - #ifdef SIS - #include "sis.h" - --extern void read_error(); - extern int read_lineno; - extern char *read_filename; - -diff --git a/sis/pld/act_bdd.c b/sis/pld/act_bdd.c -index 4fb4415..a5cd74c 100644 ---- a/sis/pld/act_bdd.c -+++ b/sis/pld/act_bdd.c -@@ -141,6 +141,8 @@ char *name; - return p_vertex; - } - -+static int compare(); -+ - /* Or 2 ACT's*/ - act_t * - my_or_act_F(array_b,cover, array) -@@ -148,7 +150,6 @@ array_t *array_b; - array_t *array; - sm_row *cover; - { -- static int compare(); - int i; - act_t *up_vertex, *down_vertex, *vertex; - sm_element *p; -diff --git a/sis/pld/act_ite.c b/sis/pld/act_ite.c -index a35f2fb..7b824df 100644 ---- a/sis/pld/act_ite.c -+++ b/sis/pld/act_ite.c -@@ -125,6 +125,8 @@ node_t *fanin; - and the minimum column cover variables in cover, generates an ite for the - original function. */ - -+static int compare(); -+ - ite_vertex * - my_or_ite_F(array_b, cover, array, network) - array_t *array_b; -@@ -132,7 +134,6 @@ array_t *array; - sm_row *cover; - network_t *network; - { -- static int compare(); - int i; - ite_vertex *vertex; - sm_element *p; -diff --git a/sis/pld/xln_merge.c b/sis/pld/xln_merge.c -index 075e6c5..16f4d61 100644 ---- a/sis/pld/xln_merge.c -+++ b/sis/pld/xln_merge.c -@@ -284,6 +284,7 @@ array_t *match1_array, *match2_array; - - } - -+static sm_row *xln_merge_find_neighbor_of_row1_with_minimum_neighbors(); - - /*---------------------------------------------------------------------------------------------------- - An alternate to lindo option. Uses greedy merging. A node with minimum mergeable nodes is picked -@@ -296,7 +297,6 @@ xln_merge_nodes_without_lindo(coeff, cand_node_array, match1_array, match2_array - { - node_t *n1, *n2; - sm_row *row1, *row2; -- static sm_row *xln_merge_find_neighbor_of_row1_with_minimum_neighbors(); - - while (TRUE) { - row1 = sm_shortest_row(coeff); -diff --git a/sis/pld/xln_part_dec.c b/sis/pld/xln_part_dec.c -index 1c856bd..b78828a 100644 ---- a/sis/pld/xln_part_dec.c -+++ b/sis/pld/xln_part_dec.c -@@ -49,13 +49,14 @@ int size; - - - -+static int kernel_value(); -+ - int - split_node(network, node, size) - network_t *network; - node_t *node; - int size; - { -- static int kernel_value(); - int i, value = 1; - kern_node *sorted; - divisor_t *div, *best_div; -diff --git a/xsis/Makefile.am b/xsis/Makefile.am -index 196d98b..686fdf4 100644 ---- a/xsis/Makefile.am -+++ b/xsis/Makefile.am -@@ -1,8 +1,8 @@ - xsis_SOURCES_local = NetPlot.c NetPlot.h NetPlotP.h main.c xastg.c \ - xblif.c xcmd.c xhelp.c xsis.c xsis.h xutil.c \ - blif50.px ghost.px help50.px sis50.px --AM_CPPFLAGS = -I../sis/include -I@SIS_X_INCLUDES@ --AM_LDFLAGS = -L@SIS_X_LIBRARIES@ -+AM_CPPFLAGS = -I../sis/include -+AM_LDFLAGS = - LDADD = ../sis/libsis.a -lXaw -lXmu -lXt -lXext -lX11 -lm - - if SIS_COND_X diff --git a/yosys/manual/CHAPTER_StateOfTheArt/synth.sh b/yosys/manual/CHAPTER_StateOfTheArt/synth.sh deleted file mode 100755 index 3a7524a29..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/synth.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash - -yosys_bin="/usr/local/synthesis/src/yosys/yosys" -hana_bin="/usr/local/synthesis/src/hana/bin/hana" -vl2mv_bin="/usr/local/synthesis/bin/vl2mv" -vis_bin="/usr/local/synthesis/bin/vis" -iverilog_bin="/usr/local/synthesis/bin/iverilog-0.8" -odin_bin="/usr/local/synthesis/src/vtr_release/ODIN_II/odin_II.exe" -abc_bin="/usr/local/synthesis/src/alanmi-abc-b5750272659f/abc" -edif2ngd="/opt/Xilinx/14.3/ISE_DS/ISE/bin/lin64/edif2ngd" -netgen="/opt/Xilinx/14.3/ISE_DS/ISE/bin/lin64/netgen" - -all_modes="yosys hana vis icarus odin" -all_sources="always01 always02 always03 arrays01 forgen01 forgen02" - -if [ "$*" == "ALL" ]; then - for mode in $all_modes; do - for src in $all_sources; do - echo "synth.sh $mode $src.v ${src}_${mode}.v" - ( set -x; bash synth.sh $mode $src.v ${src}_${mode}.v || rm -f ${src}_${mode}.v; ) > ${src}_${mode}.log 2>&1 - done - done - exit -fi - -mode="$1" -source="$2" -output="$3" -prefix="${output%.v}" - -help() { - echo "$0 ALL" >&2 - echo "$0 {yosys|hana|vis|icarus|odin} " >&2 - exit 1 -} - -if [ "$#" != 3 -o ! -f "$source" ]; then - help -fi - -set -ex - -case "$mode" in - yosys) - $yosys_bin -o $output -b "verilog -noattr" -p proc -p opt -p memory -p opt -p techmap -p opt $source ;; - hana) - $hana_bin -s $output $source ;; - vis) - $vl2mv_bin -o $prefix.mv $source - { echo "read_blif_mv $prefix.mv"; echo "write_verilog $output"; } | $abc_bin ;; - icarus) - rm -f $prefix.ngo $prefix.v - $iverilog_bin -t fpga -o $prefix.edif $source - $edif2ngd $prefix.edif $prefix.ngo - $netgen -ofmt verilog $prefix.ngo $prefix.v - sed -re '/timescale/ s,^,//,;' -i $prefix.v ;; - odin) - $odin_bin -o $prefix.blif -V $source - sed -re 's,top\^,,g; s,clock,_clock,g;' -i $prefix.blif - { echo "read_blif $prefix.blif"; echo "write_verilog $output"; } | $abc_bin ;; - *) - help -esac - diff --git a/yosys/manual/CHAPTER_StateOfTheArt/validate_tb.sh b/yosys/manual/CHAPTER_StateOfTheArt/validate_tb.sh deleted file mode 100755 index b6409eb14..000000000 --- a/yosys/manual/CHAPTER_StateOfTheArt/validate_tb.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -set -ex - -yosys_bin="/usr/local/synthesis/src/yosys/yosys" -iverilog_bin="iverilog" - -all_modes="yosys hana vis icarus odin" -all_sources="always01 always02 always03 arrays01 forgen01 forgen02" - -gcc -o cmp_tbdata cmp_tbdata.c - -for src in $all_sources; do - echo; echo - $yosys_bin -o ${src}_tb.v -b autotest ${src}.v - $iverilog_bin -o ${src}_tb ${src}_tb.v ${src}.v - ./${src}_tb > ${src}_tb.out - for mode in $all_modes; do - simlib="" - [ -f ${src}_${mode}.v ] || continue - [ -f simlib_${mode}.v ] && simlib="simlib_${mode}.v" - if $iverilog_bin -o ${src}_${mode}_tb -s testbench ${src}_tb.v ${src}_${mode}.v $simlib; then - ./${src}_${mode}_tb > ${src}_${mode}_tb.out - else - rm -f ${src}_${mode}_tb.out - fi - done -done - -set +x -echo; echo; echo - -{ - for mode in $all_modes; do - echo -en "\t$mode" - done; echo - - for src in $all_sources; do - echo -n "$src" - for mode in $all_modes; do - if [ -f ${src}_${mode}.v ]; then - if [ ! -s ${src}_${mode}_tb.out ]; then - echo -en "\tmissing" - elif ./cmp_tbdata ${src}_tb.out ${src}_${mode}_tb.out; then - echo -en "\tok" - else - echo -en "\tfailed" - fi - else - echo -en "\terror" - fi - done; echo - done -} | expand -t12 - diff --git a/yosys/manual/CHAPTER_Techmap.tex b/yosys/manual/CHAPTER_Techmap.tex deleted file mode 100644 index 13aa8e5a3..000000000 --- a/yosys/manual/CHAPTER_Techmap.tex +++ /dev/null @@ -1,102 +0,0 @@ - -\chapter{Technology Mapping} -\label{chapter:techmap} - -Previous chapters outlined how HDL code is transformed into an RTL netlist. The -RTL netlist is still based on abstract coarse-grain cell types like arbitrary -width adders and even multipliers. This chapter covers how an RTL netlist is -transformed into a functionally equivalent netlist utilizing the cell types -available in the target architecture. - -Technology mapping is often performed in two phases. In the first phase RTL cells -are mapped to an internal library of single-bit cells (see Sec.~\ref{sec:celllib_gates}). -In the second phase this netlist of internal gate types is transformed to a netlist -of gates from the target technology library. - -When the target architecture provides coarse-grain cells (such as block ram -or ALUs), these must be mapped to directly form the RTL netlist, as information -on the coarse-grain structure of the design is lost when it is mapped to -bit-width gate types. - -\section{Cell Substitution} - -The simplest form of technology mapping is cell substitution, as performed by -the {\tt techmap} pass. This pass, when provided with a Verilog file that -implements the RTL cell types using simpler cells, simply replaces the RTL -cells with the provided implementation. - -When no map file is provided, {\tt techmap} uses a built-in map file that -maps the Yosys RTL cell types to the internal gate library used by Yosys. -The curious reader may find this map file as {\tt techlibs/common/techmap.v} in -the Yosys source tree. - -Additional features have been added to {\tt techmap} to allow for conditional -mapping of cells (see {\tt help techmap} or Sec.~\ref{cmd:techmap}). This can -for example be useful if the target architecture supports hardware multipliers for -certain bit-widths but not for others. - -A usual synthesis flow would first use the {\tt techmap} pass to directly map -some RTL cells to coarse-grain cells provided by the target architecture (if -any) and then use techmap with the built-in default file to map the remaining -RTL cells to gate logic. - -\section{Subcircuit Substitution} - -Sometimes the target architecture provides cells that are more powerful than -the RTL cells used by Yosys. For example a cell in the target architecture that can -calculate the absolute-difference of two numbers does not match any single -RTL cell type but only combinations of cells. - -For these cases Yosys provides the {\tt extract} pass that can match a given set -of modules against a design and identify the portions of the design that are -identical (i.e.~isomorphic subcircuits) to any of the given modules. These -matched subcircuits are then replaced by instances of the given modules. - -The {\tt extract} pass also finds basic variations of the given modules, -such as swapped inputs on commutative cell types. - -In addition to this the {\tt extract} pass also has limited support for -frequent subcircuit mining, i.e.~the process of finding recurring subcircuits -in the design. This has a few applications, including the design of new -coarse-grain architectures \cite{intersynthFdlBookChapter}. - -The hard algorithmic work done by the {\tt extract} pass (solving the -isomorphic subcircuit problem and frequent subcircuit mining) is performed -using the SubCircuit library that can also be used stand-alone without Yosys -(see Sec.~\ref{sec:SubCircuit}). - -\section{Gate-Level Technology Mapping} -\label{sec:techmap_extern} - -On the gate-level the target architecture is usually described by a ``Liberty -file''. The Liberty file format is an industry standard format that can be -used to describe the behaviour and other properties of standard library cells -\citeweblink{LibertyFormat}. - -Mapping a design utilizing the Yosys internal gate library (e.g.~as a result -of mapping it to this representation using the {\tt techmap} pass) is -performed in two phases. - -First the register cells must be mapped to the registers that are available -on the target architectures. The target architecture might not provide all -variations of d-type flip-flops with positive and negative clock edge, -high-active and low-active asynchronous set and/or reset, etc. Therefore the -process of mapping the registers might add additional inverters to the design -and thus it is important to map the register cells first. - -Mapping of the register cells may be performed by using the {\tt dfflibmap} -pass. This pass expects a Liberty file as argument (using the {\tt -liberty} -option) and only uses the register cells from the Liberty file. - -Secondly the combinational logic must be mapped to the target architecture. -This is done using the external program ABC \citeweblink{ABC} via the -{\tt abc} pass by using the {\tt -liberty} option to the pass. Note that -in this case only the combinatorial cells are used from the cell library. - -Occasionally Liberty files contain trade secrets (such as sensitive timing -information) that cannot be shared freely. This complicates processes such as -reporting bugs in the tools involved. When the information in the Liberty file -used by Yosys and ABC are not part of the sensitive information, the additional -tool {\tt yosys-filterlib} (see Sec.~\ref{sec:filterlib}) can be used to strip -the sensitive information from the Liberty file. - diff --git a/yosys/manual/CHAPTER_Verilog.tex b/yosys/manual/CHAPTER_Verilog.tex deleted file mode 100644 index e9ca6114e..000000000 --- a/yosys/manual/CHAPTER_Verilog.tex +++ /dev/null @@ -1,849 +0,0 @@ - -\chapter{The Verilog and AST Frontends} -\label{chapter:verilog} - -This chapter provides an overview of the implementation of the Yosys Verilog -and AST frontends. The Verilog frontend reads Verilog-2005 code and creates -an abstract syntax tree (AST) representation of the input. This AST representation -is then passed to the AST frontend that converts it to RTLIL data, as illustrated -in Fig.~\ref{fig:Verilog_flow}. - -\begin{figure}[b!] - \hfil - \begin{tikzpicture} - \tikzstyle{process} = [draw, fill=green!10, rectangle, minimum height=3em, minimum width=10em, node distance=5em, font={\ttfamily}] - \tikzstyle{data} = [draw, fill=blue!10, ellipse, minimum height=3em, minimum width=7em, node distance=5em, font={\ttfamily}] - - \node[data] (n1) {Verilog Source}; - \node[process] (n2) [below of=n1] {Verilog Frontend}; - \node[data] (n3) [below of=n2] {AST}; - \node[process] (n4) [below of=n3] {AST Frontend}; - \node[data] (n5) [below of=n4] {RTLIL}; - - \draw[-latex] (n1) -- (n2); - \draw[-latex] (n2) -- (n3); - \draw[-latex] (n3) -- (n4); - \draw[-latex] (n4) -- (n5); - - \tikzstyle{details} = [draw, fill=yellow!5, rectangle, node distance=6cm, font={\ttfamily}] - - \node[details] (d1) [right of=n2] {\begin{minipage}{5cm} - \hfil - \begin{tikzpicture} - \tikzstyle{subproc} = [draw, fill=green!10, rectangle, minimum height=2em, minimum width=10em, node distance=3em, font={\ttfamily}] - \node (s0) {}; - \node[subproc] (s1) [below of=s0] {Preprocessor}; - \node[subproc] (s2) [below of=s1] {Lexer}; - \node[subproc] (s3) [below of=s2] {Parser}; - \node[node distance=3em] (s4) [below of=s3] {}; - \draw[-latex] (s0) -- (s1); - \draw[-latex] (s1) -- (s2); - \draw[-latex] (s2) -- (s3); - \draw[-latex] (s3) -- (s4); - \end{tikzpicture} - \end{minipage}}; - - \draw[dashed] (n2.north east) -- (d1.north west); - \draw[dashed] (n2.south east) -- (d1.south west); - - \node[details] (d2) [right of=n4] {\begin{minipage}{5cm} - \hfil - \begin{tikzpicture} - \tikzstyle{subproc} = [draw, fill=green!10, rectangle, minimum height=2em, minimum width=10em, node distance=3em, font={\ttfamily}] - \node (s0) {}; - \node[subproc] (s1) [below of=s0] {Simplifier}; - \node[subproc] (s2) [below of=s1] {RTLIL Generator}; - \node[node distance=3em] (s3) [below of=s2] {}; - \draw[-latex] (s0) -- (s1); - \draw[-latex] (s1) -- (s2); - \draw[-latex] (s2) -- (s3); - \end{tikzpicture} - \end{minipage}}; - - \draw[dashed] (n4.north east) -- (d2.north west); - \draw[dashed] (n4.south east) -- (d2.south west); - - \end{tikzpicture} - \caption{Simplified Verilog to RTLIL data flow} - \label{fig:Verilog_flow} -\end{figure} - - -\section{Transforming Verilog to AST} - -The {\it Verilog frontend} converts the Verilog sources to an internal AST representation that closely resembles -the structure of the original Verilog code. The Verilog frontend consists of three components, the -{\it Preprocessor}, the {\it Lexer} and the {\it Parser}. - -The source code to the Verilog frontend can be found in {\tt frontends/verilog/} in the Yosys source tree. - -\subsection{The Verilog Preprocessor} - -The Verilog preprocessor scans over the Verilog source code and interprets some of the Verilog compiler -directives such as \lstinline[language=Verilog]{`include}, \lstinline[language=Verilog]{`define} and -\lstinline[language=Verilog]{`ifdef}. - -It is implemented as a C++ function that is passed a file descriptor as input and returns the -pre-processed Verilog code as a \lstinline[language=C++]{std::string}. - -The source code to the Verilog Preprocessor can be found in {\tt -frontends/verilog/preproc.cc} in the Yosys source tree. - -\subsection{The Verilog Lexer} - -\begin{sloppypar} -The Verilog Lexer is written using the lexer generator {\it flex} \citeweblink{flex}. Its source code -can be found in {\tt frontends/verilog/lexer.l} in the Yosys source tree. -The lexer does little more than identifying all keywords and literals -recognised by the Yosys Verilog frontend. -\end{sloppypar} - -The lexer keeps track of the current location in the Verilog source code using -some global variables. These variables are used by the constructor of AST nodes -to annotate each node with the source code location it originated from. - -\begin{sloppypar} -Finally the lexer identifies and handles special comments such as -``\lstinline[language=Verilog]{// synopsys translate_off}'' and -``\lstinline[language=Verilog]{// synopsys full_case}''. (It is recommended to -use \lstinline[language=Verilog]{`ifdef} constructs instead of the Synsopsys -translate\_on/off comments and attributes such as -\lstinline[language=Verilog]{(* full_case *)} over ``\lstinline[language=Verilog]{// synopsys full_case}'' -whenever possible.) -\end{sloppypar} - -\subsection{The Verilog Parser} - -The Verilog Parser is written using the parser generator {\it bison} \citeweblink{bison}. Its source code -can be found in {\tt frontends/verilog/parser.y} in the Yosys source tree. - -It generates an AST using the \lstinline[language=C++]{AST::AstNode} data structure -defined in {\tt frontends/ast/ast.h}. An \lstinline[language=C++]{AST::AstNode} object has -the following properties: - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\begin{table}[b!] -\hfil -\begin{tabular}{>{\raggedright\arraybackslash}p{7cm}>{\raggedright\arraybackslash}p{8cm}} -AST Node Type & Corresponding Verilog Construct \\ -\hline -\hline -\arrayrulecolor{gray} -{\tt AST\_NONE} & This Node type should never be used. \\ -\hline -% -{\tt AST\_DESIGN} & This node type is used for the top node of the AST tree. It -has no corresponding Verilog construct. \\ -\hline -% -{\tt AST\_MODULE}, -{\tt AST\_TASK}, -{\tt AST\_FUNCTION} & -\lstinline[language=Verilog];module;, -\lstinline[language=Verilog];task; and -\lstinline[language=Verilog];function; \\ -\hline -% -{\tt AST\_WIRE} & -\lstinline[language=Verilog];input;, -\lstinline[language=Verilog];output;, -\lstinline[language=Verilog];wire;, -\lstinline[language=Verilog];reg; and -\lstinline[language=Verilog];integer; \\ -\hline -% -{\tt AST\_MEMORY} & -Verilog Arrays \\ -\hline -% -{\tt AST\_AUTOWIRE} & -Created by the simplifier when an undeclared signal name is used. \\ -\hline -% -{\tt AST\_PARAMETER}, -{\tt AST\_LOCALPARAM} & -\lstinline[language=Verilog];parameter; and -\lstinline[language=Verilog];localparam; \\ -\hline -% -{\tt AST\_PARASET} & -Parameter set in cell instantiation \\ -\hline -% -{\tt AST\_ARGUMENT} & -Port connection in cell instantiation \\ -\hline -% -{\tt AST\_RANGE} & -Bit-Index in a signal or element index in array \\ -\hline -% -{\tt AST\_CONSTANT} & -A literal value \\ -\hline -% -{\tt AST\_CELLTYPE} & -The type of cell in cell instantiation \\ -\hline -% -{\tt AST\_IDENTIFIER} & -An Identifier (signal name in expression or cell/task/etc. name in other contexts) \\ -\hline -% -{\tt AST\_PREFIX} & -Construct an identifier in the form {\tt [].} (used only in -advanced generate constructs) \\ -\hline -% -{\tt AST\_FCALL}, -{\tt AST\_TCALL} & -Call to function or task \\ -\hline -% -{\tt AST\_TO\_SIGNED}, -{\tt AST\_TO\_UNSIGNED} & -The \lstinline[language=Verilog];$signed(); and -\lstinline[language=Verilog];$unsigned(); functions \\ -\hline -\end{tabular} -\caption{AST node types with their corresponding Verilog constructs. \\ (continued on next page)} -\label{tab:Verilog_AstNodeType} -\end{table} - -\begin{table}[t!] -\ContinuedFloat -\hfil -\begin{tabular}{>{\raggedright\arraybackslash}p{7cm}>{\raggedright\arraybackslash}p{8cm}} -AST Node Type & Corresponding Verilog Construct \\ -\hline -\hline -\arrayrulecolor{gray} -{\tt AST\_CONCAT} -{\tt AST\_REPLICATE} & -The \lstinline[language=Verilog];{...}; and -\lstinline[language=Verilog];{...{...}}; operators \\ -\hline -% -{\tt AST\_BIT\_NOT}, -{\tt AST\_BIT\_AND}, -{\tt AST\_BIT\_OR}, -{\tt AST\_BIT\_XOR}, -{\tt AST\_BIT\_XNOR} & -The bitwise operators \break -\lstinline[language=Verilog];~;, -\lstinline[language=Verilog];&;, -\lstinline[language=Verilog];|;, -\lstinline[language=Verilog];^; and -\lstinline[language=Verilog];~^; \\ -\hline -% -{\tt AST\_REDUCE\_AND}, -{\tt AST\_REDUCE\_OR}, -{\tt AST\_REDUCE\_XOR}, -{\tt AST\_REDUCE\_XNOR} & -The unary reduction operators \break -\lstinline[language=Verilog];~;, -\lstinline[language=Verilog];&;, -\lstinline[language=Verilog];|;, -\lstinline[language=Verilog];^; and -\lstinline[language=Verilog];~^; \\ -\hline -% -{\tt AST\_REDUCE\_BOOL} & -Conversion from multi-bit value to boolean value -(equivalent to {\tt AST\_REDUCE\_OR}) \\ -\hline -% -{\tt AST\_SHIFT\_LEFT}, -{\tt AST\_SHIFT\_RIGHT}, -{\tt AST\_SHIFT\_SLEFT}, -{\tt AST\_SHIFT\_SRIGHT} & -The shift operators \break -\lstinline[language=Verilog];<<;, -\lstinline[language=Verilog];>>;, -\lstinline[language=Verilog];<<<; and -\lstinline[language=Verilog];>>>; \\ -\hline -% -{\tt AST\_LT}, -{\tt AST\_LE}, -{\tt AST\_EQ}, -{\tt AST\_NE}, -{\tt AST\_GE}, -{\tt AST\_GT} & -The relational operators \break -\lstinline[language=Verilog];<;, -\lstinline[language=Verilog];<=;, -\lstinline[language=Verilog];==;, -\lstinline[language=Verilog];!=;, -\lstinline[language=Verilog];>=; and -\lstinline[language=Verilog];>; \\ -\hline -% -{\tt AST\_ADD}, -{\tt AST\_SUB}, -{\tt AST\_MUL}, -{\tt AST\_DIV}, -{\tt AST\_MOD}, -{\tt AST\_POW} & -The binary operators \break -\lstinline[language=Verilog];+;, -\lstinline[language=Verilog];-;, -\lstinline[language=Verilog];*;, -\lstinline[language=Verilog];/;, -\lstinline[language=Verilog];%; and -\lstinline[language=Verilog];**; \\ -\hline -% -{\tt AST\_POS}, -{\tt AST\_NEG} & -The prefix operators -\lstinline[language=Verilog];+; and -\lstinline[language=Verilog];-; \\ -\hline -% -{\tt AST\_LOGIC\_AND}, -{\tt AST\_LOGIC\_OR}, -{\tt AST\_LOGIC\_NOT} & -The logic operators -\lstinline[language=Verilog];&&;, -\lstinline[language=Verilog];||; and -\lstinline[language=Verilog];!; \\ -\hline -% -{\tt AST\_TERNARY} & -The ternary \lstinline[language=Verilog];?:;-operator \\ -\hline -% -{\tt AST\_MEMRD} -{\tt AST\_MEMWR} & -Read and write memories. These nodes are generated by -the AST simplifier for writes/reads to/from Verilog arrays. \\ -\hline -% -{\tt AST\_ASSIGN} & -An \lstinline[language=Verilog];assign; statement \\ -\hline -% -{\tt AST\_CELL} & -A cell instantiation \\ -\hline -% -{\tt AST\_PRIMITIVE} & -A primitive cell (\lstinline[language=Verilog];and;, -\lstinline[language=Verilog];nand;, -\lstinline[language=Verilog];or;, etc.) \\ -\hline -% -{\tt AST\_ALWAYS}, -{\tt AST\_INITIAL} & -Verilog \lstinline[language=Verilog];always;- and \lstinline[language=Verilog];initial;-blocks \\ -\hline -% -{\tt AST\_BLOCK} & -A \lstinline[language=Verilog];begin;-\lstinline[language=Verilog];end;-block \\ -\hline -% -{\tt AST\_ASSIGN\_EQ}. -{\tt AST\_ASSIGN\_LE} & -Blocking (\lstinline[language=Verilog];=;) and nonblocking (\lstinline[language=Verilog];<=;) -assignments within an \lstinline[language=Verilog];always;- or \lstinline[language=Verilog];initial;-block \\ -\hline -% -{\tt AST\_CASE}. -{\tt AST\_COND}, -{\tt AST\_DEFAULT} & -The \lstinline[language=Verilog];case; (\lstinline[language=Verilog];if;) statements, conditions within a case -and the default case respectively \\ -\hline -% -{\tt AST\_FOR} & -A \lstinline[language=Verilog];for;-loop with an -\lstinline[language=Verilog];always;- or -\lstinline[language=Verilog];initial;-block \\ -\hline -% -{\tt AST\_GENVAR}, -{\tt AST\_GENBLOCK}, -{\tt AST\_GENFOR}, -{\tt AST\_GENIF} & -The \lstinline[language=Verilog];genvar; and -\lstinline[language=Verilog];generate; keywords and -\lstinline[language=Verilog];for; and \lstinline[language=Verilog];if; within a -generate block. \\ -\hline -% -{\tt AST\_POSEDGE}, -{\tt AST\_NEGEDGE}, -{\tt AST\_EDGE} & -Event conditions for \lstinline[language=Verilog];always; blocks. \\ -\hline -\end{tabular} -\caption{AST node types with their corresponding Verilog constructs. \\ (continuation from previous page)} -\label{tab:Verilog_AstNodeTypeCont} -\end{table} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\begin{itemize} -\item {\bf The node type} \\ -This enum (\lstinline[language=C++]{AST::AstNodeType}) specifies the role of the node. -Table~\ref{tab:Verilog_AstNodeType} contains a list of all node types. -\item {\bf The child nodes} \\ -This is a list of pointers to all children in the abstract syntax tree. -\item {\bf Attributes} \\ -As almost every AST node might have Verilog attributes assigned to it, the -\lstinline[language=C++]{AST::AstNode} has direct support for attributes. Note that the -attribute values are again AST nodes. -\item {\bf Node content} \\ -Each node might have additional content data. A series of member variables exist to hold such data. -For example the member \lstinline[language=C++]{std::string str} can hold a string value and is -used e.g.~in the {\tt AST\_IDENTIFIER} node type to store the identifier name. -\item {\bf Source code location} \\ -Each \lstinline[language=C++]{AST::AstNode} is automatically annotated with the current -source code location by the \lstinline[language=C++]{AST::AstNode} constructor. It is -stored in the \lstinline[language=C++]{std::string filename} and \lstinline[language=C++]{int linenum} -member variables. -\end{itemize} - -The \lstinline[language=C++]{AST::AstNode} constructor can be called with up to -two child nodes that are automatically added to the list of child nodes for the new object. -This simplifies the creation of AST nodes for simple expressions a bit. For example the bison -code for parsing multiplications: - -\begin{lstlisting}[numbers=left,frame=single] - basic_expr '*' attr basic_expr { - $$ = new AstNode(AST_MUL, $1, $4); - append_attr($$, $3); - } | -\end{lstlisting} - -The generated AST data structure is then passed directly to the AST frontend -that performs the actual conversion to RTLIL. - -Note that the Yosys command {\tt read\_verilog} provides the options {\tt -yydebug} -and {\tt -dump\_ast} that can be used to print the parse tree or abstract syntax tree -respectively. - -\section{Transforming AST to RTLIL} - -The {\it AST Frontend} converts a set of modules in AST representation to -modules in RTLIL representation and adds them to the current design. This is done -in two steps: {\it simplification} and {\it RTLIL generation}. - -The source code to the AST frontend can be found in {\tt frontends/ast/} in the Yosys source tree. - -\subsection{AST Simplification} - -A full-featured AST is too complex to be transformed into RTLIL directly. Therefore it must -first be brought into a simpler form. This is done by calling the \lstinline[language=C++]{AST::AstNode::simplify()} -method of all {\tt AST\_MODULE} nodes in the AST. This initiates a recursive process that performs the following transformations -on the AST data structure: - -\begin{itemize} -\item Inline all task and function calls. -\item Evaluate all \lstinline[language=Verilog]{generate}-statements and unroll all \lstinline[language=Verilog]{for}-loops. -\item Perform const folding where it is necessary (e.g.~in the value part of {\tt AST\_PARAMETER}, {\tt AST\_LOCALPARAM}, -{\tt AST\_PARASET} and {\tt AST\_RANGE} nodes). -\item Replace {\tt AST\_PRIMITIVE} nodes with appropriate {\tt AST\_ASSIGN} nodes. -\item Replace dynamic bit ranges in the left-hand-side of assignments with {\tt AST\_CASE} nodes with {\tt AST\_COND} children -for each possible case. -\item Detect array access patterns that are too complicated for the {\tt RTLIL::Memory} abstraction and replace them -with a set of signals and cases for all reads and/or writes. -\item Otherwise replace array accesses with {\tt AST\_MEMRD} and {\tt AST\_MEMWR} nodes. -\end{itemize} - -In addition to these transformations, the simplifier also annotates the AST with additional information that is needed -for the RTLIL generator, namely: - -\begin{itemize} -\item All ranges (width of signals and bit selections) are not only const folded but (when a constant value -is found) are also written to member variables in the {\tt AST\_RANGE} node. -\item All identifiers are resolved and all {\tt AST\_IDENTIFIER} nodes are annotated with a pointer to the AST node -that contains the declaration of the identifier. If no declaration has been found, an {\tt AST\_AUTOWIRE} node -is created and used for the annotation. -\end{itemize} - -This produces an AST that is fairly easy to convert to the RTLIL format. - -\subsection{Generating RTLIL} - -After AST simplification, the \lstinline[language=C++]{AST::AstNode::genRTLIL()} method of each {\tt AST\_MODULE} node -in the AST is called. This initiates a recursive process that generates equivalent RTLIL data for the AST data. - -The \lstinline[language=C++]{AST::AstNode::genRTLIL()} method returns an \lstinline[language=C++]{RTLIL::SigSpec} structure. -For nodes that represent expressions (operators, constants, signals, etc.), the cells needed to implement the calculation -described by the expression are created and the resulting signal is returned. That way it is easy to generate the circuits -for large expressions using depth-first recursion. For nodes that do not represent an expression (such as {\tt -AST\_CELL}), the corresponding circuit is generated and an empty \lstinline[language=C++]{RTLIL::SigSpec} is returned. - -\section{Synthesizing Verilog always Blocks} - -For behavioural Verilog code (code utilizing \lstinline[language=Verilog]{always}- and -\lstinline[language=Verilog]{initial}-blocks) it is necessary to also generate \lstinline[language=C++]{RTLIL::Process} -objects. This is done in the following way: - -\begin{itemize} -\item Whenever \lstinline[language=C++]{AST::AstNode::genRTLIL()} encounters an \lstinline[language=Verilog]{always}- -or \lstinline[language=Verilog]{initial}-block, it creates an instance of -\lstinline[language=Verilog]{AST_INTERNAL::ProcessGenerator}. This object then generates the -\lstinline[language=C++]{RTLIL::Process} object for the block. It also calls \lstinline[language=C++]{AST::AstNode::genRTLIL()} -for all right-hand-side expressions contained within the block. -% -\begin{sloppypar} -\item First the \lstinline[language=Verilog]{AST_INTERNAL::ProcessGenerator} creates a list of all signals assigned -within the block. It then creates a set of temporary signals using the naming scheme {\tt \$\it\tt -\textbackslash\it } for each of the assigned signals. -\end{sloppypar} -% -\item Then an \lstinline[language=C++]{RTLIL::Process} is created that assigns all intermediate values for each left-hand-side -signal to the temporary signal in its \lstinline[language=C++]{RTLIL::CaseRule}/\lstinline[language=C++]{RTLIL::SwitchRule} tree. -% -\item Finally a \lstinline[language=C++]{RTLIL::SyncRule} is created for the \lstinline[language=C++]{RTLIL::Process} that -assigns the temporary signals for the final values to the actual signals. -% -\item Calls to \lstinline[language=C++]{AST::AstNode::genRTLIL()} are generated for right hand sides as needed. When blocking -assignments are used, \lstinline[language=C++]{AST::AstNode::genRTLIL()} is configured using global variables to use -the temporary signals that hold the correct intermediate values whenever one of the previously assigned signals is used -in an expression. -\end{itemize} - -Unfortunately the generation of a correct \lstinline[language=C++]{RTLIL::CaseRule}/\lstinline[language=C++]{RTLIL::SwitchRule} -tree for behavioural code is a non-trivial task. The AST frontend solves the problem using the approach described on the following -pages. The following example illustrates what the algorithm is supposed to do. Consider the following Verilog code: - -\begin{lstlisting}[numbers=left,frame=single,language=Verilog] -always @(posedge clock) begin - out1 = in1; - if (in2) - out1 = !out1; - out2 <= out1; - if (in3) - out2 <= out2; - if (in4) - if (in5) - out3 <= in6; - else - out3 <= in7; - out1 = out1 ^ out2; -end -\end{lstlisting} - -This is translated by the Verilog and AST frontends into the following RTLIL code (attributes, cell parameters -and wire declarations not included): - -\begin{lstlisting}[numbers=left,frame=single,language=rtlil] -cell $logic_not $logic_not$:4$2 - connect \A \in1 - connect \Y $logic_not$:4$2_Y -end -cell $xor $xor$:13$3 - connect \A $1\out1[0:0] - connect \B \out2 - connect \Y $xor$:13$3_Y -end -process $proc$:1$1 - assign $0\out3[0:0] \out3 - assign $0\out2[0:0] $1\out1[0:0] - assign $0\out1[0:0] $xor$:13$3_Y - switch \in2 - case 1'1 - assign $1\out1[0:0] $logic_not$:4$2_Y - case - assign $1\out1[0:0] \in1 - end - switch \in3 - case 1'1 - assign $0\out2[0:0] \out2 - case - end - switch \in4 - case 1'1 - switch \in5 - case 1'1 - assign $0\out3[0:0] \in6 - case - assign $0\out3[0:0] \in7 - end - case - end - sync posedge \clock - update \out1 $0\out1[0:0] - update \out2 $0\out2[0:0] - update \out3 $0\out3[0:0] -end -\end{lstlisting} - -Note that the two operators are translated into separate cells outside the generated process. The signal -\lstinline[language=Verilog]{out1} is assigned using blocking assignments and therefore \lstinline[language=Verilog]{out1} -has been replaced with a different signal in all expressions after the initial assignment. The signal -\lstinline[language=Verilog]{out2} is assigned using nonblocking assignments and therefore is not substituted -on the right-hand-side expressions. - -The \lstinline[language=C++]{RTLIL::CaseRule}/\lstinline[language=C++]{RTLIL::SwitchRule} -tree must be interpreted the following way: - -\begin{itemize} -\item On each case level (the body of the process is the {\it root case}), first the actions on this level are -evaluated and then the switches within the case are evaluated. (Note that the last assignment on line 13 of the -Verilog code has been moved to the beginning of the RTLIL process to line 13 of the RTLIL listing.) - -I.e.~the special cases deeper in the switch hierarchy override the defaults on the upper levels. The assignments -in lines 12 and 22 of the RTLIL code serve as an example for this. - -Note that in contrast to this, the order within the \lstinline[language=C++]{RTLIL::SwitchRule} objects -within a \lstinline[language=C++]{RTLIL::CaseRule} is preserved with respect to the original AST and -Verilog code. -% -\item \begin{sloppypar} -The whole \lstinline[language=C++]{RTLIL::CaseRule}/\lstinline[language=C++]{RTLIL::SwitchRule} tree -describes an asynchronous circuit. I.e.~the decision tree formed by the switches can be seen independently for -each assigned signal. Whenever one assigned signal changes, all signals that depend on the changed signals -are to be updated. For example the assignments in lines 16 and 18 in the RTLIL code in fact influence the assignment -in line 12, even though they are in the ``wrong order''. -\end{sloppypar} -\end{itemize} - -The only synchronous part of the process is in the \lstinline[language=C++]{RTLIL::SyncRule} object generated at line -35 in the RTLIL code. The sync rule is the only part of the process where the original signals are assigned. The -synchronization event from the original Verilog code has been translated into the synchronization type ({\tt posedge}) -and signal ({\tt \textbackslash clock}) for the \lstinline[language=C++]{RTLIL::SyncRule} object. In the case of -this simple example the \lstinline[language=C++]{RTLIL::SyncRule} object is later simply transformed into a set of -d-type flip-flops and the \lstinline[language=C++]{RTLIL::CaseRule}/\lstinline[language=C++]{RTLIL::SwitchRule} tree -to a decision tree using multiplexers. - -\begin{sloppypar} -In more complex examples (e.g.~asynchronous resets) the part of the -\lstinline[language=C++]{RTLIL::CaseRule}/\lstinline[language=C++]{RTLIL::SwitchRule} -tree that describes the asynchronous reset must first be transformed to the -correct \lstinline[language=C++]{RTLIL::SyncRule} objects. This is done by the {\tt proc\_adff} pass. -\end{sloppypar} - -\subsection{The ProcessGenerator Algorithm} - -The \lstinline[language=C++]{AST_INTERNAL::ProcessGenerator} uses the following internal state variables: - -\begin{itemize} -\item \begin{sloppypar} -\lstinline[language=C++]{subst_rvalue_from} and \lstinline[language=C++]{subst_rvalue_to} \\ -These two variables hold the replacement pattern that should be used by \lstinline[language=C++]{AST::AstNode::genRTLIL()} -for signals with blocking assignments. After initialization of \lstinline[language=C++]{AST_INTERNAL::ProcessGenerator} -these two variables are empty. -\end{sloppypar} -% -\item \lstinline[language=C++]{subst_lvalue_from} and \lstinline[language=C++]{subst_lvalue_to} \\ -These two variables contain the mapping from left-hand-side signals ({\tt \textbackslash \it }) to the current -temporary signal for the same thing (initially {\tt \$0\textbackslash \it }). -% -\item \lstinline[language=C++]{current_case} \\ -A pointer to a \lstinline[language=C++]{RTLIL::CaseRule} object. Initially this is the root case of the -generated \lstinline[language=C++]{RTLIL::Process}. -\end{itemize} - -As the algorithm runs these variables are continuously modified as well as pushed -to the stack and later restored to their earlier values by popping from the stack. - -On startup the ProcessGenerator generates a new -\lstinline[language=C++]{RTLIL::Process} object with an empty root case and -initializes its state variables as described above. Then the \lstinline[language=C++]{RTLIL::SyncRule} objects -are created using the synchronization events from the {\tt AST\_ALWAYS} node and the initial values of -\lstinline[language=C++]{subst_lvalue_from} and \lstinline[language=C++]{subst_lvalue_to}. Then the -AST for this process is evaluated recursively. - -During this recursive evaluation, three different relevant types of AST nodes can be discovered: -{\tt AST\_ASSIGN\_LE} (nonblocking assignments), {\tt AST\_ASSIGN\_EQ} (blocking assignments) and -{\tt AST\_CASE} (\lstinline[language=Verilog]{if} or \lstinline[language=Verilog]{case} statement). - -\subsubsection{Handling of Nonblocking Assignments} - -When an {\tt AST\_ASSIGN\_LE} node is discovered, the following actions are performed by the -ProcessGenerator: - -\begin{itemize} -\item The left-hand-side is evaluated using \lstinline[language=C++]{AST::AstNode::genRTLIL()} and mapped to -a temporary signal name using \lstinline[language=C++]{subst_lvalue_from} and \lstinline[language=C++]{subst_lvalue_to}. -% -\item The right-hand-side is evaluated using \lstinline[language=C++]{AST::AstNode::genRTLIL()}. For this call, -the values of \lstinline[language=C++]{subst_rvalue_from} and \lstinline[language=C++]{subst_rvalue_to} are used to -map blocking-assigned signals correctly. -% -\item Remove all assignments to the same left-hand-side as this assignment from the \lstinline[language=C++]{current_case} -and all cases within it. -% -\item Add the new assignment to the \lstinline[language=C++]{current_case}. -\end{itemize} - -\subsubsection{Handling of Blocking Assignments} - -When an {\tt AST\_ASSIGN\_EQ} node is discovered, the following actions are performed by -the ProcessGenerator: - -\begin{itemize} -\item Perform all the steps that would be performed for a nonblocking assignment (see above). -% -\item Remove the found left-hand-side (before lvalue mapping) from -\lstinline[language=C++]{subst_rvalue_from} and also remove the respective -bits from \lstinline[language=C++]{subst_rvalue_to}. -% -\item Append the found left-hand-side (before lvalue mapping) to \lstinline[language=C++]{subst_rvalue_from} -and append the found right-hand-side to \lstinline[language=C++]{subst_rvalue_to}. -\end{itemize} - -\subsubsection{Handling of Cases and if-Statements} - -\begin{sloppypar} -When an {\tt AST\_CASE} node is discovered, the following actions are performed by -the ProcessGenerator: - -\begin{itemize} -\item The values of \lstinline[language=C++]{subst_rvalue_from}, \lstinline[language=C++]{subst_rvalue_to}, -\lstinline[language=C++]{subst_lvalue_from} and \lstinline[language=C++]{subst_lvalue_to} are pushed to the stack. -% -\item A new \lstinline[language=C++]{RTLIL::SwitchRule} object is generated, the selection expression is evaluated using -\lstinline[language=C++]{AST::AstNode::genRTLIL()} (with the use of \lstinline[language=C++]{subst_rvalue_from} and -\lstinline[language=C++]{subst_rvalue_to}) and added to the \lstinline[language=C++]{RTLIL::SwitchRule} object and the -object is added to the \lstinline[language=C++]{current_case}. -% -\item All lvalues assigned to within the {\tt AST\_CASE} node using blocking assignments are collected and -saved in the local variable \lstinline[language=C++]{this_case_eq_lvalue}. -% -\item New temporary signals are generated for all signals in \lstinline[language=C++]{this_case_eq_lvalue} and stored -in \lstinline[language=C++]{this_case_eq_ltemp}. -% -\item The signals in \lstinline[language=C++]{this_case_eq_lvalue} are mapped using \lstinline[language=C++]{subst_rvalue_from} -and \lstinline[language=C++]{subst_rvalue_to} and the resulting set of signals is stored in -\lstinline[language=C++]{this_case_eq_rvalue}. -\end{itemize} - -Then the following steps are performed for each {\tt AST\_COND} node within the {\tt AST\_CASE} node: - -\begin{itemize} -\item Set \lstinline[language=C++]{subst_rvalue_from}, \lstinline[language=C++]{subst_rvalue_to}, -\lstinline[language=C++]{subst_lvalue_from} and \lstinline[language=C++]{subst_lvalue_to} to the values -that have been pushed to the stack. -% -\item Remove \lstinline[language=C++]{this_case_eq_lvalue} from -\lstinline[language=C++]{subst_lvalue_from}/\lstinline[language=C++]{subst_lvalue_to}. -% -\item Append \lstinline[language=C++]{this_case_eq_lvalue} to \lstinline[language=C++]{subst_lvalue_from} and append -\lstinline[language=C++]{this_case_eq_ltemp} to \lstinline[language=C++]{subst_lvalue_to}. -% -\item Push the value of \lstinline[language=C++]{current_case}. -% -\item Create a new \lstinline[language=C++]{RTLIL::CaseRule}. Set \lstinline[language=C++]{current_case} to the -new object and add the new object to the \lstinline[language=C++]{RTLIL::SwitchRule} created above. -% -\item Add an assignment from \lstinline[language=C++]{this_case_eq_rvalue} to \lstinline[language=C++]{this_case_eq_ltemp} -to the new \lstinline[language=C++]{current_case}. -% -\item Evaluate the compare value for this case using \lstinline[language=C++]{AST::AstNode::genRTLIL()} (with the use of -\lstinline[language=C++]{subst_rvalue_from} and \lstinline[language=C++]{subst_rvalue_to}) modify the new -\lstinline[language=C++]{current_case} accordingly. -% -\item Recursion into the children of the {\tt AST\_COND} node. -% -\item Restore \lstinline[language=C++]{current_case} by popping the old value from the stack. -\end{itemize} - -Finally the following steps are performed: - -\begin{itemize} -\item The values of \lstinline[language=C++]{subst_rvalue_from}, \lstinline[language=C++]{subst_rvalue_to}, -\lstinline[language=C++]{subst_lvalue_from} and \lstinline[language=C++]{subst_lvalue_to} are popped from the stack. -% -\item The signals from \lstinline[language=C++]{this_case_eq_lvalue} are removed from the -\lstinline[language=C++]{subst_rvalue_from}/\lstinline[language=C++]{subst_rvalue_to}-pair. -% -\item The value of \lstinline[language=C++]{this_case_eq_lvalue} is appended to \lstinline[language=C++]{subst_rvalue_from} -and the value of \lstinline[language=C++]{this_case_eq_ltemp} is appended to \lstinline[language=C++]{subst_rvalue_to}. -% -\item Map the signals in \lstinline[language=C++]{this_case_eq_lvalue} using -\lstinline[language=C++]{subst_lvalue_from}/\lstinline[language=C++]{subst_lvalue_to}. -% -\item Remove all assignments to signals in \lstinline[language=C++]{this_case_eq_lvalue} in \lstinline[language=C++]{current_case} -and all cases within it. -% -\item Add an assignment from \lstinline[language=C++]{this_case_eq_ltemp} to \lstinline[language=C++]{this_case_eq_lvalue} -to \lstinline[language=C++]{current_case}. -\end{itemize} -\end{sloppypar} - -\subsubsection{Further Analysis of the Algorithm for Cases and if-Statements} - -With respect to nonblocking assignments the algorithm is easy: later assignments invalidate earlier assignments. -For each signal assigned using nonblocking assignments exactly one temporary variable is generated (with the -{\tt \$0}-prefix) and this variable is used for all assignments of the variable. - -Note how all the \lstinline[language=C++]{_eq_}-variables become empty when no blocking assignments are used -and many of the steps in the algorithm can then be ignored as a result of this. - -For a variable with blocking assignments the algorithm shows the following behaviour: First a new temporary variable -is created. This new temporary variable is then registered as the assignment target for all assignments for this -variable within the cases for this {\tt AST\_CASE} node. Then for each case the new temporary variable is first -assigned the old temporary variable. This assignment is overwritten if the variable is actually assigned in this -case and is kept as a default value otherwise. - -This yields an \lstinline[language=C++]{RTLIL::CaseRule} that assigns the new temporary variable in all branches. -So when all cases have been processed a final assignment is added to the containing block that assigns the new -temporary variable to the old one. Note how this step always overrides a previous assignment to the old temporary -variable. Other than nonblocking assignments, the old assignment could still have an effect somewhere -in the design, as there have been calls to \lstinline[language=C++]{AST::AstNode::genRTLIL()} with a -\lstinline[language=C++]{subst_rvalue_from}/\lstinline[language=C++]{subst_rvalue_to}-tuple that contained -the right-hand-side of the old assignment. - -\subsection{The proc pass} - -The ProcessGenerator converts a behavioural model in AST representation to a behavioural model in -\lstinline[language=C++]{RTLIL::Process} representation. The actual conversion from a behavioural -model to an RTL representation is performed by the {\tt proc} pass and the passes it launches: - -\begin{itemize} -\item {\tt proc\_clean} and {\tt proc\_rmdead} \\ -These two passes just clean up the \lstinline[language=C++]{RTLIL::Process} structure. The {\tt proc\_clean} -pass removes empty parts (eg. empty assignments) from the process and {\tt proc\_rmdead} detects and removes -unreachable branches from the process's decision trees. -% -\item {\tt proc\_arst} \\ -This pass detects processes that describe d-type flip-flops with asynchronous -resets and rewrites the process to better reflect what they are modelling: -Before this pass, an asynchronous reset has two edge-sensitive sync rules and -one top-level \C{RTLIL::SwitchRule} for the reset path. After this pass the -sync rule for the reset is level-sensitive and the top-level -\C{RTLIL::SwitchRule} has been removed. -% -\item {\tt proc\_mux} \\ -This pass converts the \C{RTLIL::CaseRule}/\C{RTLIL::SwitchRule}-tree to a tree -of multiplexers per written signal. After this, the \C{RTLIL::Process} structure only contains -the \C{RTLIL::SyncRule}s that describe the output registers. -% -\item {\tt proc\_dff} \\ -This pass replaces the \C{RTLIL::SyncRule}s to d-type flip-flops (with -asynchronous resets if necessary). -% -\item {\tt proc\_clean} \\ -A final call to {\tt proc\_clean} removes the now empty \C{RTLIL::Process} objects. -\end{itemize} - -Performing these last processing steps in passes instead of in the Verilog frontend has two important benefits: - -First it improves the transparency of the process. Everything that happens in a separate pass is easier to debug, -as the RTLIL data structures can be easily investigated before and after each of the steps. - -Second it improves flexibility. This scheme can easily be extended to support other types of storage-elements, such -as sr-latches or d-latches, without having to extend the actual Verilog frontend. - -\section{Synthesizing Verilog Arrays} - -\begin{fixme} -Add some information on the generation of {\tt \$memrd} and {\tt \$memwr} cells -and how they are processed in the {\tt memory} pass. -\end{fixme} - -\section{Synthesizing Parametric Designs} - -\begin{fixme} -Add some information on the \lstinline[language=C++]{RTLIL::Module::derive()} method and how it -is used to synthesize parametric modules via the {\tt hierarchy} pass. -\end{fixme} - diff --git a/yosys/manual/PRESENTATION_ExAdv.tex b/yosys/manual/PRESENTATION_ExAdv.tex deleted file mode 100644 index ef8f64cec..000000000 --- a/yosys/manual/PRESENTATION_ExAdv.tex +++ /dev/null @@ -1,896 +0,0 @@ - -\section{Yosys by example -- Advanced Synthesis} - -\begin{frame} -\sectionpage -\end{frame} - -\begin{frame}{Overview} -This section contains 4 subsections: -\begin{itemize} -\item Using selections -\item Advanced uses of techmap -\item Coarse-grain synthesis -\item Automatic design changes -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Using selections} - -\begin{frame} -\subsectionpage -\subsectionpagesuffix -\end{frame} - -\subsubsection{Simple selections} - -\begin{frame}[fragile]{\subsubsecname} -Most Yosys commands make use of the ``selection framework'' of Yosys. It can be used -to apply commands only to part of the design. For example: - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -delete # will delete the whole design, but - -delete foobar # will only delete the module foobar. -\end{lstlisting} - -\bigskip -The {\tt select} command can be used to create a selection for subsequent -commands. For example: - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -select foobar # select the module foobar -delete # delete selected objects -select -clear # reset selection (select whole design) -\end{lstlisting} -\end{frame} - -\subsubsection{Selection by object name} - -\begin{frame}[fragile]{\subsubsecname} -The easiest way to select objects is by object name. This is usually only done -in synthesis scripts that are hand-tailored for a specific design. - -\bigskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -select foobar # select module foobar -select foo* # select all modules whose names start with foo -select foo*/bar* # select all objects matching bar* from modules matching foo* -select */clk # select objects named clk from all modules -\end{lstlisting} -\end{frame} - -\subsubsection{Module and design context} - -\begin{frame}[fragile]{\subsubsecname} -Commands can be executed in {\it module\/} or {\it design\/} context. Until now all -commands have been executed in design context. The {\tt cd} command can be used -to switch to module context. - -\bigskip -In module context all commands only effect the active module. Objects in the module -are selected without the {\tt /} prefix. For example: - -\bigskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -cd foo # switch to module foo -delete bar # delete object foo/bar - -cd mycpu # switch to module mycpu -dump reg_* # print details on all objects whose names start with reg_ - -cd .. # switch back to design -\end{lstlisting} - -\bigskip -Note: Most synthesis scripts never switch to module context. But it is a very powerful -tool for interactive design investigation. -\end{frame} - -\subsubsection{Selecting by object property or type} - -\begin{frame}[fragile]{\subsubsecname} -Special patterns can be used to select by object property or type. For example: - -\bigskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -select w:reg_* # select all wires whose names start with reg_ -select a:foobar # select all objects with the attribute foobar set -select a:foobar=42 # select all objects with the attribute foobar set to 42 -select A:blabla # select all modules with the attribute blabla set -select foo/t:$add # select all $add cells from the module foo -\end{lstlisting} - -\bigskip -A complete list of this pattern expressions can be found in the command -reference to the {\tt select} command. -\end{frame} - -\subsubsection{Combining selection} - -\begin{frame}[fragile]{\subsubsecname} -When more than one selection expression is used in one statement, then they are -pushed on a stack. The final elements on the stack are combined into a union: - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -select t:$dff r:WIDTH>1 # all cells of type $dff and/or with a parameter WIDTH > 1 -\end{lstlisting} - -\bigskip -Special \%-commands can be used to combine the elements on the stack: - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -select t:$dff r:WIDTH>1 %i # all cells of type $dff *AND* with a parameter WIDTH > 1 -\end{lstlisting} - -\medskip -\begin{block}{Examples for {\tt \%}-codes (see {\tt help select} for full list)} -{\tt \%u} \dotfill union of top two elements on stack -- pop 2, push 1 \\ -{\tt \%d} \dotfill difference of top two elements on stack -- pop 2, push 1 \\ -{\tt \%i} \dotfill intersection of top two elements on stack -- pop 2, push 1 \\ -{\tt \%n} \dotfill inverse of top element on stack -- pop 1, push 1 \\ -\end{block} -\end{frame} - -\subsubsection{Expanding selections} - -\begin{frame}[fragile]{\subsubsecname} -Selections of cells and wires can be expanded along connections using {\tt \%}-codes -for selecting input cones ({\tt \%ci}), output cones ({\tt \%co}), or both ({\tt \%x}). - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -# select all wires that are inputs to $add cells -select t:$add %ci w:* %i -\end{lstlisting} - -\bigskip -Additional constraints such as port names can be specified. - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -# select all wires that connect a "Q" output with a "D" input -select c:* %co:+[Q] w:* %i c:* %ci:+[D] w:* %i %i - -# select the multiplexer tree that drives the signal 'state' -select state %ci*:+$mux,$pmux[A,B,Y] -\end{lstlisting} - -\bigskip -See {\tt help select} for full documentation of this expressions. -\end{frame} - -\subsubsection{Incremental selection} - -\begin{frame}[fragile]{\subsubsecname} -Sometimes a selection can most easily be described by a series of add/delete operations. -The commands {\tt select -add} and {\tt select -del} respectively add or remove objects -from the current selection instead of overwriting it. - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -select -none # start with an empty selection -select -add reg_* # select a bunch of objects -select -del reg_42 # but not this one -select -add state %ci # and add mor stuff -\end{lstlisting} - -\bigskip -Within a select expression the token {\tt \%} can be used to push the previous selection -on the stack. - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -select t:$add t:$sub # select all $add and $sub cells -select % %ci % %d # select only the input wires to those cells -\end{lstlisting} -\end{frame} - -\subsubsection{Creating selection variables} - -\begin{frame}[fragile]{\subsubsecname} -Selections can be stored under a name with the {\tt select -set } -command. The stored selections can be used in later select expressions -using the syntax {\tt @}. - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -select -set cone_a state_a %ci*:-$dff # set @cone_a to the input cone of state_a -select -set cone_b state_b %ci*:-$dff # set @cone_b to the input cone of state_b -select @cone_a @cone_b %i # select the objects that are in both cones -\end{lstlisting} - -\bigskip -Remember that select expressions can also be used directly as arguments to most -commands. Some commands also except a single select argument to some options. -In those cases selection variables must be used to capture more complex selections. - -\medskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -dump @cone_a @cone_b - -select -set cone_ab @cone_a @cone_b %i -show -color red @cone_ab -color magenta @cone_a -color blue @cone_b -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile]{\subsubsecname{} -- Example} -\begin{columns} -\column[t]{4cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/select.v} -\column[t]{7cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExAdv/select.ys} -\end{columns} -\hfil\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/select.pdf} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Advanced uses of techmap} - -\begin{frame} -\subsectionpage -\subsectionpagesuffix -\end{frame} - -\subsubsection{Introduction to techmap} - -\begin{frame}{\subsubsecname} -\begin{itemize} -\item -The {\tt techmap} command replaces cells in the design with implementations given -as Verilog code (called ``map files''). It can replace Yosys' internal cell -types (such as {\tt \$or}) as well as user-defined cell types. -\medskip\item -Verilog parameters are used extensively to customize the internal cell types. -\medskip\item -Additional special parameters are used by techmap to communicate meta-data to the -map files. -\medskip\item -Special wires are used to instruct techmap how to handle a module in the map file. -\medskip\item -Generate blocks and recursion are powerful tools for writing map files. -\end{itemize} -\end{frame} - -\begin{frame}[t]{\subsubsecname{} -- Example 1/2} -\vskip-0.2cm -To map the Verilog OR-reduction operator to 3-input OR gates: -\vskip-0.2cm -\begin{columns} -\column[t]{0.35\linewidth} -\lstinputlisting[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, lastline=24]{PRESENTATION_ExAdv/red_or3x1_map.v} -\column[t]{0.65\linewidth} -\lstinputlisting[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=25]{PRESENTATION_ExAdv/red_or3x1_map.v} -\end{columns} -\end{frame} - -\begin{frame}[t]{\subsubsecname{} -- Example 2/2} -\vbox to 0cm{ -\hfil\includegraphics[width=10cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/red_or3x1.pdf} -\vss -} -\begin{columns} -\column[t]{6cm} -\column[t]{4cm} -\vskip-0.6cm\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, firstline=4, lastline=4, frame=single]{PRESENTATION_ExAdv/red_or3x1_test.ys} -\vskip-0.2cm\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/red_or3x1_test.v} -\end{columns} -\end{frame} - -\subsubsection{Conditional techmap} - -\begin{frame}{\subsubsecname} -\begin{itemize} -\item In some cases only cells with certain properties should be substituted. -\medskip -\item The special wire {\tt \_TECHMAP\_FAIL\_} can be used to disable a module -in the map file for a certain set of parameters. -\medskip -\item The wire {\tt \_TECHMAP\_FAIL\_} must be set to a constant value. If it -is non-zero then the module is disabled for this set of parameters. -\medskip -\item Example use-cases: -\begin{itemize} -\item coarse-grain cell types that only operate on certain bit widths -\item memory resources for different memory geometries (width, depth, ports, etc.) -\end{itemize} -\end{itemize} -\end{frame} - -\begin{frame}[t]{\subsubsecname{} -- Example} -\vbox to 0cm{ -\vskip-0.5cm -\hfill\includegraphics[width=6cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/sym_mul.pdf} -\vss -} -\vskip-0.5cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/sym_mul_map.v} -\begin{columns} -\column[t]{6cm} -\vskip-0.5cm\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/sym_mul_test.v} -\column[t]{4cm} -\vskip-0.5cm\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys, lastline=4]{PRESENTATION_ExAdv/sym_mul_test.ys} -\end{columns} -\end{frame} - -\subsubsection{Scripting in map modules} - -\begin{frame}{\subsubsecname} -\begin{itemize} -\item The special wires {\tt \_TECHMAP\_DO\_*} can be used to run Yosys scripts -in the context of the replacement module. -\medskip -\item The wire that comes first in alphabetical oder is interpreted as string (must -be connected to constants) that is executed as script. Then the wire is removed. Repeat. -\medskip -\item You can even call techmap recursively! -\medskip -\item Example use-cases: -\begin{itemize} -\item Using always blocks in map module: call {\tt proc} -\item Perform expensive optimizations (such as {\tt freduce}) on cells where -this is known to work well. -\item Interacting with custom commands. -\end{itemize} -\end{itemize} - -\scriptsize -PROTIP: Commands such as {\tt shell}, {\tt show -pause}, and {\tt dump} can be use -in the {\tt \_TECHMAP\_DO\_*} scripts for debugging map modules. -\end{frame} - -\begin{frame}[t]{\subsubsecname{} -- Example} -\vbox to 0cm{ -\vskip4.2cm -\hskip0.5cm\includegraphics[width=10cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/mymul.pdf} -\vss -} -\vskip-0.6cm -\begin{columns} -\column[t]{6cm} -\vskip-0.6cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/mymul_map.v} -\column[t]{4.2cm} -\vskip-0.6cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/mymul_test.v} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys, lastline=5]{PRESENTATION_ExAdv/mymul_test.ys} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, frame=single, language=ys, firstline=7, lastline=12]{PRESENTATION_ExAdv/mymul_test.ys} -\end{columns} -\end{frame} - -\subsubsection{Handling constant inputs} - -\begin{frame}{\subsubsecname} -\begin{itemize} -\item The special parameters {\tt \_TECHMAP\_CONSTMSK\_\it \tt \_} and -{\tt \_TECHMAP\_CONSTVAL\_\it \tt \_} can be used to handle constant -input values to cells. -\medskip -\item The former contains 1-bits for all constant input bits on the port. -\medskip -\item The latter contains the constant bits or undef (x) for non-constant bits. -\medskip -\item Example use-cases: -\begin{itemize} -\item Converting arithmetic (for example multiply to shift) -\item Identify constant addresses or enable bits in memory interfaces. -\end{itemize} -\end{itemize} -\end{frame} - -\begin{frame}[t]{\subsubsecname{} -- Example} -\vbox to 0cm{ -\vskip5.2cm -\hskip6.5cm\includegraphics[width=5cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/mulshift.pdf} -\vss -} -\vskip-0.6cm -\begin{columns} -\column[t]{6cm} -\vskip-0.4cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/mulshift_map.v} -\column[t]{4.2cm} -\vskip-0.6cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/mulshift_test.v} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys, lastline=5]{PRESENTATION_ExAdv/mulshift_test.ys} -\end{columns} -\end{frame} - -\subsubsection{Handling shorted inputs} - -\begin{frame}{\subsubsecname} -\begin{itemize} -\item The special parameters {\tt \_TECHMAP\_BITS\_CONNMAP\_} and -{\tt \_TECHMAP\_CONNMAP\_\it \tt \_} can be used to handle shorted inputs. -\medskip -\item Each bit of the port correlates to an {\tt \_TECHMAP\_BITS\_CONNMAP\_} bits wide -number in {\tt \_TECHMAP\_CONNMAP\_\it \tt \_}. -\medskip -\item Each unique signal bit is assigned its own number. Identical fields in the {\tt -\_TECHMAP\_CONNMAP\_\it \tt \_} parameters mean shorted signal bits. -\medskip -\item The numbers 0-3 are reserved for {\tt 0}, {\tt 1}, {\tt x}, and {\tt z} respectively. -\medskip -\item Example use-cases: -\begin{itemize} -\item Detecting shared clock or control signals in memory interfaces. -\item In some cases this can be used for for optimization. -\end{itemize} -\end{itemize} -\end{frame} - -\begin{frame}[t]{\subsubsecname{} -- Example} -\vbox to 0cm{ -\vskip4.5cm -\hskip6.5cm\includegraphics[width=5cm,trim=0 0cm 0 0cm]{PRESENTATION_ExAdv/addshift.pdf} -\vss -} -\vskip-0.6cm -\begin{columns} -\column[t]{6cm} -\vskip-0.4cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/addshift_map.v} -\column[t]{4.2cm} -\vskip-0.6cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/addshift_test.v} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys, lastline=5]{PRESENTATION_ExAdv/addshift_test.ys} -\end{columns} -\end{frame} - -\subsubsection{Notes on using techmap} - -\begin{frame}{\subsubsecname} -\begin{itemize} -\item Don't use positional cell parameters in map modules. -\medskip -\item Don't try to implement basic logic optimization with techmap. \\ -{\small (So the OR-reduce using OR3X1 cells map was actually a bad example.)} -\medskip -\item You can use the {\tt \$\_\,\_}-prefix for internal cell types to avoid -collisions with the user-namespace. But always use two underscores or the -internal consistency checker will trigger on this cells. -\medskip -\item Techmap has two major use cases: -\begin{itemize} -\item Creating good logic-level representation of arithmetic functions. \\ -This also means using dedicated hardware resources such as half- and full-adder -cells in ASICS or dedicated carry logic in FPGAs. -\smallskip -\item Mapping of coarse-grain resources such as block memory or DSP cells. -\end{itemize} -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Coarse-grain synthesis} - -\begin{frame} -\subsectionpage -\subsectionpagesuffix -\end{frame} - -\subsubsection{Intro to coarse-grain synthesis} - -\begin{frame}[fragile]{\subsubsecname} -In coarse-grain synthesis the target architecture has cells of the same -complexity or larger complexity than the internal RTL representation. - -For example: -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog] - wire [15:0] a, b; - wire [31:0] c, y; - assign y = a * b + c; -\end{lstlisting} - -This circuit contains two cells in the RTL representation: one multiplier and -one adder. In some architectures this circuit can be implemented using -a single circuit element, for example an FPGA DSP core. Coarse grain synthesis -is this mapping of groups of circuit elements to larger components. - -\bigskip -Fine-grain synthesis would be matching the circuit elements to smaller -components, such as LUTs, gates, or half- and full-adders. -\end{frame} - -\subsubsection{The extract pass} - -\begin{frame}{\subsubsecname} -\begin{itemize} -\item Like the {\tt techmap} pass, the {\tt extract} pass is called with -a map file. It compares the circuits inside the modules of the map file -with the design and looks for sub-circuits in the design that match any -of the modules in the map file. -\bigskip -\item If a match is found, the {\tt extract} pass will replace the matching -subcircuit with an instance of the module from the map file. -\bigskip -\item In a way the {\tt extract} pass is the inverse of the techmap pass. -\end{itemize} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- Example 1/2} -\vbox to 0cm{ -\vskip2cm -\begin{tikzpicture} - \node at (0,0) {\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_00a.pdf}}; - \node at (3,-3) {\includegraphics[width=8cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_00b.pdf}}; - \draw[yshift=0.2cm,thick,-latex] (1,-1) -- (2,-2); -\end{tikzpicture} -\vss} -\vskip-1.2cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/macc_simple_test.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExAdv/macc_simple_xmap.v} -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=ys] -read_verilog macc_simple_test.v -hierarchy -check -top test - -extract -map macc_simple_xmap.v;; -\end{lstlisting} -\end{columns} -\end{frame} - -\begin{frame}[fragile]{\subsubsecname{} -- Example 2/2} -\hfil\begin{tabular}{cc} -\fbox{\hbox to 5cm {\lstinputlisting[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/macc_simple_test_01.v}}} & -\fbox{\hbox to 5cm {\lstinputlisting[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExAdv/macc_simple_test_02.v}}} \\ -$\downarrow$ & $\downarrow$ \\ -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_01a.pdf}} & -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_02a.pdf}} \\ -$\downarrow$ & $\downarrow$ \\ -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_01b.pdf}} & -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_simple_test_02b.pdf}} \\ -\end{tabular} -\end{frame} - -\subsubsection{The wrap-extract-unwrap method} - -\begin{frame}{\subsubsecname} -\scriptsize -Often a coarse-grain element has a constant bit-width, but can be used to -implement operations with a smaller bit-width. For example, a 18x25-bit multiplier -can also be used to implement 16x20-bit multiplication. - -\bigskip -A way of mapping such elements in coarse grain synthesis is the wrap-extract-unwrap method: - -\begin{itemize} -\item {\bf wrap} \\ -Identify candidate-cells in the circuit and wrap them in a cell with a constant -wider bit-width using {\tt techmap}. The wrappers use the same parameters as the original cell, so -the information about the original width of the ports is preserved. \\ -Then use the {\tt connwrappers} command to connect up the bit-extended in- and -outputs of the wrapper cells. -\item {\bf extract} \\ -Now all operations are encoded using the same bit-width as the coarse grain element. The {\tt -extract} command can be used to replace circuits with cells of the target architecture. -\item {\bf unwrap} \\ -The remaining wrapper cell can be unwrapped using {\tt techmap}. -\end{itemize} - -\bigskip -The following sides detail an example that shows how to map MACC operations of -arbitrary size to MACC cells with a 18x25-bit multiplier and a 48-bit adder (such as -the Xilinx DSP48 cells). -\end{frame} - -\subsubsection{Example: DSP48\_MACC} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 1/13} -Preconditioning: {\tt macc\_xilinx\_swap\_map.v} \\ -Make sure {\tt A} is the smaller port on all multipliers - -\begin{columns} -\column{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, lastline=15]{PRESENTATION_ExAdv/macc_xilinx_swap_map.v} -\column{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=16]{PRESENTATION_ExAdv/macc_xilinx_swap_map.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 2/13} -Wrapping multipliers: {\tt macc\_xilinx\_wrap\_map.v} - -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, lastline=23]{PRESENTATION_ExAdv/macc_xilinx_wrap_map.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=24, lastline=46]{PRESENTATION_ExAdv/macc_xilinx_wrap_map.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 3/13} -Wrapping adders: {\tt macc\_xilinx\_wrap\_map.v} - -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=48, lastline=67]{PRESENTATION_ExAdv/macc_xilinx_wrap_map.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=68, lastline=89]{PRESENTATION_ExAdv/macc_xilinx_wrap_map.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 4/13} -Extract: {\tt macc\_xilinx\_xmap.v} - -\lstinputlisting[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=1, lastline=17]{PRESENTATION_ExAdv/macc_xilinx_xmap.v} - -.. simply use the same wrapping commands on this module as on the design to create a template for the {\tt extract} command. -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 5/13} -Unwrapping multipliers: {\tt macc\_xilinx\_unwrap\_map.v} - -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=1, lastline=17]{PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=18, lastline=30]{PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 6/13} -Unwrapping adders: {\tt macc\_xilinx\_unwrap\_map.v} - -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=32, lastline=48]{PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{7pt}{8pt}\selectfont, language=verilog, firstline=49, lastline=61]{PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v} -\end{columns} -\end{frame} - -\begin{frame}[fragile]{\subsubsecname{} -- 7/13} -\hfil\begin{tabular}{cc} -{\tt test1} & {\tt test2} \\ -\fbox{\hbox to 5cm {\lstinputlisting[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, firstline=1, lastline=6, language=verilog]{PRESENTATION_ExAdv/macc_xilinx_test.v}}} & -\fbox{\hbox to 5cm {\lstinputlisting[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, firstline=8, lastline=13, language=verilog]{PRESENTATION_ExAdv/macc_xilinx_test.v}}} \\ -$\downarrow$ & $\downarrow$ \\ -\end{tabular} -\vskip-0.5cm -\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - read_verilog macc_xilinx_test.v - hierarchy -check -\end{lstlisting} -\vskip-0.5cm -\hfil\begin{tabular}{cc} -$\downarrow$ & $\downarrow$ \\ -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1a.pdf}} & -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2a.pdf}} \\ -\end{tabular} -\end{frame} - -\begin{frame}[fragile]{\subsubsecname{} -- 8/13} -\hfil\begin{tabular}{cc} -{\tt test1} & {\tt test2} \\ -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1a.pdf}} & -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2a.pdf}} \\ -$\downarrow$ & $\downarrow$ \\ -\end{tabular} -\vskip-0.2cm -\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - techmap -map macc_xilinx_swap_map.v ;; -\end{lstlisting} -\vskip-0.2cm -\hfil\begin{tabular}{cc} -$\downarrow$ & $\downarrow$ \\ -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1b.pdf}} & -\fbox{\includegraphics[width=5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2b.pdf}} \\ -\end{tabular} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 9/13} -Wrapping in {\tt test1}: -\begin{columns} -\column[t]{5cm} -\vbox to 0cm{\fbox{\includegraphics[width=4.5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1b.pdf}}\vss} -\column[t]{6cm} -\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -techmap -map macc_xilinx_wrap_map.v - -connwrappers -unsigned $__mul_wrapper \ - Y Y_WIDTH \ - -unsigned $__add_wrapper \ - Y Y_WIDTH ;; -\end{lstlisting} -\end{columns} - -\vskip1cm -\hfil\includegraphics[width=\linewidth,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1c.pdf} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 10/13} -Wrapping in {\tt test2}: -\begin{columns} -\column[t]{5cm} -\vbox to 0cm{\fbox{\includegraphics[width=4.5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2b.pdf}}\vss} -\column[t]{6cm} -\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -techmap -map macc_xilinx_wrap_map.v - -connwrappers -unsigned $__mul_wrapper \ - Y Y_WIDTH \ - -unsigned $__add_wrapper \ - Y Y_WIDTH ;; -\end{lstlisting} -\end{columns} - -\vskip1cm -\hfil\includegraphics[width=\linewidth,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2c.pdf} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 11/13} -Extract in {\tt test1}: -\begin{columns} -\column[t]{4.5cm} -\vbox to 0cm{ -\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -design -push -read_verilog macc_xilinx_xmap.v -techmap -map macc_xilinx_swap_map.v -techmap -map macc_xilinx_wrap_map.v;; -design -save __macc_xilinx_xmap -design -pop -\end{lstlisting} -\vss} -\column[t]{5.5cm} -\vskip-1cm -\begin{lstlisting}[linewidth=5.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -extract -constports -ignore_parameters \ - -map %__macc_xilinx_xmap \ - -swap $__add_wrapper A,B ;; -\end{lstlisting} -\vbox to 0cm{\fbox{\includegraphics[width=4.5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1c.pdf}}\vss} -\end{columns} - -\vskip2cm -\hfil\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test1d.pdf} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 12/13} -Extract in {\tt test2}: -\begin{columns} -\column[t]{4.5cm} -\vbox to 0cm{ -\begin{lstlisting}[linewidth=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -design -push -read_verilog macc_xilinx_xmap.v -techmap -map macc_xilinx_swap_map.v -techmap -map macc_xilinx_wrap_map.v;; -design -save __macc_xilinx_xmap -design -pop -\end{lstlisting} -\vss} -\column[t]{5.5cm} -\vskip-1cm -\begin{lstlisting}[linewidth=5.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -extract -constports -ignore_parameters \ - -map %__macc_xilinx_xmap \ - -swap $__add_wrapper A,B ;; -\end{lstlisting} -\vbox to 0cm{\fbox{\includegraphics[width=4.5cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2c.pdf}}\vss} -\end{columns} - -\vskip2cm -\hfil\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2d.pdf} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname{} -- 13/13} -Unwrap in {\tt test2}: - -\hfil\begin{tikzpicture} -\node at (0,0) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2d.pdf}}; -\node at (0,-4) {\includegraphics[width=8cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2e.pdf}}; -\node at (1,-1.7) {\begin{lstlisting}[linewidth=5.5cm, frame=single, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -techmap -map macc_xilinx_unwrap_map.v ;; -\end{lstlisting}}; -\draw[-latex] (4,-0.7) .. controls (5,-1.7) .. (4,-2.7); -\end{tikzpicture} -\end{frame} - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Automatic design changes} - -\begin{frame} -\subsectionpage -\subsectionpagesuffix -\end{frame} - -\subsubsection{Changing the design from Yosys} - -\begin{frame}{\subsubsecname} -Yosys commands can be used to change the design in memory. Examples of this are: - -\begin{itemize} -\item {\bf Changes in design hierarchy} \\ -Commands such as {\tt flatten} and {\tt submod} can be used to change the design hierarchy, i.e. -flatten the hierarchy or moving parts of a module to a submodule. This has applications in synthesis -scripts as well as in reverse engineering and analysis. - -\item {\bf Behavioral changes} \\ -Commands such as {\tt techmap} can be used to make behavioral changes to the design, for example -changing asynchronous resets to synchronous resets. This has applications in design space exploration -(evaluation of various architectures for one circuit). -\end{itemize} -\end{frame} - -\subsubsection{Example: Async reset to sync reset} - -\begin{frame}[t, fragile]{\subsubsecname} -The following techmap map file replaces all positive-edge async reset flip-flops with -positive-edge sync reset flip-flops. The code is taken from the example Yosys script -for ASIC synthesis of the Amber ARMv2 CPU. - -\begin{columns} -\column[t]{6cm} -\vbox to 0cm{ -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog] -(* techmap_celltype = "$adff" *) -module adff2dff (CLK, ARST, D, Q); - - parameter WIDTH = 1; - parameter CLK_POLARITY = 1; - parameter ARST_POLARITY = 1; - parameter ARST_VALUE = 0; - - input CLK, ARST; - input [WIDTH-1:0] D; - output reg [WIDTH-1:0] Q; - - wire [1023:0] _TECHMAP_DO_ = "proc"; - - wire _TECHMAP_FAIL_ = !CLK_POLARITY || !ARST_POLARITY; -\end{lstlisting} -\vss} -\column[t]{4cm} -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog] -// ..continued.. - - - always @(posedge CLK) - if (ARST) - Q <= ARST_VALUE; - else - <= D; - -endmodule -\end{lstlisting} -\end{columns} - -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Summary} - -\begin{frame}{\subsecname} -\begin{itemize} -\item A lot can be achieved in Yosys just with the standard set of commands. -\item The commands {\tt techmap} and {\tt extract} can be used to prototype many complex synthesis tasks. -\end{itemize} - -\bigskip -\bigskip -\begin{center} -Questions? -\end{center} - -\bigskip -\bigskip -\begin{center} -\url{http://www.clifford.at/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_ExAdv/.gitignore b/yosys/manual/PRESENTATION_ExAdv/.gitignore deleted file mode 100644 index cf658897d..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dot diff --git a/yosys/manual/PRESENTATION_ExAdv/Makefile b/yosys/manual/PRESENTATION_ExAdv/Makefile deleted file mode 100644 index 993a9d9e1..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/Makefile +++ /dev/null @@ -1,28 +0,0 @@ - -all: select.pdf red_or3x1.pdf sym_mul.pdf mymul.pdf mulshift.pdf addshift.pdf \ - macc_simple_xmap.pdf macc_xilinx_xmap.pdf - -select.pdf: select.v select.ys - ../../yosys select.ys - -red_or3x1.pdf: red_or3x1_* - ../../yosys red_or3x1_test.ys - -sym_mul.pdf: sym_mul_* - ../../yosys sym_mul_test.ys - -mymul.pdf: mymul_* - ../../yosys mymul_test.ys - -mulshift.pdf: mulshift_* - ../../yosys mulshift_test.ys - -addshift.pdf: addshift_* - ../../yosys addshift_test.ys - -macc_simple_xmap.pdf: macc_simple_*.v macc_simple_test.ys - ../../yosys macc_simple_test.ys - -macc_xilinx_xmap.pdf: macc_xilinx_*.v macc_xilinx_test.ys - ../../yosys macc_xilinx_test.ys - diff --git a/yosys/manual/PRESENTATION_ExAdv/addshift_map.v b/yosys/manual/PRESENTATION_ExAdv/addshift_map.v deleted file mode 100644 index 13ecf0bae..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/addshift_map.v +++ /dev/null @@ -1,20 +0,0 @@ -module \$add (A, B, Y); - parameter A_SIGNED = 0; - parameter B_SIGNED = 0; - parameter A_WIDTH = 1; - parameter B_WIDTH = 1; - parameter Y_WIDTH = 1; - - input [A_WIDTH-1:0] A; - input [B_WIDTH-1:0] B; - output [Y_WIDTH-1:0] Y; - - parameter _TECHMAP_BITS_CONNMAP_ = 0; - parameter _TECHMAP_CONNMAP_A_ = 0; - parameter _TECHMAP_CONNMAP_B_ = 0; - - wire _TECHMAP_FAIL_ = A_WIDTH != B_WIDTH || B_WIDTH < Y_WIDTH || - _TECHMAP_CONNMAP_A_ != _TECHMAP_CONNMAP_B_; - - assign Y = A << 1; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/addshift_test.v b/yosys/manual/PRESENTATION_ExAdv/addshift_test.v deleted file mode 100644 index b53271faa..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/addshift_test.v +++ /dev/null @@ -1,5 +0,0 @@ -module test (A, B, X, Y); -input [7:0] A, B; -output [7:0] X = A + B; -output [7:0] Y = A + A; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/addshift_test.ys b/yosys/manual/PRESENTATION_ExAdv/addshift_test.ys deleted file mode 100644 index c08f1106a..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/addshift_test.ys +++ /dev/null @@ -1,6 +0,0 @@ -read_verilog addshift_test.v -hierarchy -check -top test - -techmap -map addshift_map.v;; - -show -prefix addshift -format pdf -notitle diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_simple_test.v b/yosys/manual/PRESENTATION_ExAdv/macc_simple_test.v deleted file mode 100644 index 6358a47c9..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_simple_test.v +++ /dev/null @@ -1,6 +0,0 @@ -module test(a, b, c, d, y); -input [15:0] a, b; -input [31:0] c, d; -output [31:0] y; -assign y = a * b + c + d; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_simple_test.ys b/yosys/manual/PRESENTATION_ExAdv/macc_simple_test.ys deleted file mode 100644 index 8d106a28c..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_simple_test.ys +++ /dev/null @@ -1,37 +0,0 @@ -read_verilog macc_simple_test.v -hierarchy -check -top test;; - -show -prefix macc_simple_test_00a -format pdf -notitle -lib macc_simple_xmap.v - -extract -constports -map macc_simple_xmap.v;; -show -prefix macc_simple_test_00b -format pdf -notitle -lib macc_simple_xmap.v - -################################################# - -design -reset -read_verilog macc_simple_test_01.v -hierarchy -check -top test;; - -show -prefix macc_simple_test_01a -format pdf -notitle -lib macc_simple_xmap.v - -extract -map macc_simple_xmap.v;; -show -prefix macc_simple_test_01b -format pdf -notitle -lib macc_simple_xmap.v - -################################################# - -design -reset -read_verilog macc_simple_test_02.v -hierarchy -check -top test;; - -show -prefix macc_simple_test_02a -format pdf -notitle -lib macc_simple_xmap.v - -extract -map macc_simple_xmap.v;; -show -prefix macc_simple_test_02b -format pdf -notitle -lib macc_simple_xmap.v - -################################################# - -design -reset -read_verilog macc_simple_xmap.v -hierarchy -check -top macc_16_16_32;; - -show -prefix macc_simple_xmap -format pdf -notitle diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_simple_test_01.v b/yosys/manual/PRESENTATION_ExAdv/macc_simple_test_01.v deleted file mode 100644 index 8391fb383..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_simple_test_01.v +++ /dev/null @@ -1,6 +0,0 @@ -module test(a, b, c, d, x, y); -input [15:0] a, b, c, d; -input [31:0] x; -output [31:0] y; -assign y = a*b + c*d + x; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_simple_test_02.v b/yosys/manual/PRESENTATION_ExAdv/macc_simple_test_02.v deleted file mode 100644 index 3630102fa..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_simple_test_02.v +++ /dev/null @@ -1,6 +0,0 @@ -module test(a, b, c, d, x, y); -input [15:0] a, b, c, d; -input [31:0] x; -output [31:0] y; -assign y = a*b + (c*d + x); -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_simple_xmap.v b/yosys/manual/PRESENTATION_ExAdv/macc_simple_xmap.v deleted file mode 100644 index 42f5bae95..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_simple_xmap.v +++ /dev/null @@ -1,6 +0,0 @@ -module macc_16_16_32(a, b, c, y); -input [15:0] a, b; -input [31:0] c; -output [31:0] y; -assign y = a*b + c; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_swap_map.v b/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_swap_map.v deleted file mode 100644 index e36967225..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_swap_map.v +++ /dev/null @@ -1,28 +0,0 @@ -(* techmap_celltype = "$mul" *) -module mul_swap_ports (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire _TECHMAP_FAIL_ = A_WIDTH <= B_WIDTH; - -\$mul #( - .A_SIGNED(B_SIGNED), - .B_SIGNED(A_SIGNED), - .A_WIDTH(B_WIDTH), - .B_WIDTH(A_WIDTH), - .Y_WIDTH(Y_WIDTH) -) _TECHMAP_REPLACE_ ( - .A(B), - .B(A), - .Y(Y) -); - -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_test.v b/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_test.v deleted file mode 100644 index 683d9d847..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_test.v +++ /dev/null @@ -1,13 +0,0 @@ -module test1(a, b, c, d, e, f, y); - input [19:0] a, b, c; - input [15:0] d, e, f; - output [41:0] y; - assign y = a*b + c*d + e*f; -endmodule - -module test2(a, b, c, d, e, f, y); - input [19:0] a, b, c; - input [15:0] d, e, f; - output [41:0] y; - assign y = a*b + (c*d + e*f); -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_test.ys b/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_test.ys deleted file mode 100644 index f3e8af4f0..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_test.ys +++ /dev/null @@ -1,43 +0,0 @@ -read_verilog macc_xilinx_test.v -read_verilog -lib -icells macc_xilinx_unwrap_map.v -read_verilog -lib -icells macc_xilinx_xmap.v -hierarchy -check ;; - -show -prefix macc_xilinx_test1a -format pdf -notitle test1 -show -prefix macc_xilinx_test2a -format pdf -notitle test2 - -techmap -map macc_xilinx_swap_map.v;; - -show -prefix macc_xilinx_test1b -format pdf -notitle test1 -show -prefix macc_xilinx_test2b -format pdf -notitle test2 - -techmap -map macc_xilinx_wrap_map.v - -connwrappers -unsigned $__mul_wrapper Y Y_WIDTH \ - -unsigned $__add_wrapper Y Y_WIDTH;; - -show -prefix macc_xilinx_test1c -format pdf -notitle test1 -show -prefix macc_xilinx_test2c -format pdf -notitle test2 - -design -push -read_verilog macc_xilinx_xmap.v -techmap -map macc_xilinx_swap_map.v -techmap -map macc_xilinx_wrap_map.v;; -design -save __macc_xilinx_xmap -design -pop - -extract -constports -ignore_parameters \ - -map %__macc_xilinx_xmap \ - -swap $__add_wrapper A,B ;; - -show -prefix macc_xilinx_test1d -format pdf -notitle test1 -show -prefix macc_xilinx_test2d -format pdf -notitle test2 - -techmap -map macc_xilinx_unwrap_map.v;; - -show -prefix macc_xilinx_test1e -format pdf -notitle test1 -show -prefix macc_xilinx_test2e -format pdf -notitle test2 - -design -load __macc_xilinx_xmap -show -prefix macc_xilinx_xmap -format pdf -notitle - diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v b/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v deleted file mode 100644 index 9dfaef131..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_unwrap_map.v +++ /dev/null @@ -1,61 +0,0 @@ -module \$__mul_wrapper (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [17:0] A; -input [24:0] B; -output [47:0] Y; - -wire [A_WIDTH-1:0] A_ORIG = A; -wire [B_WIDTH-1:0] B_ORIG = B; -wire [Y_WIDTH-1:0] Y_ORIG; -assign Y = Y_ORIG; - -\$mul #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) -) _TECHMAP_REPLACE_ ( - .A(A_ORIG), - .B(B_ORIG), - .Y(Y_ORIG) -); - -endmodule - -module \$__add_wrapper (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [47:0] A; -input [47:0] B; -output [47:0] Y; - -wire [A_WIDTH-1:0] A_ORIG = A; -wire [B_WIDTH-1:0] B_ORIG = B; -wire [Y_WIDTH-1:0] Y_ORIG; -assign Y = Y_ORIG; - -\$add #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) -) _TECHMAP_REPLACE_ ( - .A(A_ORIG), - .B(B_ORIG), - .Y(Y_ORIG) -); - -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_wrap_map.v b/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_wrap_map.v deleted file mode 100644 index f23f6c02a..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_wrap_map.v +++ /dev/null @@ -1,89 +0,0 @@ -(* techmap_celltype = "$mul" *) -module mul_wrap (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire [17:0] A_18 = A; -wire [24:0] B_25 = B; -wire [47:0] Y_48; -assign Y = Y_48; - -wire [1023:0] _TECHMAP_DO_ = "proc; clean"; - -reg _TECHMAP_FAIL_; -initial begin - _TECHMAP_FAIL_ <= 0; - if (A_SIGNED || B_SIGNED) - _TECHMAP_FAIL_ <= 1; - if (A_WIDTH < 4 || B_WIDTH < 4) - _TECHMAP_FAIL_ <= 1; - if (A_WIDTH > 18 || B_WIDTH > 25) - _TECHMAP_FAIL_ <= 1; - if (A_WIDTH*B_WIDTH < 100) - _TECHMAP_FAIL_ <= 1; -end - -\$__mul_wrapper #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) -) _TECHMAP_REPLACE_ ( - .A(A_18), - .B(B_25), - .Y(Y_48) -); - -endmodule - -(* techmap_celltype = "$add" *) -module add_wrap (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire [47:0] A_48 = A; -wire [47:0] B_48 = B; -wire [47:0] Y_48; -assign Y = Y_48; - -wire [1023:0] _TECHMAP_DO_ = "proc; clean"; - -reg _TECHMAP_FAIL_; -initial begin - _TECHMAP_FAIL_ <= 0; - if (A_SIGNED || B_SIGNED) - _TECHMAP_FAIL_ <= 1; - if (A_WIDTH < 10 && B_WIDTH < 10) - _TECHMAP_FAIL_ <= 1; -end - -\$__add_wrapper #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) -) _TECHMAP_REPLACE_ ( - .A(A_48), - .B(B_48), - .Y(Y_48) -); - -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_xmap.v b/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_xmap.v deleted file mode 100644 index 06372f5af..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/macc_xilinx_xmap.v +++ /dev/null @@ -1,10 +0,0 @@ -module DSP48_MACC (a, b, c, y); - -input [17:0] a; -input [24:0] b; -input [47:0] c; -output [47:0] y; - -assign y = a*b + c; - -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/mulshift_map.v b/yosys/manual/PRESENTATION_ExAdv/mulshift_map.v deleted file mode 100644 index 4a3c2a062..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/mulshift_map.v +++ /dev/null @@ -1,26 +0,0 @@ -module MYMUL(A, B, Y); - parameter WIDTH = 1; - input [WIDTH-1:0] A, B; - output reg [WIDTH-1:0] Y; - - parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx; - parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx; - - reg _TECHMAP_FAIL_; - wire [1023:0] _TECHMAP_DO_ = "proc; clean"; - - integer i; - always @* begin - _TECHMAP_FAIL_ <= 1; - for (i = 0; i < WIDTH; i=i+1) begin - if (_TECHMAP_CONSTVAL_A_ === WIDTH'd1 << i) begin - _TECHMAP_FAIL_ <= 0; - Y <= B << i; - end - if (_TECHMAP_CONSTVAL_B_ === WIDTH'd1 << i) begin - _TECHMAP_FAIL_ <= 0; - Y <= A << i; - end - end - end -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/mulshift_test.v b/yosys/manual/PRESENTATION_ExAdv/mulshift_test.v deleted file mode 100644 index 4b975f414..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/mulshift_test.v +++ /dev/null @@ -1,5 +0,0 @@ -module test (A, X, Y); -input [7:0] A; -output [7:0] X = A * 8'd 6; -output [7:0] Y = A * 8'd 8; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/mulshift_test.ys b/yosys/manual/PRESENTATION_ExAdv/mulshift_test.ys deleted file mode 100644 index c5dac49eb..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/mulshift_test.ys +++ /dev/null @@ -1,7 +0,0 @@ -read_verilog mulshift_test.v -hierarchy -check -top test - -techmap -map sym_mul_map.v \ - -map mulshift_map.v;; - -show -prefix mulshift -format pdf -notitle -lib sym_mul_cells.v diff --git a/yosys/manual/PRESENTATION_ExAdv/mymul_map.v b/yosys/manual/PRESENTATION_ExAdv/mymul_map.v deleted file mode 100644 index e888a7a7c..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/mymul_map.v +++ /dev/null @@ -1,15 +0,0 @@ -module MYMUL(A, B, Y); - parameter WIDTH = 1; - input [WIDTH-1:0] A, B; - output reg [WIDTH-1:0] Y; - - wire [1023:0] _TECHMAP_DO_ = "proc; clean"; - - integer i; - always @* begin - Y = 0; - for (i = 0; i < WIDTH; i=i+1) - if (A[i]) - Y = Y + (B << i); - end -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/mymul_test.v b/yosys/manual/PRESENTATION_ExAdv/mymul_test.v deleted file mode 100644 index 620a06d9e..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/mymul_test.v +++ /dev/null @@ -1,4 +0,0 @@ -module test(A, B, Y); - input [1:0] A, B; - output [1:0] Y = A * B; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/mymul_test.ys b/yosys/manual/PRESENTATION_ExAdv/mymul_test.ys deleted file mode 100644 index 48203e319..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/mymul_test.ys +++ /dev/null @@ -1,15 +0,0 @@ -read_verilog mymul_test.v -hierarchy -check -top test - -techmap -map sym_mul_map.v \ - -map mymul_map.v;; - -rename test test_mapped -read_verilog mymul_test.v -miter -equiv test test_mapped miter -flatten miter - -sat -verify -prove trigger 0 miter - -splitnets -ports test_mapped/A -show -prefix mymul -format pdf -notitle test_mapped diff --git a/yosys/manual/PRESENTATION_ExAdv/red_or3x1_cells.v b/yosys/manual/PRESENTATION_ExAdv/red_or3x1_cells.v deleted file mode 100644 index 0750a1307..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/red_or3x1_cells.v +++ /dev/null @@ -1,5 +0,0 @@ -module OR3X1(A, B, C, Y); - input A, B, C; - output Y; - assign Y = A | B | C; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/red_or3x1_map.v b/yosys/manual/PRESENTATION_ExAdv/red_or3x1_map.v deleted file mode 100644 index 8c37b1dba..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/red_or3x1_map.v +++ /dev/null @@ -1,48 +0,0 @@ -module \$reduce_or (A, Y); - - parameter A_SIGNED = 0; - parameter A_WIDTH = 0; - parameter Y_WIDTH = 0; - - input [A_WIDTH-1:0] A; - output [Y_WIDTH-1:0] Y; - - function integer min; - input integer a, b; - begin - if (a < b) - min = a; - else - min = b; - end - endfunction - - genvar i; - generate begin - if (A_WIDTH == 0) begin - assign Y = 0; - end - if (A_WIDTH == 1) begin - assign Y = A; - end - if (A_WIDTH == 2) begin - wire ybuf; - OR3X1 g (.A(A[0]), .B(A[1]), .C(1'b0), .Y(ybuf)); - assign Y = ybuf; - end - if (A_WIDTH == 3) begin - wire ybuf; - OR3X1 g (.A(A[0]), .B(A[1]), .C(A[2]), .Y(ybuf)); - assign Y = ybuf; - end - if (A_WIDTH > 3) begin - localparam next_stage_sz = (A_WIDTH+2) / 3; - wire [next_stage_sz-1:0] next_stage; - for (i = 0; i < next_stage_sz; i = i+1) begin - localparam bits = min(A_WIDTH - 3*i, 3); - assign next_stage[i] = |A[3*i +: bits]; - end - assign Y = |next_stage; - end - end endgenerate -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/red_or3x1_test.v b/yosys/manual/PRESENTATION_ExAdv/red_or3x1_test.v deleted file mode 100644 index bcdd32cbf..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/red_or3x1_test.v +++ /dev/null @@ -1,5 +0,0 @@ -module test (A, Y); - input [6:0] A; - output Y; - assign Y = |A; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/red_or3x1_test.ys b/yosys/manual/PRESENTATION_ExAdv/red_or3x1_test.ys deleted file mode 100644 index b92346034..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/red_or3x1_test.ys +++ /dev/null @@ -1,7 +0,0 @@ -read_verilog red_or3x1_test.v -hierarchy -check -top test - -techmap -map red_or3x1_map.v;; - -splitnets -ports -show -prefix red_or3x1 -format pdf -notitle -lib red_or3x1_cells.v diff --git a/yosys/manual/PRESENTATION_ExAdv/select.v b/yosys/manual/PRESENTATION_ExAdv/select.v deleted file mode 100644 index 1b0bb7eeb..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/select.v +++ /dev/null @@ -1,15 +0,0 @@ -module test(clk, s, a, y); - input clk, s; - input [15:0] a; - output [15:0] y; - reg [15:0] b, c; - - always @(posedge clk) begin - b <= a; - c <= b; - end - - wire [15:0] state_a = (a ^ b) + c; - wire [15:0] state_b = (a ^ b) - c; - assign y = !s ? state_a : state_b; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/select.ys b/yosys/manual/PRESENTATION_ExAdv/select.ys deleted file mode 100644 index 9832c104b..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/select.ys +++ /dev/null @@ -1,10 +0,0 @@ -read_verilog select.v -hierarchy -check -top test -proc; opt -cd test -select -set cone_a state_a %ci*:-$dff -select -set cone_b state_b %ci*:-$dff -select -set cone_ab @cone_a @cone_b %i -show -prefix select -format pdf -notitle \ - -color red @cone_ab -color magenta @cone_a \ - -color blue @cone_b diff --git a/yosys/manual/PRESENTATION_ExAdv/sym_mul_cells.v b/yosys/manual/PRESENTATION_ExAdv/sym_mul_cells.v deleted file mode 100644 index ce1771544..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/sym_mul_cells.v +++ /dev/null @@ -1,6 +0,0 @@ -module MYMUL(A, B, Y); - parameter WIDTH = 1; - input [WIDTH-1:0] A, B; - output [WIDTH-1:0] Y; - assign Y = A * B; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/sym_mul_map.v b/yosys/manual/PRESENTATION_ExAdv/sym_mul_map.v deleted file mode 100644 index b4dbd9e07..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/sym_mul_map.v +++ /dev/null @@ -1,15 +0,0 @@ -module \$mul (A, B, Y); - parameter A_SIGNED = 0; - parameter B_SIGNED = 0; - parameter A_WIDTH = 1; - parameter B_WIDTH = 1; - parameter Y_WIDTH = 1; - - input [A_WIDTH-1:0] A; - input [B_WIDTH-1:0] B; - output [Y_WIDTH-1:0] Y; - - wire _TECHMAP_FAIL_ = A_WIDTH != B_WIDTH || B_WIDTH != Y_WIDTH; - - MYMUL #( .WIDTH(Y_WIDTH) ) g ( .A(A), .B(B), .Y(Y) ); -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/sym_mul_test.v b/yosys/manual/PRESENTATION_ExAdv/sym_mul_test.v deleted file mode 100644 index eb715f83d..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/sym_mul_test.v +++ /dev/null @@ -1,5 +0,0 @@ -module test(A, B, C, Y1, Y2); - input [7:0] A, B, C; - output [7:0] Y1 = A * B; - output [15:0] Y2 = A * C; -endmodule diff --git a/yosys/manual/PRESENTATION_ExAdv/sym_mul_test.ys b/yosys/manual/PRESENTATION_ExAdv/sym_mul_test.ys deleted file mode 100644 index 0c07e7e87..000000000 --- a/yosys/manual/PRESENTATION_ExAdv/sym_mul_test.ys +++ /dev/null @@ -1,6 +0,0 @@ -read_verilog sym_mul_test.v -hierarchy -check -top test - -techmap -map sym_mul_map.v;; - -show -prefix sym_mul -format pdf -notitle -lib sym_mul_cells.v diff --git a/yosys/manual/PRESENTATION_ExOth.tex b/yosys/manual/PRESENTATION_ExOth.tex deleted file mode 100644 index 73f8bea2e..000000000 --- a/yosys/manual/PRESENTATION_ExOth.tex +++ /dev/null @@ -1,227 +0,0 @@ - -\section{Yosys by example -- Beyond Synthesis} - -\begin{frame} -\sectionpage -\end{frame} - -\begin{frame}{Overview} -This section contains 2 subsections: -\begin{itemize} -\item Interactive Design Investigation -\item Symbolic Model Checking -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Interactive Design Investigation} - -\begin{frame} -\subsectionpage -\subsectionpagesuffix -\end{frame} - -\begin{frame}{\subsecname} -Yosys can also be used to investigate designs (or netlists created -from other tools). - -\begin{itemize} -\item -The selection mechanism (see slides ``Using Selections''), especially patterns such -as {\tt \%ci} and {\tt \%co}, can be used to figure out how parts of the design -are connected. - -\item -Commands such as {\tt submod}, {\tt expose}, {\tt splice}, \dots can be used -to transform the design into an equivalent design that is easier to analyse. - -\item -Commands such as {\tt eval} and {\tt sat} can be used to investigate the -behavior of the circuit. -\end{itemize} -\end{frame} - -\begin{frame}[t, fragile]{Example: Reorganizing a module} -\begin{columns} -\column[t]{4cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=verilog]{PRESENTATION_ExOth/scrambler.v} -\column[t]{7cm} -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single] -read_verilog scrambler.v - -hierarchy; proc;; - -cd scrambler -submod -name xorshift32 \ - xs %c %ci %D %c %ci:+[D] %D \ - %ci*:-$dff xs %co %ci %d -\end{lstlisting} -\end{columns} - -\hfil\includegraphics[width=11cm,trim=0 0cm 0 1.5cm]{PRESENTATION_ExOth/scrambler_p01.pdf} - -\hfil\includegraphics[width=11cm,trim=0 0cm 0 2cm]{PRESENTATION_ExOth/scrambler_p02.pdf} -\end{frame} - -\begin{frame}[t, fragile]{Example: Analysis of circuit behavior} -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -> read_verilog scrambler.v -> hierarchy; proc;; cd scrambler -> submod -name xorshift32 xs %c %ci %D %c %ci:+[D] %D %ci*:-$dff xs %co %ci %d - -> cd xorshift32 -> rename n2 in -> rename n1 out - -> eval -set in 1 -show out -Eval result: \out = 270369. - -> eval -set in 270369 -show out -Eval result: \out = 67634689. - -> sat -set out 632435482 -Signal Name Dec Hex Bin --------------------- ---------- ---------- ------------------------------------- -\in 745495504 2c6f5bd0 00101100011011110101101111010000 -\out 632435482 25b2331a 00100101101100100011001100011010 -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Symbolic Model Checking} - -\begin{frame} -\subsectionpage -\subsectionpagesuffix -\end{frame} - -\begin{frame}{\subsecname} -Symbolic Model Checking (SMC) is used to formally prove that a circuit has -(or has not) a given property. - -\bigskip -One application is Formal Equivalence Checking: Proving that two circuits -are identical. For example this is a very useful feature when debugging custom -passes in Yosys. - -\bigskip -Other applications include checking if a module conforms to interface -standards. - -\bigskip -The {\tt sat} command in Yosys can be used to perform Symbolic Model Checking. -\end{frame} - -\begin{frame}[t]{Example: Formal Equivalence Checking (1/2)} -Remember the following example? -\vskip1em - -\vbox to 0cm{ -\vskip-0.3cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/techmap_01_map.v} -}\vbox to 0cm{ -\vskip-0.5cm -\lstinputlisting[xleftmargin=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExSyn/techmap_01.v} -\lstinputlisting[xleftmargin=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/techmap_01.ys}} - -\vskip5cm\hskip5cm -Lets see if it is correct.. -\end{frame} - -\begin{frame}[t, fragile]{Example: Formal Equivalence Checking (2/2)} -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single] -# read test design -read_verilog techmap_01.v -hierarchy -top test - -# create two version of the design: test_orig and test_mapped -copy test test_orig -rename test test_mapped - -# apply the techmap only to test_mapped -techmap -map techmap_01_map.v test_mapped - -# create a miter circuit to test equivalence -miter -equiv -make_assert -make_outputs test_orig test_mapped miter -flatten miter - -# run equivalence check -sat -verify -prove-asserts -show-inputs -show-outputs miter -\end{lstlisting} - -\dots -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont] -Solving problem with 945 variables and 2505 clauses.. -SAT proof finished - no model found: SUCCESS! -\end{lstlisting} -\end{frame} - -\begin{frame}[t, fragile]{Example: Symbolic Model Checking (1/2)} -\small -The following AXI4 Stream Master has a bug. But the bug is not exposed if the -slave keeps {\tt tready} asserted all the time. (Something a test bench might do.) - -\medskip -Symbolic Model Checking can be used to expose the bug and find a sequence -of values for {\tt tready} that yield the incorrect behavior. - -\vskip-1em -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{5pt}{6pt}\selectfont, language=verilog]{PRESENTATION_ExOth/axis_master.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{5pt}{6pt}\selectfont, language=verilog]{PRESENTATION_ExOth/axis_test.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{Example: Symbolic Model Checking (2/2)} -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single] -read_verilog -sv axis_master.v axis_test.v -hierarchy -top axis_test - -proc; flatten;; -sat -seq 50 -prove-asserts -\end{lstlisting} - -\bigskip -\dots with unmodified {\tt axis\_master.v}: -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont] -Solving problem with 159344 variables and 442126 clauses.. -SAT proof finished - model found: FAIL! -\end{lstlisting} - -\bigskip -\dots with fixed {\tt axis\_master.v}: -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont] -Solving problem with 159144 variables and 441626 clauses.. -SAT proof finished - no model found: SUCCESS! -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Summary} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Yosys provides useful features beyond synthesis. -\item The commands {\tt sat} and {\tt eval} can be used to analyse the behavior of a circuit. -\item The {\tt sat} command can also be used for symbolic model checking. -\item This can be useful for debugging and testing designs and Yosys extensions alike. -\end{itemize} - -\bigskip -\bigskip -\begin{center} -Questions? -\end{center} - -\bigskip -\bigskip -\begin{center} -\url{http://www.clifford.at/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_ExOth/.gitignore b/yosys/manual/PRESENTATION_ExOth/.gitignore deleted file mode 100644 index cf658897d..000000000 --- a/yosys/manual/PRESENTATION_ExOth/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dot diff --git a/yosys/manual/PRESENTATION_ExOth/Makefile b/yosys/manual/PRESENTATION_ExOth/Makefile deleted file mode 100644 index 4864d8d52..000000000 --- a/yosys/manual/PRESENTATION_ExOth/Makefile +++ /dev/null @@ -1,16 +0,0 @@ - -all: scrambler_p01.pdf scrambler_p02.pdf equiv.log axis_test.log - -scrambler_p01.pdf: scrambler.ys scrambler.v - ../../yosys scrambler.ys - -scrambler_p02.pdf: scrambler_p01.pdf - -equiv.log: equiv.ys - ../../yosys -l equiv.log_new equiv.ys - mv equiv.log_new equiv.log - -axis_test.log: axis_test.ys axis_master.v axis_test.v - ../../yosys -l axis_test.log_new axis_test.ys - mv axis_test.log_new axis_test.log - diff --git a/yosys/manual/PRESENTATION_ExOth/axis_master.v b/yosys/manual/PRESENTATION_ExOth/axis_master.v deleted file mode 100644 index fe9008adb..000000000 --- a/yosys/manual/PRESENTATION_ExOth/axis_master.v +++ /dev/null @@ -1,27 +0,0 @@ -module axis_master(aclk, aresetn, tvalid, tready, tdata); - input aclk, aresetn, tready; - output reg tvalid; - output reg [7:0] tdata; - - reg [31:0] state; - always @(posedge aclk) begin - if (!aresetn) begin - state <= 314159265; - tvalid <= 0; - tdata <= 'bx; - end else begin - if (tvalid && tready) - tvalid <= 0; - if (!tvalid || !tready) begin - // ^- should not be inverted! - state = state ^ state << 13; - state = state ^ state >> 7; - state = state ^ state << 17; - if (state[9:8] == 0) begin - tvalid <= 1; - tdata <= state; - end - end - end - end -endmodule diff --git a/yosys/manual/PRESENTATION_ExOth/axis_test.v b/yosys/manual/PRESENTATION_ExOth/axis_test.v deleted file mode 100644 index 0be833f16..000000000 --- a/yosys/manual/PRESENTATION_ExOth/axis_test.v +++ /dev/null @@ -1,27 +0,0 @@ -module axis_test(aclk, tready); - input aclk, tready; - wire aresetn, tvalid; - wire [7:0] tdata; - - integer counter = 0; - reg aresetn = 0; - - axis_master uut (aclk, aresetn, tvalid, tready, tdata); - - always @(posedge aclk) begin - if (aresetn && tready && tvalid) begin - if (counter == 0) assert(tdata == 19); - if (counter == 1) assert(tdata == 99); - if (counter == 2) assert(tdata == 1); - if (counter == 3) assert(tdata == 244); - if (counter == 4) assert(tdata == 133); - if (counter == 5) assert(tdata == 209); - if (counter == 6) assert(tdata == 241); - if (counter == 7) assert(tdata == 137); - if (counter == 8) assert(tdata == 176); - if (counter == 9) assert(tdata == 6); - counter <= counter + 1; - end - aresetn <= 1; - end -endmodule diff --git a/yosys/manual/PRESENTATION_ExOth/axis_test.ys b/yosys/manual/PRESENTATION_ExOth/axis_test.ys deleted file mode 100644 index 19663ac77..000000000 --- a/yosys/manual/PRESENTATION_ExOth/axis_test.ys +++ /dev/null @@ -1,5 +0,0 @@ -read_verilog -sv axis_master.v axis_test.v -hierarchy -top axis_test - -proc; flatten;; -sat -falsify -seq 50 -prove-asserts diff --git a/yosys/manual/PRESENTATION_ExOth/equiv.ys b/yosys/manual/PRESENTATION_ExOth/equiv.ys deleted file mode 100644 index 8db0a88a5..000000000 --- a/yosys/manual/PRESENTATION_ExOth/equiv.ys +++ /dev/null @@ -1,17 +0,0 @@ -# read test design -read_verilog ../PRESENTATION_ExSyn/techmap_01.v -hierarchy -top test - -# create two version of the design: test_orig and test_mapped -copy test test_orig -rename test test_mapped - -# apply the techmap only to test_mapped -techmap -map ../PRESENTATION_ExSyn/techmap_01_map.v test_mapped - -# create a miter circuit to test equivalence -miter -equiv -make_assert -make_outputs test_orig test_mapped miter -flatten miter - -# run equivalence check -sat -verify -prove-asserts -show-inputs -show-outputs miter diff --git a/yosys/manual/PRESENTATION_ExOth/scrambler.v b/yosys/manual/PRESENTATION_ExOth/scrambler.v deleted file mode 100644 index d4c1fa2bb..000000000 --- a/yosys/manual/PRESENTATION_ExOth/scrambler.v +++ /dev/null @@ -1,14 +0,0 @@ -module scrambler( - input clk, rst, in_bit, - output reg out_bit -); - reg [31:0] xs; - always @(posedge clk) begin - if (rst) - xs = 1; - xs = xs ^ (xs << 13); - xs = xs ^ (xs >> 17); - xs = xs ^ (xs << 5); - out_bit <= in_bit ^ xs[0]; - end -endmodule diff --git a/yosys/manual/PRESENTATION_ExOth/scrambler.ys b/yosys/manual/PRESENTATION_ExOth/scrambler.ys deleted file mode 100644 index 2ef14c56e..000000000 --- a/yosys/manual/PRESENTATION_ExOth/scrambler.ys +++ /dev/null @@ -1,23 +0,0 @@ - -read_verilog scrambler.v - -hierarchy; proc;; - -cd scrambler -submod -name xorshift32 xs %c %ci %D %c %ci:+[D] %D %ci*:-$dff xs %co %ci %d -cd .. - -show -prefix scrambler_p01 -format pdf -notitle scrambler -show -prefix scrambler_p02 -format pdf -notitle xorshift32 - -echo on - -cd xorshift32 -rename n2 in -rename n1 out - -eval -set in 1 -show out -eval -set in 270369 -show out - -sat -set out 632435482 - diff --git a/yosys/manual/PRESENTATION_ExSyn.tex b/yosys/manual/PRESENTATION_ExSyn.tex deleted file mode 100644 index 655720ebc..000000000 --- a/yosys/manual/PRESENTATION_ExSyn.tex +++ /dev/null @@ -1,515 +0,0 @@ - -\section{Yosys by example -- Synthesis} - -\begin{frame} -\sectionpage -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Typical Phases of a Synthesis Flow} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Reading and elaborating the design -\item Higher-level synthesis and optimization -\begin{itemize} -\item Converting {\tt always}-blocks to logic and registers -\item Perform coarse-grain optimizations (resource sharing, const folding, ...) -\item Handling of memories and other coarse-grain blocks -\item Extracting and optimizing finite state machines -\end{itemize} -\item Convert remaining logic to bit-level logic functions -\item Perform optimizations on bit-level logic functions -\item Map bit-level logic gates and registers to cell library -\item Write results to output file -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Reading the design} - -\begin{frame}[fragile]{\subsecname} -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -read_verilog file1.v -read_verilog -I include_dir -D enable_foo -D WIDTH=12 file2.v -read_verilog -lib cell_library.v - -verilog_defaults -add -I include_dir -read_verilog file3.v -read_verilog file4.v -verilog_defaults -clear - -verilog_defaults -push -verilog_defaults -add -I include_dir -read_verilog file5.v -read_verilog file6.v -verilog_defaults -pop -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Design elaboration} - -\begin{frame}[fragile]{\subsecname} -During design elaboration Yosys figures out how the modules are hierarchically -connected. It also re-runs the AST parts of the Verilog frontend to create -all needed variations of parametric modules. - -\bigskip -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -# simplest form. at least this version should be used after reading all input files -# -hierarchy - -# recommended form. fails if parts of the design hierarchy are missing, removes -# everything that is unreachable from the top module, and marks the top module. -# -hierarchy -check -top top_module -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The {\tt proc} command} - -\begin{frame}[fragile]{\subsecname} -The Verilog frontend converts {\tt always}-blocks to RTL netlists for the -expressions and ``processes'' for the control- and memory elements. - -\medskip -The {\tt proc} command transforms this ``processes'' to netlists of RTL -multiplexer and register cells. - -\medskip -The {\tt proc} command is actually a macro-command that calls the following -other commands: - -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -proc_clean # remove empty branches and processes -proc_rmdead # remove unreachable branches -proc_init # special handling of "initial" blocks -proc_arst # identify modeling of async resets -proc_mux # convert decision trees to multiplexer networks -proc_dff # extract registers from processes -proc_clean # if all went fine, this should remove all the processes -\end{lstlisting} - -\medskip -Many commands can not operate on modules with ``processes'' in them. Usually -a call to {\tt proc} is the first command in the actual synthesis procedure -after design elaboration. -\end{frame} - -\begin{frame}[fragile]{\subsecname{} -- Example 1/3} -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/proc_01.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/proc_01.ys} -\end{columns} -\hfil\includegraphics[width=8cm,trim=0 0cm 0 0cm]{PRESENTATION_ExSyn/proc_01.pdf} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Example 2/3} -\vbox to 0cm{\includegraphics[width=\linewidth,trim=0cm 0cm 0cm -2.5cm]{PRESENTATION_ExSyn/proc_02.pdf}\vss} -\vskip-1cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/proc_02.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/proc_02.ys} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Example 3/3} -\vbox to 0cm{\includegraphics[width=\linewidth,trim=0cm 0cm 0cm -1.5cm]{PRESENTATION_ExSyn/proc_03.pdf}\vss} -\vskip-1cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/proc_03.ys} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/proc_03.v} -\end{columns} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The {\tt opt} command} - -\begin{frame}[fragile]{\subsecname} -The {\tt opt} command implements a series of simple optimizations. It also -is a macro command that calls other commands: - -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -opt_expr # const folding and simple expression rewriting -opt_merge -nomux # merging identical cells - -do - opt_muxtree # remove never-active branches from multiplexer tree - opt_reduce # consolidate trees of boolean ops to reduce functions - opt_merge # merging identical cells - opt_rmdff # remove/simplify registers with constant inputs - opt_clean # remove unused objects (cells, wires) from design - opt_expr # const folding and simple expression rewriting -while [changed design] -\end{lstlisting} - -The command {\tt clean} can be used as alias for {\tt opt\_clean}. And {\tt ;;} -can be used as shortcut for {\tt clean}. For example: - -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -proc; opt; memory; opt_expr;; fsm;; -\end{lstlisting} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Example 1/4} -\vbox to 0cm{\includegraphics[width=\linewidth,trim=0cm 0cm 0cm -0.5cm]{PRESENTATION_ExSyn/opt_01.pdf}\vss} -\vskip-1cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/opt_01.ys} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/opt_01.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Example 2/4} -\vbox to 0cm{\includegraphics[width=\linewidth,trim=0cm 0cm 0cm 0cm]{PRESENTATION_ExSyn/opt_02.pdf}\vss} -\vskip-1cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/opt_02.ys} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/opt_02.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Example 3/4} -\vbox to 0cm{\includegraphics[width=\linewidth,trim=0cm 0cm 0cm -2cm]{PRESENTATION_ExSyn/opt_03.pdf}\vss} -\vskip-1cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/opt_03.ys} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/opt_03.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Example 4/4} -\vbox to 0cm{\hskip6cm\includegraphics[width=6cm,trim=0cm 0cm 0cm -3cm]{PRESENTATION_ExSyn/opt_04.pdf}\vss} -\vskip-1cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/opt_04.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/opt_04.ys} -\end{columns} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{When to use {\tt opt} or {\tt clean}} - -\begin{frame}{\subsecname} -Usually it does not hurt to call {\tt opt} after each regular command in the -synthesis script. But it increases the synthesis time, so it is favourable -to only call {\tt opt} when an improvement can be achieved. - -\bigskip -The designs in {\tt yosys-bigsim} are a good playground for experimenting with -the effects of calling {\tt opt} in various places of the flow. - -\bigskip -It generally is a good idea to call {\tt opt} before inherently expensive -commands such as {\tt sat} or {\tt freduce}, as the possible gain is much -higher in this cases as the possible loss. - -\bigskip -The {\tt clean} command on the other hand is very fast and many commands leave -a mess (dangling signal wires, etc). For example, most commands do not remove -any wires or cells. They just change the connections and depend on a later -call to clean to get rid of the now unused objects. So the occasional {\tt ;;} -is a good idea in every synthesis script. -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The {\tt memory} command} - -\begin{frame}[fragile]{\subsecname} -In the RTL netlist, memory reads and writes are individual cells. This makes -consolidating the number of ports for a memory easier. The {\tt memory} -transforms memories to an implementation. Per default that is logic for address -decoders and registers. It also is a macro command that calls other commands: - -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -# this merges registers into the memory read- and write cells. -memory_dff - -# this collects all read and write cells for a memory and transforms them -# into one multi-port memory cell. -memory_collect - -# this takes the multi-port memory cell and transforms it to address decoder -# logic and registers. This step is skipped if "memory" is called with -nomap. -memory_map -\end{lstlisting} - -\bigskip -Usually it is preferred to use architecture-specific RAM resources for memory. -For example: - -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -memory -nomap; techmap -map my_memory_map.v; memory_map -\end{lstlisting} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Example 1/2} -\vbox to 0cm{\includegraphics[width=0.7\linewidth,trim=0cm 0cm 0cm -10cm]{PRESENTATION_ExSyn/memory_01.pdf}\vss} -\vskip-1cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/memory_01.ys} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/memory_01.v} -\end{columns} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Example 2/2} -\vbox to 0cm{\hfill\includegraphics[width=7.5cm,trim=0cm 0cm 0cm -5cm]{PRESENTATION_ExSyn/memory_02.pdf}\vss} -\vskip-1cm -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{8pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/memory_02.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/memory_02.ys} -\end{columns} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The {\tt fsm} command} - -\begin{frame}[fragile]{\subsecname{}} -The {\tt fsm} command identifies, extracts, optimizes (re-encodes), and -re-synthesizes finite state machines. It again is a macro that calls -a series of other commands: - -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -fsm_detect # unless got option -nodetect -fsm_extract - -fsm_opt -clean -fsm_opt - -fsm_expand # if got option -expand -clean # if got option -expand -fsm_opt # if got option -expand - -fsm_recode # unless got option -norecode - -fsm_info - -fsm_export # if got option -export -fsm_map # unless got option -nomap -\end{lstlisting} -\end{frame} - -\begin{frame}{\subsecname{} -- details} -Some details on the most important commands from the {\tt fsm\_*} group: - -\bigskip -The {\tt fsm\_detect} command identifies FSM state registers and marks them -with the {\tt (* fsm\_encoding = "auto" *)} attribute, if they do not have the -{\tt fsm\_encoding} set already. Mark registers with {\tt (* fsm\_encoding = -"none" *)} to disable FSM optimization for a register. - -\bigskip -The {\tt fsm\_extract} command replaces the entire FSM (logic and state -registers) with a {\tt \$fsm} cell. - -\bigskip -The commands {\tt fsm\_opt} and {\tt fsm\_recode} can be used to optimize the -FSM. - -\bigskip -Finally the {\tt fsm\_map} command can be used to convert the (optimized) {\tt -\$fsm} cell back to logic and registers. -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The {\tt techmap} command} - -\begin{frame}[t]{\subsecname} -\vbox to 0cm{\includegraphics[width=12cm,trim=-15cm 0cm 0cm -20cm]{PRESENTATION_ExSyn/techmap_01.pdf}\vss} -\vskip-0.8cm -The {\tt techmap} command replaces cells with implementations given as -verilog source. For example implementing a 32 bit adder using 16 bit adders: - -\vbox to 0cm{ -\vskip-0.3cm -\lstinputlisting[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/techmap_01_map.v} -}\vbox to 0cm{ -\vskip-0.5cm -\lstinputlisting[xleftmargin=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, frame=single, language=verilog]{PRESENTATION_ExSyn/techmap_01.v} -\lstinputlisting[xleftmargin=5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/techmap_01.ys} -} -\end{frame} - -\begin{frame}[t]{\subsecname{} -- stdcell mapping} -When {\tt techmap} is used without a map file, it uses a built-in map file -to map all RTL cell types to a generic library of built-in logic gates and registers. - -\bigskip -\begin{block}{The built-in logic gate types are:} -{\tt \$\_NOT\_ \$\_AND\_ \$\_OR\_ \$\_XOR\_ \$\_MUX\_} -\end{block} - -\bigskip -\begin{block}{The register types are:} -{\tt \$\_SR\_NN\_ \$\_SR\_NP\_ \$\_SR\_PN\_ \$\_SR\_PP\_ \\ -\$\_DFF\_N\_ \$\_DFF\_P\_ \\ -\$\_DFF\_NN0\_ \$\_DFF\_NN1\_ \$\_DFF\_NP0\_ \$\_DFF\_NP1\_ \\ -\$\_DFF\_PN0\_ \$\_DFF\_PN1\_ \$\_DFF\_PP0\_ \$\_DFF\_PP1\_ \\ -\$\_DFFSR\_NNN\_ \$\_DFFSR\_NNP\_ \$\_DFFSR\_NPN\_ \$\_DFFSR\_NPP\_ \\ -\$\_DFFSR\_PNN\_ \$\_DFFSR\_PNP\_ \$\_DFFSR\_PPN\_ \$\_DFFSR\_PPP\_ \\ -\$\_DLATCH\_N\_ \$\_DLATCH\_P\_} -\end{block} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The {\tt abc} command} - -\begin{frame}{\subsecname} -The {\tt abc} command provides an interface to ABC\footnote[frame]{\url{http://www.eecs.berkeley.edu/~alanmi/abc/}}, -an open source tool for low-level logic synthesis. - -\medskip -The {\tt abc} command processes a netlist of internal gate types and can perform: -\begin{itemize} -\item logic minimization (optimization) -\item mapping of logic to standard cell library (liberty format) -\item mapping of logic to k-LUTs (for FPGA synthesis) -\end{itemize} - -\medskip -Optionally {\tt abc} can process registers from one clock domain and perform -sequential optimization (such as register balancing). - -\medskip -ABC is also controlled using scripts. An ABC script can be specified to use -more advanced ABC features. It is also possible to write the design with -{\tt write\_blif} and load the output file into ABC outside of Yosys. -\end{frame} - -\begin{frame}[fragile]{\subsecname{} -- Example} -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=verilog]{PRESENTATION_ExSyn/abc_01.v} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys, frame=single]{PRESENTATION_ExSyn/abc_01.ys} -\end{columns} -\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_ExSyn/abc_01.pdf} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Other special-purpose mapping commands} - -\begin{frame}{\subsecname} -\begin{block}{\tt dfflibmap} -This command maps the internal register cell types to the register types -described in a liberty file. -\end{block} - -\bigskip -\begin{block}{\tt hilomap} -Some architectures require special driver cells for driving a constant hi or lo -value. This command replaces simple constants with instances of such driver cells. -\end{block} - -\bigskip -\begin{block}{\tt iopadmap} -Top-level input/outputs must usually be implemented using special I/O-pad cells. -This command inserts this cells to the design. -\end{block} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Example Synthesis Script} - -\begin{frame}[fragile]{\subsecname} -\begin{columns} -\column[t]{4cm} -\begin{lstlisting}[basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont, language=ys] -# read and elaborate design -read_verilog cpu_top.v cpu_ctrl.v cpu_regs.v -read_verilog -D WITH_MULT cpu_alu.v -hierarchy -check -top cpu_top - -# high-level synthesis -proc; opt; fsm;; memory -nomap; opt - -# substitute block rams -techmap -map map_rams.v - -# map remaining memories -memory_map - -# low-level synthesis -techmap; opt; flatten;; abc -lut6 -techmap -map map_xl_cells.v - -# add clock buffers -select -set xl_clocks t:FDRE %x:+FDRE[C] t:FDRE %d -iopadmap -inpad BUFGP O:I @xl_clocks - -# add io buffers -select -set xl_nonclocks w:* t:BUFGP %x:+BUFGP[I] %d -iopadmap -outpad OBUF I:O -inpad IBUF O:I @xl_nonclocks - -# write synthesis results -write_edif synth.edif -\end{lstlisting} -\column[t]{6cm} -\vskip1cm -\begin{block}{Teaser / Outlook} -\small\parbox{6cm}{ -The weird {\tt select} expressions at the end of this script are discussed in -the next part (Section 3, ``Advanced Synthesis'') of this presentation.} -\end{block} -\end{columns} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Summary} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Yosys provides commands for each phase of the synthesis. -\item Each command solves a (more or less) simple problem. -\item Complex commands are often only front-ends to simple commands. -\item {\tt proc; opt; fsm; opt; memory; opt; techmap; opt; abc;;} -\end{itemize} - -\bigskip -\bigskip -\begin{center} -Questions? -\end{center} - -\bigskip -\bigskip -\begin{center} -\url{http://www.clifford.at/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_ExSyn/.gitignore b/yosys/manual/PRESENTATION_ExSyn/.gitignore deleted file mode 100644 index cf658897d..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dot diff --git a/yosys/manual/PRESENTATION_ExSyn/Makefile b/yosys/manual/PRESENTATION_ExSyn/Makefile deleted file mode 100644 index c34eae3ff..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/Makefile +++ /dev/null @@ -1,20 +0,0 @@ - -TARGETS += proc_01 proc_02 proc_03 -TARGETS += opt_01 opt_02 opt_03 opt_04 -TARGETS += memory_01 memory_02 -TARGETS += techmap_01 -TARGETS += abc_01 - -all: $(addsuffix .pdf,$(TARGETS)) - -define make_pdf_template -$(1).pdf: $(1)*.v $(1)*.ys - ../../yosys -p 'script $(1).ys; show -notitle -prefix $(1) -format pdf' -endef - -$(foreach trg,$(TARGETS),$(eval $(call make_pdf_template,$(trg)))) - -clean: - rm -f $(addsuffix .pdf,$(TARGETS)) - rm -f $(addsuffix .dot,$(TARGETS)) - diff --git a/yosys/manual/PRESENTATION_ExSyn/abc_01.v b/yosys/manual/PRESENTATION_ExSyn/abc_01.v deleted file mode 100644 index 3bc686353..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/abc_01.v +++ /dev/null @@ -1,10 +0,0 @@ -module test(input clk, a, b, c, - output reg y); - - reg [2:0] q1, q2; - always @(posedge clk) begin - q1 <= { a, b, c }; - q2 <= q1; - y <= ^q2; - end -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/abc_01.ys b/yosys/manual/PRESENTATION_ExSyn/abc_01.ys deleted file mode 100644 index bb0b3780f..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/abc_01.ys +++ /dev/null @@ -1,5 +0,0 @@ -read_verilog abc_01.v -read_verilog -lib abc_01_cells.v -hierarchy -check -top test -proc; opt; techmap -abc -dff -liberty abc_01_cells.lib;; diff --git a/yosys/manual/PRESENTATION_ExSyn/abc_01_cells.lib b/yosys/manual/PRESENTATION_ExSyn/abc_01_cells.lib deleted file mode 100644 index bf6b34788..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/abc_01_cells.lib +++ /dev/null @@ -1,54 +0,0 @@ -// test comment -/* test comment */ -library(demo) { - cell(BUF) { - area: 6; - pin(A) { direction: input; } - pin(Y) { direction: output; - function: "A"; } - } - cell(NOT) { - area: 3; - pin(A) { direction: input; } - pin(Y) { direction: output; - function: "A'"; } - } - cell(NAND) { - area: 4; - pin(A) { direction: input; } - pin(B) { direction: input; } - pin(Y) { direction: output; - function: "(A*B)'"; } - } - cell(NOR) { - area: 4; - pin(A) { direction: input; } - pin(B) { direction: input; } - pin(Y) { direction: output; - function: "(A+B)'"; } - } - cell(DFF) { - area: 18; - ff(IQ, IQN) { clocked_on: C; - next_state: D; } - pin(C) { direction: input; - clock: true; } - pin(D) { direction: input; } - pin(Q) { direction: output; - function: "IQ"; } - } - cell(DFFSR) { - area: 18; - ff(IQ, IQN) { clocked_on: C; - next_state: D; - preset: S; - clear: R; } - pin(C) { direction: input; - clock: true; } - pin(D) { direction: input; } - pin(Q) { direction: output; - function: "IQ"; } - pin(S) { direction: input; } - pin(R) { direction: input; } - } -} diff --git a/yosys/manual/PRESENTATION_ExSyn/abc_01_cells.v b/yosys/manual/PRESENTATION_ExSyn/abc_01_cells.v deleted file mode 100644 index 444094798..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/abc_01_cells.v +++ /dev/null @@ -1,40 +0,0 @@ - -module BUF(A, Y); -input A; -output Y = A; -endmodule - -module NOT(A, Y); -input A; -output Y = ~A; -endmodule - -module NAND(A, B, Y); -input A, B; -output Y = ~(A & B); -endmodule - -module NOR(A, B, Y); -input A, B; -output Y = ~(A | B); -endmodule - -module DFF(C, D, Q); -input C, D; -output reg Q; -always @(posedge C) - Q <= D; -endmodule - -module DFFSR(C, D, Q, S, R); -input C, D, S, R; -output reg Q; -always @(posedge C, posedge S, posedge R) - if (S) - Q <= 1'b1; - else if (R) - Q <= 1'b0; - else - Q <= D; -endmodule - diff --git a/yosys/manual/PRESENTATION_ExSyn/memory_01.v b/yosys/manual/PRESENTATION_ExSyn/memory_01.v deleted file mode 100644 index 0a3f9acd7..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/memory_01.v +++ /dev/null @@ -1,9 +0,0 @@ -module test(input CLK, ADDR, - input [7:0] DIN, - output reg [7:0] DOUT); - reg [7:0] mem [0:1]; - always @(posedge CLK) begin - mem[ADDR] <= DIN; - DOUT <= mem[ADDR]; - end -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/memory_01.ys b/yosys/manual/PRESENTATION_ExSyn/memory_01.ys deleted file mode 100644 index 2ffd8223a..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/memory_01.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog memory_01.v -hierarchy -check -top test -proc;; memory; opt diff --git a/yosys/manual/PRESENTATION_ExSyn/memory_02.v b/yosys/manual/PRESENTATION_ExSyn/memory_02.v deleted file mode 100644 index dbe86ed18..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/memory_02.v +++ /dev/null @@ -1,27 +0,0 @@ -module test( - input WR1_CLK, WR2_CLK, - input WR1_WEN, WR2_WEN, - input [7:0] WR1_ADDR, WR2_ADDR, - input [7:0] WR1_DATA, WR2_DATA, - input RD1_CLK, RD2_CLK, - input [7:0] RD1_ADDR, RD2_ADDR, - output reg [7:0] RD1_DATA, RD2_DATA -); - -reg [7:0] memory [0:255]; - -always @(posedge WR1_CLK) - if (WR1_WEN) - memory[WR1_ADDR] <= WR1_DATA; - -always @(posedge WR2_CLK) - if (WR2_WEN) - memory[WR2_ADDR] <= WR2_DATA; - -always @(posedge RD1_CLK) - RD1_DATA <= memory[RD1_ADDR]; - -always @(posedge RD2_CLK) - RD2_DATA <= memory[RD2_ADDR]; - -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/memory_02.ys b/yosys/manual/PRESENTATION_ExSyn/memory_02.ys deleted file mode 100644 index 9da6fda54..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/memory_02.ys +++ /dev/null @@ -1,4 +0,0 @@ -read_verilog memory_02.v -hierarchy -check -top test -proc;; memory -nomap -opt -mux_undef -mux_bool diff --git a/yosys/manual/PRESENTATION_ExSyn/opt_01.v b/yosys/manual/PRESENTATION_ExSyn/opt_01.v deleted file mode 100644 index 5d3c1ea49..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/opt_01.v +++ /dev/null @@ -1,3 +0,0 @@ -module test(input A, B, output Y); -assign Y = A ? A ? B : 1'b1 : B; -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/opt_01.ys b/yosys/manual/PRESENTATION_ExSyn/opt_01.ys deleted file mode 100644 index 34ed123be..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/opt_01.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog opt_01.v -hierarchy -check -top test -opt diff --git a/yosys/manual/PRESENTATION_ExSyn/opt_02.v b/yosys/manual/PRESENTATION_ExSyn/opt_02.v deleted file mode 100644 index 762fc1a89..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/opt_02.v +++ /dev/null @@ -1,3 +0,0 @@ -module test(input A, output Y, Z); -assign Y = A == A, Z = A != A; -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/opt_02.ys b/yosys/manual/PRESENTATION_ExSyn/opt_02.ys deleted file mode 100644 index fc92a636e..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/opt_02.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog opt_02.v -hierarchy -check -top test -opt diff --git a/yosys/manual/PRESENTATION_ExSyn/opt_03.v b/yosys/manual/PRESENTATION_ExSyn/opt_03.v deleted file mode 100644 index 134161bb8..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/opt_03.v +++ /dev/null @@ -1,4 +0,0 @@ -module test(input [3:0] A, B, - output [3:0] Y, Z); -assign Y = A + B, Z = B + A; -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/opt_03.ys b/yosys/manual/PRESENTATION_ExSyn/opt_03.ys deleted file mode 100644 index 282f06dde..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/opt_03.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog opt_03.v -hierarchy -check -top test -opt diff --git a/yosys/manual/PRESENTATION_ExSyn/opt_04.v b/yosys/manual/PRESENTATION_ExSyn/opt_04.v deleted file mode 100644 index 2ed447639..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/opt_04.v +++ /dev/null @@ -1,19 +0,0 @@ -module test(input CLK, ARST, - output [7:0] Q1, Q2, Q3); - -wire NO_CLK = 0; - -always @(posedge CLK, posedge ARST) - if (ARST) - Q1 <= 42; - -always @(posedge NO_CLK, posedge ARST) - if (ARST) - Q2 <= 42; - else - Q2 <= 23; - -always @(posedge CLK) - Q3 <= 42; - -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/opt_04.ys b/yosys/manual/PRESENTATION_ExSyn/opt_04.ys deleted file mode 100644 index f5ddae29f..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/opt_04.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog opt_04.v -hierarchy -check -top test -proc; opt diff --git a/yosys/manual/PRESENTATION_ExSyn/proc_01.v b/yosys/manual/PRESENTATION_ExSyn/proc_01.v deleted file mode 100644 index 612863195..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/proc_01.v +++ /dev/null @@ -1,7 +0,0 @@ -module test(input D, C, R, output reg Q); - always @(posedge C, posedge R) - if (R) - Q <= 0; - else - Q <= D; -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/proc_01.ys b/yosys/manual/PRESENTATION_ExSyn/proc_01.ys deleted file mode 100644 index c22a2fd5f..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/proc_01.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog proc_01.v -hierarchy -check -top test -proc;; diff --git a/yosys/manual/PRESENTATION_ExSyn/proc_02.v b/yosys/manual/PRESENTATION_ExSyn/proc_02.v deleted file mode 100644 index 8e440f6ce..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/proc_02.v +++ /dev/null @@ -1,8 +0,0 @@ -module test(input D, C, R, RV, - output reg Q); - always @(posedge C, posedge R) - if (R) - Q <= RV; - else - Q <= D; -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/proc_02.ys b/yosys/manual/PRESENTATION_ExSyn/proc_02.ys deleted file mode 100644 index 823b18d6e..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/proc_02.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog proc_02.v -hierarchy -check -top test -proc;; diff --git a/yosys/manual/PRESENTATION_ExSyn/proc_03.v b/yosys/manual/PRESENTATION_ExSyn/proc_03.v deleted file mode 100644 index a89c965e4..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/proc_03.v +++ /dev/null @@ -1,10 +0,0 @@ -module test(input A, B, C, D, E, - output reg Y); - always @* begin - Y <= A; - if (B) - Y <= C; - if (D) - Y <= E; - end -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/proc_03.ys b/yosys/manual/PRESENTATION_ExSyn/proc_03.ys deleted file mode 100644 index 3e7e6ddae..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/proc_03.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog proc_03.v -hierarchy -check -top test -proc;; diff --git a/yosys/manual/PRESENTATION_ExSyn/techmap_01.v b/yosys/manual/PRESENTATION_ExSyn/techmap_01.v deleted file mode 100644 index c53ca91a8..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/techmap_01.v +++ /dev/null @@ -1,4 +0,0 @@ -module test(input [31:0] a, b, - output [31:0] y); -assign y = a + b; -endmodule diff --git a/yosys/manual/PRESENTATION_ExSyn/techmap_01.ys b/yosys/manual/PRESENTATION_ExSyn/techmap_01.ys deleted file mode 100644 index 8ef9de222..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/techmap_01.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog techmap_01.v -hierarchy -check -top test -techmap -map techmap_01_map.v;; diff --git a/yosys/manual/PRESENTATION_ExSyn/techmap_01_map.v b/yosys/manual/PRESENTATION_ExSyn/techmap_01_map.v deleted file mode 100644 index 4fd86e854..000000000 --- a/yosys/manual/PRESENTATION_ExSyn/techmap_01_map.v +++ /dev/null @@ -1,24 +0,0 @@ -module \$add (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -generate - if ((A_WIDTH == 32) && (B_WIDTH == 32)) - begin - wire [16:0] S1 = A[15:0] + B[15:0]; - wire [15:0] S2 = A[31:16] + B[31:16] + S1[16]; - assign Y = {S2[15:0], S1[15:0]}; - end - else - wire _TECHMAP_FAIL_ = 1; -endgenerate - -endmodule diff --git a/yosys/manual/PRESENTATION_Intro.tex b/yosys/manual/PRESENTATION_Intro.tex deleted file mode 100644 index 555ec9175..000000000 --- a/yosys/manual/PRESENTATION_Intro.tex +++ /dev/null @@ -1,956 +0,0 @@ - -\section{Introduction to Yosys} - -\begin{frame} -\sectionpage -\end{frame} - -\iffalse -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Representations of (digital) Circuits} - -\begin{frame}[t]{\subsecname} -\begin{itemize} - \item Graphical - \begin{itemize} - \item \alert<1>{Schematic Diagram} - \item \alert<2>{Physical Layout} - \end{itemize} - \bigskip - \item Non-graphical - \begin{itemize} - \item \alert<3>{Netlists} - \item \alert<4>{Hardware Description Languages (HDLs)} - \end{itemize} -\end{itemize} -\bigskip -\begin{block}{Definition: -\only<1>{Schematic Diagram}% -\only<2>{Physical Layout}% -\only<3>{Netlists}% -\only<4>{Hardware Description Languages (HDLs)}} -\only<1>{ - Graphical representation of the circuit topology. Circuit elements - are represented by symbols and electrical connections by lines. The geometric - layout is for readability only. -}% -\only<2>{ - The actual physical geometry of the device (PCB or ASIC manufacturing masks). - This is the final product of the design process. -}% -\only<3>{ - A list of circuit elements and a list of connections. This is the raw circuit - topology. -}% -\only<4>{ - Computer languages (like programming languages) that can be used to describe - circuits. HDLs are much more powerful in describing huge circuits than - schematic diagrams. -}% -\end{block} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\fi - -\subsection{Levels of Abstraction for Digital Circuits} - -\begin{frame}[t]{\subsecname} -\begin{itemize} - \item \alert<1>{System Level} - \item \alert<2>{High Level} - \item \alert<3>{Behavioral Level} - \item \alert<4>{Register-Transfer Level (RTL)} - \item \alert<5>{Logical Gate Level} - \item \alert<6>{Physical Gate Level} - \item \alert<7>{Switch Level} -\end{itemize} -\bigskip -\begin{block}{Definition: -\only<1>{System Level}% -\only<2>{High Level}% -\only<3>{Behavioral Level}% -\only<4>{Register-Transfer Level (RTL)}% -\only<5>{Logical Gate Level}% -\only<6>{Physical Gate Level}% -\only<7>{Switch Level}} -\only<1>{ - Overall view of the circuit. E.g. block-diagrams or instruction-set architecture descriptions. -}% -\only<2>{ - Functional implementation of circuit in high-level programming language (C, C++, SystemC, Matlab, Python, etc.). -}% -\only<3>{ - Cycle-accurate description of circuit in hardware description language (Verilog, VHDL, etc.). -}% -\only<4>{ - List of registers (flip-flops) and logic functions that calculate the next state from the previous one. Usually - a netlist utilizing high-level cells such as adders, multipliers, multiplexer, etc. -}% -\only<5>{ - Netlist of single-bit registers and basic logic gates (such as AND, OR, - NOT, etc.). Popular form: And-Inverter-Graphs (AIGs) with pairs of primary - inputs and outputs for each register bit. -}% -\only<6>{ - Netlist of cells that actually are available on the target architecture - (such as CMOS gates in an ASIC or LUTs in an FPGA). Optimized for - area, power, and/or speed (static timing or number of logic levels). -}% -\only<7>{ - Netlist of individual transistors. -}% -\end{block} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Digital Circuit Synthesis} - -\begin{frame}{\subsecname} - Synthesis Tools (such as Yosys) can transform HDL code to circuits: - - \bigskip - \begin{center} - \begin{tikzpicture}[scale=0.8, every node/.style={transform shape}] - \tikzstyle{lvl} = [draw, fill=MyBlue, rectangle, minimum height=2em, minimum width=15em] - \node[lvl] (sys) {System Level}; - \node[lvl] (hl) [below of=sys] {High Level}; - \node[lvl] (beh) [below of=hl] {Behavioral Level}; - \node[lvl] (rtl) [below of=beh] {Register-Transfer Level (RTL)}; - \node[lvl] (lg) [below of=rtl] {Logical Gate Level}; - \node[lvl] (pg) [below of=lg] {Physical Gate Level}; - \node[lvl] (sw) [below of=pg] {Switch Level}; - - \draw[dotted] (sys.east) -- ++(1,0) coordinate (sysx); - \draw[dotted] (hl.east) -- ++(1,0) coordinate (hlx); - \draw[dotted] (beh.east) -- ++(1,0) coordinate (behx); - \draw[dotted] (rtl.east) -- ++(1,0) coordinate (rtlx); - \draw[dotted] (lg.east) -- ++(1,0) coordinate (lgx); - \draw[dotted] (pg.east) -- ++(1,0) coordinate (pgx); - \draw[dotted] (sw.east) -- ++(1,0) coordinate (swx); - - \draw[gray,|->] (sysx) -- node[right] {System Design} (hlx); - \draw[|->|] (hlx) -- node[right] {High Level Synthesis (HLS)} (behx); - \draw[->|] (behx) -- node[right] {Behavioral Synthesis} (rtlx); - \draw[->|] (rtlx) -- node[right] {RTL Synthesis} (lgx); - \draw[->|] (lgx) -- node[right] {Logic Synthesis} (pgx); - \draw[gray,->|] (pgx) -- node[right] {Cell Library} (swx); - - \draw[dotted] (behx) -- ++(4,0) coordinate (a); - \draw[dotted] (pgx) -- ++(4,0) coordinate (b); - \draw[|->|] (a) -- node[right] {Yosys} (b); - \end{tikzpicture} - \end{center} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{What Yosys can and can't do} - -\begin{frame}{\subsecname} - -Things Yosys can do: -\begin{itemize} -\item Read and process (most of) modern Verilog-2005 code. -\item Perform all kinds of operations on netlist (RTL, Logic, Gate). -\item Perform logic optimizations and gate mapping with ABC\footnote[frame]{\url{http://www.eecs.berkeley.edu/~alanmi/abc/}}. -\end{itemize} - -\bigskip -Things Yosys can't do: -\begin{itemize} -\item Process high-level languages such as C/C++/SystemC. -\item Create physical layouts (place\&route). -\end{itemize} - -\bigskip -A typical flow combines Yosys with with a low-level implementation tool, such -as Qflow\footnote[frame]{\url{http://opencircuitdesign.com/qflow/}} for ASIC designs. - -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Yosys Data- and Control-Flow} - -\begin{frame}{\subsecname} - A (usually short) synthesis script controls Yosys. - - This scripts contain three types of commands: - \begin{itemize} - \item {\bf Frontends}, that read input files (usually Verilog). - \item {\bf Passes}, that perform transformations on the design in memory. - \item {\bf Backends}, that write the design in memory to a file (various formats are available: Verilog, BLIF, EDIF, SPICE, BTOR, \dots). - \end{itemize} - - \bigskip - \begin{center} - \begin{tikzpicture}[scale=0.6, every node/.style={transform shape}] - \path (-1.5,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=orange!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Frontend} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=green!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Pass} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=green!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Pass} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=green!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Pass} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - \draw[fill=orange!10] ($ (cursor) + (1,-3) $) rectangle node[rotate=90] {Backend} ++(1,3) coordinate (cursor); - \draw[-latex] ($ (cursor) + (0,-1.5) $) -- ++(1,0); - - \path (-3,-0.5) coordinate (cursor); - \draw (cursor) -- node[below] {HDL} ++(3,0) coordinate (cursor); - \draw[|-|] (cursor) -- node[below] {Internal Format (RTLIL)} ++(8,0) coordinate (cursor); - \draw (cursor) -- node[below] {Netlist} ++(3,0); - - \path (-3,3.5) coordinate (cursor); - \draw[-] (cursor) -- node[above] {High-Level} ++(3,0) coordinate (cursor); - \draw[-] (cursor) -- ++(8,0) coordinate (cursor); - \draw[->] (cursor) -- node[above] {Low-Level} ++(3,0); - \end{tikzpicture} - \end{center} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Program Components and Data Formats} - -\begin{frame}{\subsecname} - \begin{center} - \begin{tikzpicture}[scale=0.6, every node/.style={transform shape}] - \tikzstyle{process} = [draw, fill=green!10, rectangle, minimum height=3em, minimum width=10em, node distance=15em] - \tikzstyle{data} = [draw, fill=blue!10, ellipse, minimum height=3em, minimum width=7em, node distance=15em] - \node[process] (vlog) {Verilog Frontend}; - \node[process, dashed, fill=green!5] (vhdl) [right of=vlog] {VHDL Frontend}; - \node[process] (ilang) [right of=vhdl] {Other Frontends}; - \node[data] (ast) [below of=vlog, node distance=5em, xshift=7.5em] {AST}; - \node[process] (astfe) [below of=ast, node distance=5em] {AST Frontend}; - \node[data] (rtlil) [below of=astfe, node distance=5em, xshift=7.5em] {RTLIL}; - \node[process] (pass) [right of=rtlil, node distance=5em, xshift=7.5em] {Passes}; - \node[process] (vlbe) [below of=rtlil, node distance=7em, xshift=-13em] {Verilog Backend}; - \node[process] (ilangbe) [below of=rtlil, node distance=7em, xshift=0em] {ILANG Backend}; - \node[process, fill=green!5] (otherbe) [below of=rtlil, node distance=7em, xshift=+13em] {Other Backends}; - - \draw[-latex] (vlog) -- (ast); - \draw[-latex] (vhdl) -- (ast); - \draw[-latex] (ast) -- (astfe); - \draw[-latex] (astfe) -- (rtlil); - \draw[-latex] (ilang) -- (rtlil); - \draw[latex-latex] (rtlil) -- (pass); - \draw[-latex] (rtlil) -- (vlbe); - \draw[-latex] (rtlil) -- (ilangbe); - \draw[-latex] (rtlil) -- (otherbe); - \end{tikzpicture} - \end{center} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Example Project} - -\begin{frame}[t]{\subsecname} -The following slides cover an example project. This project contains three files: -\begin{itemize} -\item A simple ASIC synthesis script -\item A digital design written in Verilog -\item A simple CMOS cell library -\end{itemize} -\vfill -Direct link to the files: \\ \footnotesize -\url{https://github.com/cliffordwolf/yosys/tree/master/manual/PRESENTATION_Intro} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\begin{frame}[t]{\subsecname{} -- Synthesis Script} - -\setbeamercolor{alerted text}{fg=white,bg=red} - -\begin{minipage}[t]{6cm} -\tt\scriptsize -{\color{YosysGreen}\# read design}\\ -\boxalert<1>{read\_verilog counter.v}\\ -\boxalert<2>{hierarchy -check -top counter} - -\medskip -{\color{YosysGreen}\# the high-level stuff}\\ -\boxalert<3>{proc}; \boxalert<4>{opt}; \boxalert<5>{fsm}; \boxalert<6>{opt}; \boxalert<7>{memory}; \boxalert<8>{opt} - -\medskip -{\color{YosysGreen}\# mapping to internal cell library}\\ -\boxalert<9>{techmap}; \boxalert<10>{opt} -\end{minipage} -\begin{minipage}[t]{5cm} -\tt\scriptsize -{\color{YosysGreen}\# mapping flip-flops to mycells.lib}\\ -\boxalert<11>{dfflibmap -liberty mycells.lib} - -\medskip -{\color{YosysGreen}\# mapping logic to mycells.lib}\\ -\boxalert<12>{abc -liberty mycells.lib} - -\medskip -{\color{YosysGreen}\# cleanup}\\ -\boxalert<13>{clean} - -\medskip -{\color{YosysGreen}\# write synthesized design}\\ -\boxalert<14>{write\_verilog synth.v} -\end{minipage} - -\vskip1cm - -\begin{block}{Command: \tt -\only<1>{read\_verilog counter.v}% -\only<2>{hierarchy -check -top counter}% -\only<3>{proc}% -\only<4>{opt}% -\only<5>{fsm}% -\only<6>{opt}% -\only<7>{memory}% -\only<8>{opt}% -\only<9>{techmap}% -\only<10>{opt}% -\only<11>{dfflibmap -liberty mycells.lib}% -\only<12>{abc -liberty mycells.lib}% -\only<13>{clean}% -\only<14>{write\_verilog synth.v}} -\only<1>{ - Read Verilog source file and convert to internal representation. -}% -\only<2>{ - Elaborate the design hierarchy. Should always be the first - command after reading the design. Can re-run AST front-end. -}% -\only<3>{ - Convert ``processes'' (the internal representation of behavioral - Verilog code) into multiplexers and registers. -}% -\only<4>{ - Perform some basic optimizations and cleanups. -}% -\only<5>{ - Analyze and optimize finite state machines. -}% -\only<6>{ - Perform some basic optimizations and cleanups. -}% -\only<7>{ - Analyze memories and create circuits to implement them. -}% -\only<8>{ - Perform some basic optimizations and cleanups. -}% -\only<9>{ - Map coarse-grain RTL cells (adders, etc.) to fine-grain - logic gates (AND, OR, NOT, etc.). -}% -\only<10>{ - Perform some basic optimizations and cleanups. -}% -\only<11>{ - Map registers to available hardware flip-flops. -}% -\only<12>{ - Map logic to available hardware gates. -}% -\only<13>{ - Clean up the design (just the last step of {\tt opt}). -}% -\only<14>{ - Write final synthesis result to output file. -}% -\end{block} - -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\begin{frame}[fragile]{\subsecname{} -- Verilog Source: \tt counter.v} -\lstinputlisting[xleftmargin=1cm, language=Verilog]{PRESENTATION_Intro/counter.v} -\end{frame} - -\begin{frame}[fragile]{\subsecname{} -- Cell Library: \tt mycells.lib} -\begin{columns} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=liberty, lastline=20]{PRESENTATION_Intro/mycells.lib} -\column[t]{5cm} -\lstinputlisting[basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=liberty, firstline=21]{PRESENTATION_Intro/mycells.lib} -\end{columns} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Running the Synthesis Script} - -\begin{frame}[t, fragile]{\subsecname{} -- Step 1/4} -\begin{verbatim} -read_verilog counter.v -hierarchy -check -top counter -\end{verbatim} - -\vfill -\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_Intro/counter_00.pdf} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Step 2/4} -\begin{verbatim} -proc; opt; fsm; opt; memory; opt -\end{verbatim} - -\vfill -\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_Intro/counter_01.pdf} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Step 3/4} -\begin{verbatim} -techmap; opt -\end{verbatim} - -\vfill -\includegraphics[width=\linewidth,trim=0 0cm 0 2cm]{PRESENTATION_Intro/counter_02.pdf} -\end{frame} - -\begin{frame}[t, fragile]{\subsecname{} -- Step 4/4} -\begin{verbatim} -dfflibmap -liberty mycells.lib -abc -liberty mycells.lib -clean -\end{verbatim} - -\vfill\hfil -\includegraphics[width=10cm,trim=0 0cm 0 0cm]{PRESENTATION_Intro/counter_03.pdf} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The synth command} - -\begin{frame}[fragile]{\subsecname{}} -Yosys contains a default (recommended example) synthesis script in form of the -{\tt synth} command. The following commands are executed by this synthesis command: - -\begin{columns} -\column[t]{5cm} -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -begin: - hierarchy -check [-top ] - -coarse: - proc - opt - wreduce - alumacc - share - opt - fsm - opt -fast - memory -nomap - opt_clean -\end{lstlisting} -\column[t]{5cm} -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] -fine: - opt -fast -full - memory_map - opt -full - techmap - opt -fast - -abc: - abc -fast - opt -fast -\end{lstlisting} -\end{columns} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Yosys Commands} - -\begin{frame}[fragile]{\subsecname{} 1/3 \hspace{0pt plus 1 filll} (excerpt)} -Command reference: -\begin{itemize} -\item Use ``{\tt help}'' for a command list and ``{\tt help \it command}'' for details. -\item Or run ``{\tt yosys -H}'' or ``{\tt yosys -h \it command}''. -\item Or go to \url{http://www.clifford.at/yosys/documentation.html}. -\end{itemize} - -\bigskip -Commands for design navigation and investigation: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - cd # a shortcut for 'select -module ' - ls # list modules or objects in modules - dump # print parts of the design in ilang format - show # generate schematics using graphviz - select # modify and view the list of selected objects -\end{lstlisting} - -\bigskip -Commands for executing scripts or entering interactive mode: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - shell # enter interactive command mode - history # show last interactive commands - script # execute commands from script file - tcl # execute a TCL script file -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile]{\subsecname{} 2/3 \hspace{0pt plus 1 filll} (excerpt)} -Commands for reading and elaborating the design: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - read_ilang # read modules from ilang file - read_verilog # read modules from Verilog file - hierarchy # check, expand and clean up design hierarchy -\end{lstlisting} - -\bigskip -Commands for high-level synthesis: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - proc # translate processes to netlists - fsm # extract and optimize finite state machines - memory # translate memories to basic cells - opt # perform simple optimizations -\end{lstlisting} - -\bigskip -Commands for technology mapping: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - techmap # generic technology mapper - abc # use ABC for technology mapping - dfflibmap # technology mapping of flip-flops - hilomap # technology mapping of constant hi- and/or lo-drivers - iopadmap # technology mapping of i/o pads (or buffers) - flatten # flatten design -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile]{\subsecname{} 3/3 \hspace{0pt plus 1 filll} (excerpt)} -Commands for writing the results: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - write_blif # write design to BLIF file - write_btor # write design to BTOR file - write_edif # write design to EDIF netlist file - write_ilang # write design to ilang file - write_spice # write design to SPICE netlist file - write_verilog # write design to Verilog file -\end{lstlisting} - -\bigskip -Script-Commands for standard synthesis tasks: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - synth # generic synthesis script - synth_xilinx # synthesis for Xilinx FPGAs -\end{lstlisting} - -\bigskip -Commands for model checking: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] - sat # solve a SAT problem in the circuit - miter # automatically create a miter circuit - scc # detect strongly connected components (logic loops) -\end{lstlisting} - -\bigskip -... and many many more. -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{More Verilog Examples} - -\begin{frame}[fragile]{\subsecname{} 1/3} -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog] -module detectprime(a, y); - input [4:0] a; - output y; - - integer i, j; - reg [31:0] lut; - - initial begin - for (i = 0; i < 32; i = i+1) begin - lut[i] = i > 1; - for (j = 2; j*j <= i; j = j+1) - if (i % j == 0) - lut[i] = 0; - end - end - - assign y = lut[a]; -endmodule -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile]{\subsecname{} 2/3} -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog] -module carryadd(a, b, y); - parameter WIDTH = 8; - input [WIDTH-1:0] a, b; - output [WIDTH-1:0] y; - - genvar i; - generate - for (i = 0; i < WIDTH; i = i+1) begin:STAGE - wire IN1 = a[i], IN2 = b[i]; - wire C, Y; - if (i == 0) - assign C = IN1 & IN2, Y = IN1 ^ IN2; - else - assign C = (IN1 & IN2) | ((IN1 | IN2) & STAGE[i-1].C), - Y = IN1 ^ IN2 ^ STAGE[i-1].C; - assign y[i] = Y; - end - endgenerate -endmodule -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile]{\subsecname{} 3/3} -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{7pt}{8.5pt}\selectfont, language=Verilog] -module cam(clk, wr_enable, wr_addr, wr_data, rd_data, rd_addr, rd_match); - parameter WIDTH = 8; - parameter DEPTH = 16; - localparam ADDR_BITS = $clog2(DEPTH-1); - - input clk, wr_enable; - input [ADDR_BITS-1:0] wr_addr; - input [WIDTH-1:0] wr_data, rd_data; - output reg [ADDR_BITS-1:0] rd_addr; - output reg rd_match; - - integer i; - reg [WIDTH-1:0] mem [0:DEPTH-1]; - - always @(posedge clk) begin - rd_addr <= 'bx; - rd_match <= 0; - for (i = 0; i < DEPTH; i = i+1) - if (mem[i] == rd_data) begin - rd_addr <= i; - rd_match <= 1; - end - if (wr_enable) - mem[wr_addr] <= wr_data; - end -endmodule -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Currently unsupported Verilog-2005 language features} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Tri-state logic -\item The wor/wand wire types (maybe for 0.5) -\item Latched logic (is synthesized as logic with feedback loops) -\item Some non-synthesizable features that should be ignored in synthesis are not supported by the parser and cause a parser error (file a bug report if you encounter this problem) -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Verification of Yosys} - -\begin{frame}{\subsecname} -Continuously checking the correctness of Yosys and making sure that new features -do not break old ones is a high priority in Yosys. - -\bigskip -Two external test suites have been built for Yosys: VlogHammer and yosys-bigsim -(see next slides) - -\bigskip -In addition to that, yosys comes with $\approx\!200$ test cases used in ``{\tt make test}''. - -\bigskip -A debug build of Yosys also contains a lot of asserts and checks the integrity of -the internal state after each command. -\end{frame} - -\begin{frame}[fragile]{\subsecname{} -- VlogHammer} -VlogHammer is a Verilog regression test suite developed to test the different -subsystems in Yosys by comparing them to each other and to the output created -by some other tools (Xilinx Vivado, Xilinx XST, Altera Quartus II, ...). - -\bigskip -Yosys Subsystems tested: Verilog frontend, const folding, const eval, technology mapping, -simulation models, SAT models. - -\bigskip -Thousands of auto-generated test cases containing code such as: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog] -assign y9 = $signed(((+$signed((^(6'd2 ** a2))))<$unsigned($unsigned(((+a3)))))); -assign y10 = (-((+((+{2{(~^p13)}})))^~(!{{b5,b1,a0},(a1&p12),(a4+a3)}))); -assign y11 = (~&(-{(-3'sd3),($unsigned($signed($unsigned({p0,b4,b1}))))})); -\end{lstlisting} - -\bigskip -Some bugs in Yosys where found and fixed thanks to VlogHammer. Over 50 bugs in -the other tools used as external reference where found and reported so far. -\end{frame} - -\begin{frame}{\subsecname{} -- yosys-bigsim} -yosys-bigsim is a collection of real-world open-source Verilog designs and test -benches. yosys-bigsim compares the testbench outputs of simulations of the original -Verilog code and synthesis results. - -\bigskip -The following designs are included in yosys-bigsim (excerpt): -\begin{itemize} -\item {\tt openmsp430} -- an MSP430 compatible 16 bit CPU -\item {\tt aes\_5cycle\_2stage} -- an AES encryption core -\item {\tt softusb\_navre} -- an AVR compatible 8 bit CPU -\item {\tt amber23} -- an ARMv2 compatible 32 bit CPU -\item {\tt lm32} -- another 32 bit CPU from Lattice Semiconductor -\item {\tt verilog-pong} -- a hardware pong game with VGA output -\item {\tt elliptic\_curve\_group} -- ECG point-add and point-scalar-mul core -\item {\tt reed\_solomon\_decoder} -- a Reed-Solomon Error Correction Decoder -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Benefits of Open Source HDL Synthesis} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Cost (also applies to ``free as in free beer'' solutions) -\item Availability and Reproducibility -\item Framework- and all-in-one-aspects -\item Educational Tool -\end{itemize} - -\bigskip - -Yosys is open source under the ISC license. -\end{frame} - -\begin{frame}{\subsecname{} -- 1/3} -\begin{itemize} -\item Cost (also applies to ``free as in free beer'' solutions): \smallskip\par -Today the cost for a mask set in $\unit[180]{nm}$ technology is far less than -the cost for the design tools needed to design the mask layouts. Open Source -ASIC flows are an important enabler for ASIC-level Open Source Hardware. - -\bigskip -\item Availability and Reproducibility: \smallskip\par -If you are a researcher who is publishing, you want to use tools that everyone -else can also use. Even if most universities have access to all major -commercial tools, you usually do not have easy access to the version that was -used in a research project a couple of years ago. With Open Source tools you -can even release the source code of the tool you have used alongside your data. -\end{itemize} -\end{frame} - -\begin{frame}{\subsecname{} -- 2/3} -\begin{itemize} -\item Framework: \smallskip\par -Yosys is not only a tool. It is a framework that can be used as basis for other -developments, so researchers and hackers alike do not need to re-invent the -basic functionality. Extensibility was one of Yosys' design goals. - -\bigskip -\item All-in-one: \smallskip\par -Because of the framework characteristics of Yosys, an increasing number of features -become available in one tool. Yosys not only can be used for circuit synthesis but -also for formal equivalence checking, SAT solving, and for circuit analysis, to -name just a few other application domains. With proprietary software one needs to -learn a new tool for each of these applications. -\end{itemize} -\end{frame} - -\begin{frame}{\subsecname{} -- 3/3} -\begin{itemize} -\item Educational Tool: \smallskip\par -Proprietary synthesis tools are at times very secretive about their inner -workings. They often are ``black boxes''. Yosys is very open about its -internals and it is easy to observe the different steps of synthesis. -\end{itemize} - -\bigskip -\begin{block}{Yosys is licensed under the ISC license:} -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. -\end{block} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Typical Applications for Yosys} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Synthesis of final production designs -\item Pre-production synthesis (trial runs before investing in other tools) -\item Conversion of full-featured Verilog to simple Verilog -\item Conversion of Verilog to other formats (BLIF, BTOR, etc) -\item Demonstrating synthesis algorithms (e.g. for educational purposes) -\item Framework for experimenting with new algorithms -\item Framework for building custom flows\footnote[frame]{Not limited to synthesis -but also formal verification, reverse engineering, ...} -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Projects (that I know of) using Yosys} - -\begin{frame}{\subsecname{} -- (1/2)} -\begin{itemize} -\item Ongoing PhD project on coarse grain synthesis \\ -{\setlength{\parindent}{0.5cm}\footnotesize -Johann Glaser and Clifford Wolf. Methodology and Example-Driven Interconnect -Synthesis for Designing Heterogeneous Coarse-Grain Reconfigurable -Architectures. In Jan Haase, editor, \it Models, Methods, and Tools for Complex -Chip Design. Lecture Notes in Electrical Engineering. Volume 265, 2014, pp -201-221. Springer, 2013.} - -\bigskip -\item I know several people that use Yosys simply as Verilog frontend for other -flows (using either the BLIF and BTOR backends). - -\bigskip -\item I know some analog chip designers that use Yosys for small digital -control logic because it is simpler than setting up a commercial flow. -\end{itemize} -\end{frame} - -\begin{frame}{\subsecname{} -- (2/2)} -\begin{itemize} -\item Efabless -\begin{itemize} -\smallskip \item Not much information on the website (\url{http://efabless.com}) yet. -\smallskip \item Very cheap 180nm prototyping process (partnering with various fabs) -\smallskip \item A semiconductor company, NOT an EDA company -\smallskip \item Web-based design environment -\smallskip \item HDL Synthesis using Yosys -\smallskip \item Custom place\&route tool - -\bigskip -\item efabless is building an Open Source IC as reference design. \\ -\hskip1cm (to be announced soon: \url{http://www.openic.io}) -\end{itemize} -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Supported Platforms} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Main development OS: Kubuntu 14.04 -\item There is a PPA for ubuntu (not maintained by me) -\item Any current Debian-based system should work out of the box -\item When building on other Linux distributions: -\begin{itemize} -\item Needs compiler with some C++11 support -\item See README file for build instructions -\item Post to the subreddit if you get stuck -\end{itemize} -\item Ported to OS X (Darwin) and OpenBSD -\item Native win32 build with VisualStudio -\item Cross win32 build with MXE -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Other Open Source Tools} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Icarus Verilog \\ -\smallskip\hskip1cm{}Verilog Simulation (and also a good syntax checker) \\ -\smallskip\hskip1cm{}\url{http://iverilog.icarus.com/} - -\bigskip -\item Qflow (incl. TimberWolf, qrouter and Magic) \\ -\smallskip\hskip1cm{}A complete ASIC synthesis flow, using Yosys and ABC \\ -\smallskip\hskip1cm{}\url{http://opencircuitdesign.com/qflow/} - -\bigskip -\item ABC \\ -\smallskip\hskip1cm{}Logic optimization, technology mapping, and more \\ -\smallskip\hskip1cm{}\url{http://www.eecs.berkeley.edu/~alanmi/abc/} -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Yosys needs you} - -\begin{frame}{\subsecname} -\dots as an active user: -\begin{itemize} -\item Use Yosys for on your own projects -\item .. even if you are not using it as final synthesis tool -\item Join the discussion on the Subreddit -\item Report bugs and send in feature requests -\end{itemize} - -\bigskip -\dots as a developer: -\begin{itemize} -\item Use Yosys as environment for your (research) work -\item .. you might also want to look into ABC for logic-level stuff -\item Fork the project on github or create loadable plugins -\item We need a VHDL frontend or a good VHDL-to-Verilog converter -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Documentation, Downloads, Contacts} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Website: \\ -\smallskip\hskip1cm\url{http://www.clifford.at/yosys/} - -\bigskip -\item Manual, Command Reference, Application Notes: \\ -\smallskip\hskip1cm\url{http://www.clifford.at/yosys/documentation.html} - -\bigskip -\item Instead of a mailing list we have a SubReddit: \\ -\smallskip\hskip1cm\url{http://www.reddit.com/r/yosys/} - -\bigskip -\item Direct link to the source code: \\ -\smallskip\hskip1cm\url{https://github.com/cliffordwolf/yosys} -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Summary} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Yosys is a powerful tool and framework for Verilog synthesis. -\item It uses a command-based interface and can be controlled by scripts. -\item By combining existing commands and implementing new commands Yosys can -be used in a wide range of application far beyond simple synthesis. -\end{itemize} - -\bigskip -\bigskip -\begin{center} -Questions? -\end{center} - -\bigskip -\bigskip -\begin{center} -\url{http://www.clifford.at/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_Intro/.gitignore b/yosys/manual/PRESENTATION_Intro/.gitignore deleted file mode 100644 index d0c4618ac..000000000 --- a/yosys/manual/PRESENTATION_Intro/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -counter_00.dot -counter_01.dot -counter_02.dot -counter_03.dot diff --git a/yosys/manual/PRESENTATION_Intro/Makefile b/yosys/manual/PRESENTATION_Intro/Makefile deleted file mode 100644 index abc354e46..000000000 --- a/yosys/manual/PRESENTATION_Intro/Makefile +++ /dev/null @@ -1,10 +0,0 @@ - -all: counter_00.pdf counter_01.pdf counter_02.pdf counter_03.pdf - -counter_00.pdf: counter.v counter.ys mycells.lib - ../../yosys counter.ys - -counter_01.pdf: counter_00.pdf -counter_02.pdf: counter_00.pdf -counter_03.pdf: counter_00.pdf - diff --git a/yosys/manual/PRESENTATION_Intro/counter.v b/yosys/manual/PRESENTATION_Intro/counter.v deleted file mode 100644 index 36b878e31..000000000 --- a/yosys/manual/PRESENTATION_Intro/counter.v +++ /dev/null @@ -1,12 +0,0 @@ -module counter (clk, rst, en, count); - - input clk, rst, en; - output reg [1:0] count; - - always @(posedge clk) - if (rst) - count <= 2'd0; - else if (en) - count <= count + 2'd1; - -endmodule diff --git a/yosys/manual/PRESENTATION_Intro/counter.ys b/yosys/manual/PRESENTATION_Intro/counter.ys deleted file mode 100644 index cc4e7cd31..000000000 --- a/yosys/manual/PRESENTATION_Intro/counter.ys +++ /dev/null @@ -1,27 +0,0 @@ -# read design -read_verilog counter.v -hierarchy -check -top counter - -show -notitle -stretch -format pdf -prefix counter_00 - -# the high-level stuff -proc; opt; memory; opt; fsm; opt - -show -notitle -stretch -format pdf -prefix counter_01 - -# mapping to internal cell library -techmap; opt - -splitnets -ports;; -show -notitle -stretch -format pdf -prefix counter_02 - -# mapping flip-flops to mycells.lib -dfflibmap -liberty mycells.lib - -# mapping logic to mycells.lib -abc -liberty mycells.lib - -# cleanup -clean - -show -notitle -stretch -lib mycells.v -format pdf -prefix counter_03 diff --git a/yosys/manual/PRESENTATION_Intro/mycells.lib b/yosys/manual/PRESENTATION_Intro/mycells.lib deleted file mode 100644 index a0204d7e1..000000000 --- a/yosys/manual/PRESENTATION_Intro/mycells.lib +++ /dev/null @@ -1,38 +0,0 @@ -library(demo) { - cell(BUF) { - area: 6; - pin(A) { direction: input; } - pin(Y) { direction: output; - function: "A"; } - } - cell(NOT) { - area: 3; - pin(A) { direction: input; } - pin(Y) { direction: output; - function: "A'"; } - } - cell(NAND) { - area: 4; - pin(A) { direction: input; } - pin(B) { direction: input; } - pin(Y) { direction: output; - function: "(A*B)'"; } - } - cell(NOR) { - area: 4; - pin(A) { direction: input; } - pin(B) { direction: input; } - pin(Y) { direction: output; - function: "(A+B)'"; } - } - cell(DFF) { - area: 18; - ff(IQ, IQN) { clocked_on: C; - next_state: D; } - pin(C) { direction: input; - clock: true; } - pin(D) { direction: input; } - pin(Q) { direction: output; - function: "IQ"; } - } -} diff --git a/yosys/manual/PRESENTATION_Intro/mycells.v b/yosys/manual/PRESENTATION_Intro/mycells.v deleted file mode 100644 index 802f58718..000000000 --- a/yosys/manual/PRESENTATION_Intro/mycells.v +++ /dev/null @@ -1,23 +0,0 @@ - -module NOT(A, Y); -input A; -output Y = ~A; -endmodule - -module NAND(A, B, Y); -input A, B; -output Y = ~(A & B); -endmodule - -module NOR(A, B, Y); -input A, B; -output Y = ~(A | B); -endmodule - -module DFF(C, D, Q); -input C, D; -output reg Q; -always @(posedge C) - Q <= D; -endmodule - diff --git a/yosys/manual/PRESENTATION_Prog.tex b/yosys/manual/PRESENTATION_Prog.tex deleted file mode 100644 index b85eda892..000000000 --- a/yosys/manual/PRESENTATION_Prog.tex +++ /dev/null @@ -1,597 +0,0 @@ - -\section{Writing Yosys extensions in C++} - -\begin{frame} -\sectionpage -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Program Components and Data Formats} - -\begin{frame}{\subsecname} -\begin{center} -\begin{tikzpicture}[scale=0.6, every node/.style={transform shape}] - \tikzstyle{process} = [draw, fill=green!10, rectangle, minimum height=3em, minimum width=10em, node distance=15em] - \tikzstyle{data} = [draw, fill=blue!10, ellipse, minimum height=3em, minimum width=7em, node distance=15em] - \node[process] (vlog) {Verilog Frontend}; - \node[process, dashed, fill=green!5] (vhdl) [right of=vlog] {VHDL Frontend}; - \node[process] (ilang) [right of=vhdl] {Other Frontends}; - \node[data] (ast) [below of=vlog, node distance=5em, xshift=7.5em] {AST}; - \node[process] (astfe) [below of=ast, node distance=5em] {AST Frontend}; - \node[data] (rtlil) [below of=astfe, node distance=5em, xshift=7.5em] {RTLIL}; - \node[process] (pass) [right of=rtlil, node distance=5em, xshift=7.5em] {Passes}; - \node[process] (vlbe) [below of=rtlil, node distance=7em, xshift=-13em] {Verilog Backend}; - \node[process] (ilangbe) [below of=rtlil, node distance=7em, xshift=0em] {ILANG Backend}; - \node[process, fill=green!5] (otherbe) [below of=rtlil, node distance=7em, xshift=+13em] {Other Backends}; - - \draw[-latex] (vlog) -- (ast); - \draw[-latex] (vhdl) -- (ast); - \draw[-latex] (ast) -- (astfe); - \draw[-latex] (astfe) -- (rtlil); - \draw[-latex] (ilang) -- (rtlil); - \draw[latex-latex] (rtlil) -- (pass); - \draw[-latex] (rtlil) -- (vlbe); - \draw[-latex] (rtlil) -- (ilangbe); - \draw[-latex] (rtlil) -- (otherbe); -\end{tikzpicture} -\end{center} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Simplified RTLIL Entity-Relationship Diagram} - -\begin{frame}{\subsecname} -Between passses and frontends/backends the design is stored in Yosys' internal -RTLIL (RTL Intermediate Language) format. For writing Yosys extensions it is -key to understand this format. - -\bigskip -\begin{center} -\begin{tikzpicture}[scale=0.6, every node/.style={transform shape}] - \tikzstyle{entity} = [draw, fill=gray!10, rectangle, minimum height=3em, minimum width=7em, node distance=5em, font={\ttfamily}] - \node[entity] (design) {RTLIL::Design}; - \node[entity] (module) [right of=design, node distance=11em] {RTLIL::Module} edge [-latex] node[above] {\tiny 1 \hskip3em N} (design); - - \node[entity] (process) [fill=green!10, right of=module, node distance=10em] {RTLIL::Process} (process.west) edge [-latex] (module); - \node[entity] (memory) [fill=red!10, below of=process] {RTLIL::Memory} edge [-latex] (module); - \node[entity] (wire) [fill=blue!10, above of=process] {RTLIL::Wire} (wire.west) edge [-latex] (module); - \node[entity] (cell) [fill=blue!10, above of=wire] {RTLIL::Cell} (cell.west) edge [-latex] (module); - - \node[entity] (case) [fill=green!10, right of=process, node distance=10em] {RTLIL::CaseRule} edge [latex-latex] (process); - \node[entity] (sync) [fill=green!10, above of=case] {RTLIL::SyncRule} edge [-latex] (process); - \node[entity] (switch) [fill=green!10, below of=case] {RTLIL::SwitchRule} edge [-latex] (case); - \draw[latex-] (switch.east) -- ++(1em,0) |- (case.east); -\end{tikzpicture} -\end{center} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{RTLIL without memories and processes} - -\begin{frame}[fragile]{\subsecname} -After the commands {\tt proc} and {\tt memory} (or {\tt memory -nomap}), we are -left with a much simpler version of RTLIL: - -\begin{center} -\begin{tikzpicture}[scale=0.6, every node/.style={transform shape}] - \tikzstyle{entity} = [draw, fill=gray!10, rectangle, minimum height=3em, minimum width=7em, node distance=5em, font={\ttfamily}] - \node[entity] (design) {RTLIL::Design}; - \node[entity] (module) [right of=design, node distance=11em] {RTLIL::Module} edge [-latex] node[above] {\tiny 1 \hskip3em N} (design); - - \node[entity] (wire) [fill=blue!10, right of=module, node distance=10em] {RTLIL::Wire} (wire.west) edge [-latex] (module); - \node[entity] (cell) [fill=blue!10, above of=wire] {RTLIL::Cell} (cell.west) edge [-latex] (module); -\end{tikzpicture} -\end{center} - -\bigskip -Many commands simply choose to only work on this simpler version: -\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont] -for (RTLIL::Module *module : design->selected_modules() { - if (module->has_memories_warn() || module->has_processes_warn()) - continue; - .... -} -\end{lstlisting} - -For simplicity we only discuss this version of RTLIL in this presentation. -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Using dump and show commands} - -\begin{frame}{\subsecname} -\begin{itemize} -\item The {\tt dump} command prints the design (or parts of it) in ILANG format. This is -a text representation of RTLIL. - -\bigskip -\item The {\tt show} command visualizes how the components in the design are connected. -\end{itemize} - -\bigskip -When trying to understand what a command does, create a small test case and -look at the output of {\tt dump} and {\tt show} before and after the command -has been executed. -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The RTLIL Data Structures} - -\begin{frame}{\subsecname} -The RTLIL data structures are simple structs utilizing {\tt pool<>} and -{\tt dict<>} containers (drop-in replacements for {\tt -std::unordered\_set<>} and {\tt std::unordered\_map<>}). - -\bigskip -\begin{itemize} -\item Most operations are performed directly on the RTLIL structs without -setter or getter functions. - -\bigskip -\item In debug builds a consistency checker is run over the in-memory design -between commands to make sure that the RTLIL representation is intact. - -\bigskip -\item Most RTLIL structs have helper methods that perform the most common operations. -\end{itemize} - -\bigskip -See {\tt yosys/kernel/rtlil.h} for details. -\end{frame} - -\subsubsection{RTLIL::IdString} - -\begin{frame}{\subsubsecname}{} -{\tt RTLIL::IdString} in many ways behave like a {\tt std::string}. It is used -for names of RTLIL objects. Internally a RTLIL::IdString object is only a -single integer. - -\medskip -The first character of a {\tt RTLIL::IdString} specifies if the name is {\it public\/} or {\it private\/}: - -\medskip -\begin{itemize} -\item {\tt RTLIL::IdString[0] == '\textbackslash\textbackslash'}: \\ -This is a public name. Usually this means it is a name that was declared in a Verilog file. - -\bigskip -\item {\tt RTLIL::IdString[0] == '\$'}: \\ -This is a private name. It was assigned by Yosys. -\end{itemize} - -\bigskip -Use the {\tt NEW\_ID} macro to create a new unique private name. -\end{frame} - -\subsubsection{RTLIL::Design and RTLIL::Module} - -\begin{frame}[t, fragile]{\subsubsecname} -The {\tt RTLIL::Design} and {\tt RTLIL::Module} structs are the top-level RTLIL -data structures. Yosys always operates on one active design, but can hold many designs in memory. - -\bigskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -struct RTLIL::Design { - dict modules_; - ... -}; - -struct RTLIL::Module { - RTLIL::IdString name; - dict wires_; - dict cells_; - std::vector connections_; - ... -}; -\end{lstlisting} - -(Use the various accessor functions instead of directly working with the {\tt *\_} members.) -\end{frame} - -\subsubsection{The RTLIL::Wire Structure} - -\begin{frame}[t, fragile]{\subsubsecname} -Each wire in the design is represented by a {\tt RTLIL::Wire} struct: - -\medskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -struct RTLIL::Wire { - RTLIL::IdString name; - int width, start_offset, port_id; - bool port_input, port_output; - ... -}; -\end{lstlisting} - -\medskip -\hfil\begin{tabular}{p{3cm}l} -{\tt width} \dotfill & The total number of bits. E.g. 10 for {\tt [9:0]}. \\ -{\tt start\_offset} \dotfill & The lowest bit index. E.g. 3 for {\tt [5:3]}. \\ -{\tt port\_id} \dotfill & Zero for non-ports. Positive index for ports. \\ -{\tt port\_input} \dotfill & True for {\tt input} and {\tt inout} ports. \\ -{\tt port\_output} \dotfill & True for {\tt output} and {\tt inout} ports. \\ -\end{tabular} -\end{frame} - -\subsubsection{RTLIL::State and RTLIL::Const} - -\begin{frame}[t, fragile]{\subsubsecname} -The {\tt RTLIL::State} enum represents a simple 1-bit logic level: - -\smallskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -enum RTLIL::State { - S0 = 0, - S1 = 1, - Sx = 2, // undefined value or conflict - Sz = 3, // high-impedance / not-connected - Sa = 4, // don't care (used only in cases) - Sm = 5 // marker (used internally by some passes) -}; -\end{lstlisting} - -\bigskip -The {\tt RTLIL::Const} struct represents a constant multi-bit value: - -\smallskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -struct RTLIL::Const { - std::vector bits; - ... -}; -\end{lstlisting} - -\bigskip -Notice that Yosys is not using special {\tt VCC} or {\tt GND} driver cells to represent constants. Instead -constants are part of the RTLIL representation itself. -\end{frame} - -\subsubsection{The RTLIL::SigSpec Structure} - -\begin{frame}[t, fragile]{\subsubsecname} -The {\tt RTLIL::SigSpec} struct represents a signal vector. Each bit can either be a bit from a wire -or a constant value. - -\bigskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -struct RTLIL::SigBit -{ - RTLIL::Wire *wire; - union { - RTLIL::State data; // used if wire == NULL - int offset; // used if wire != NULL - }; - ... -}; - -struct RTLIL::SigSpec { - std::vector bits_; // LSB at index 0 - ... -}; -\end{lstlisting} - -\bigskip -The {\tt RTLIL::SigSpec} struct has a ton of additional helper methods to compare, analyze, and -manipulate instances of {\tt RTLIL::SigSpec}. -\end{frame} - -\subsubsection{The RTLIL::Cell Structure} - -\begin{frame}[t, fragile]{\subsubsecname (1/2)} -The {\tt RTLIL::Cell} struct represents an instance of a module or library cell. - -\smallskip -The ports of the cell -are associated with {\tt RTLIL::SigSpec} instances and the parameters are associated with {\tt RTLIL::Const} -instances: - -\bigskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -struct RTLIL::Cell { - RTLIL::IdString name, type; - dict connections_; - dict parameters; - ... -}; -\end{lstlisting} - -\bigskip -The {\tt type} may refer to another module in the same design, a cell name from a cell library, or a -cell name from the internal cell library: - -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont] -$not $pos $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor -$reduce_bool $shl $shr $sshl $sshr $lt $le $eq $ne $eqx $nex $ge $gt $add $sub $mul $div $mod -$pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff -$dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_NOT_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_ -$_SR_NP_ $_SR_PN_ $_SR_PP_ $_DFF_N_ $_DFF_P_ $_DFF_NN0_ $_DFF_NN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PN0_ -$_DFF_PN1_ $_DFF_PP0_ $_DFF_PP1_ $_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PNN_ -$_DFFSR_PNP_ $_DFFSR_PPN_ $_DFFSR_PPP_ $_DLATCH_N_ $_DLATCH_P_ $_DLATCHSR_NNN_ $_DLATCHSR_NNP_ -$_DLATCHSR_NPN_ $_DLATCHSR_NPP_ $_DLATCHSR_PNN_ $_DLATCHSR_PNP_ $_DLATCHSR_PPN_ $_DLATCHSR_PPP_ -\end{lstlisting} -\end{frame} - -\begin{frame}[t, fragile]{\subsubsecname (2/2)} -Simulation models (i.e. {\it documentation\/} :-) for the internal cell library: - -\smallskip -\hskip2em {\tt yosys/techlibs/common/simlib.v} and \\ -\hskip2em {\tt yosys/techlibs/common/simcells.v} - -\bigskip -The lower-case cell types (such as {\tt \$and}) are parameterized cells of variable -width. This so-called {\it RTL Cells\/} are the cells described in {\tt simlib.v}. - -\bigskip -The upper-case cell types (such as {\tt \$\_AND\_}) are single-bit cells that are not -parameterized. This so-called {\it Internal Logic Gates} are the cells described -in {\tt simcells.v}. - -\bigskip -The consistency checker also checks the interfaces to the internal cell library. -If you want to use private cell types for your own purposes, use the {\tt \$\_\_}-prefix -to avoid name collisions. -\end{frame} - -\subsubsection{Connecting wires or constant drivers} - -\begin{frame}[t, fragile]{\subsubsecname} -Additional connections between wires or between wires and constants are modelled using -{\tt RTLIL::Module::connections}: - -\bigskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -typedef std::pair RTLIL::SigSig; - -struct RTLIL::Module { - ... - std::vector connections_; - ... -}; -\end{lstlisting} - -\bigskip -{\tt RTLIL::SigSig::first} is the driven signal and {\tt RTLIL::SigSig::second} is the driving signal. -Example usage (setting wire {\tt foo} to value {\tt 42}): -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -module->connect(module->wire("\\foo"), - RTLIL::SigSpec(42, module->wire("\\foo")->width)); -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Creating modules from scratch} - -\begin{frame}[t, fragile]{\subsecname} -Let's create the following module using the RTLIL API: - -\smallskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog] -module absval(input signed [3:0] a, output [3:0] y); - assign y = a[3] ? -a : a; -endmodule -\end{lstlisting} - -\smallskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -RTLIL::Module *module = new RTLIL::Module; -module->name = "\\absval"; - -RTLIL::Wire *a = module->addWire("\\a", 4); -a->port_input = true; -a->port_id = 1; - -RTLIL::Wire *y = module->addWire("\\y", 4); -y->port_output = true; -y->port_id = 2; - -RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4); -module->addNeg(NEW_ID, a, a_inv, true); -module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y); - -module->fixup_ports(); -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Modifying modules} - -\begin{frame}{\subsecname} -Most commands modify existing modules, not create new ones. - -When modifying existing modules, stick to the following DOs and DON'Ts: - -\begin{itemize} -\item Do not remove wires. Simply disconnect them and let a successive {\tt clean} command worry about removing it. - -\item Use {\tt module->fixup\_ports()} after changing the {\tt port\_*} properties of wires. - -\item You can safely remove cells or change the {\tt connections} property of a cell, but be careful when -changing the size of the {\tt SigSpec} connected to a cell port. - -\item Use the {\tt SigMap} helper class (see next slide) when you need a unique handle for each signal bit. -\end{itemize} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Using the SigMap helper class} - -\begin{frame}[t, fragile]{\subsecname} -Consider the following module: - -\smallskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog] -module test(input a, output x, y); - assign x = a, y = a; -endmodule -\end{lstlisting} - -In this case {\tt a}, {\tt x}, and {\tt y} are all different names for the same signal. However: - -\smallskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")), - y(module->wire("\\y")); -log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0" -\end{lstlisting} - -The {\tt SigMap} helper class can be used to map all such aliasing signals to a -unique signal from the group (usually the wire that is directly driven by a cell or port). - -\smallskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -SigMap sigmap(module); -log("%d %d %d\n", sigmap(a) == sigmap(x), sigmap(x) == sigmap(y), - sigmap(y) == sigmap(a)); // will print "1 1 1" -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Printing log messages} - -\begin{frame}[t, fragile]{\subsecname} -The {\tt log()} function is a {\tt printf()}-like function that can be used to create log messages. - -\medskip -Use {\tt log\_signal()} to create a C-string for a SigSpec object\footnote[frame]{The pointer returned -by {\tt log\_signal()} is automatically freed by the log framework at a later time.}: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -log("Mapped signal x: %s\n", log_signal(sigmap(x))); -\end{lstlisting} - -\medskip -Use {\tt log\_id()} to create a C-string for an {\tt RTLIL::IdString}: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -log("Name of this module: %s\n", log_id(module->name)); -\end{lstlisting} - -\medskip -Use {\tt log\_header()} and {\tt log\_push()}/{\tt log\_pop()} to structure log messages: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -log_header(design, "Doing important stuff!\n"); -log_push(); -for (int i = 0; i < 10; i++) - log("Log message #%d.\n", i); -log_pop(); -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Error handling} - -\begin{frame}[t, fragile]{\subsecname} -Use {\tt log\_error()} to report a non-recoverable error: - -\medskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -if (design->modules.count(module->name) != 0) - log_error("A module with the name %s already exists!\n", - RTLIL::id2cstr(module->name)); -\end{lstlisting} - -\bigskip -Use {\tt log\_cmd\_error()} to report a recoverable error: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -if (design->selection_stack.back().empty()) - log_cmd_error("This command can't operator on an empty selection!\n"); -\end{lstlisting} - -\bigskip -Use {\tt log\_assert()} and {\tt log\_abort()} instead of {\tt assert()} and {\tt abort()}. -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Creating a command} - -\begin{frame}[t, fragile]{\subsecname} -Simply create a global instance of a class derived from {\tt Pass} to create -a new yosys command: - -\bigskip -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++] -#include "kernel/yosys.h" -USING_YOSYS_NAMESPACE - -struct MyPass : public Pass { - MyPass() : Pass("my_cmd", "just a simple test") { } - virtual void execute(std::vector args, RTLIL::Design *design) - { - log("Arguments to my_cmd:\n"); - for (auto &arg : args) - log(" %s\n", arg.c_str()); - - log("Modules in current design:\n"); - for (auto mod : design->modules()) - log(" %s (%d wires, %d cells)\n", log_id(mod), - GetSize(mod->wires()), GetSize(mod->cells())); - } -} MyPass; -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Creating a plugin} - -\begin{frame}[fragile]{\subsecname} -Yosys can be extended by adding additional C++ code to the Yosys code base, or -by loading plugins into Yosys. - -\bigskip -Use the following command to compile a Yosys plugin: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont] -yosys-config --exec --cxx --cxxflags --ldflags \ - -o my_cmd.so -shared my_cmd.cc --ldlibs -\end{lstlisting} - -\bigskip -Or shorter: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont] -yosys-config --build my_cmd.so my_cmd.cc -\end{lstlisting} - -\bigskip -Load the plugin using the yosys {\tt -m} option: -\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont] -yosys -m ./my_cmd.so -p 'my_cmd foo bar' -\end{lstlisting} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{Summary} - -\begin{frame}{\subsecname} -\begin{itemize} -\item Writing Yosys extensions is very straight-forward. -\item \dots and even simpler if you don't need RTLIL::Memory or RTLIL::Process objects. - -\bigskip -\item Writing synthesis software? Consider learning the Yosys API and make your work -part of the Yosys framework. -\end{itemize} - -\bigskip -\bigskip -\begin{center} -Questions? -\end{center} - -\bigskip -\bigskip -\begin{center} -\url{http://www.clifford.at/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_Prog/.gitignore b/yosys/manual/PRESENTATION_Prog/.gitignore deleted file mode 100644 index ccdd6bd5c..000000000 --- a/yosys/manual/PRESENTATION_Prog/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -my_cmd.so -my_cmd.d diff --git a/yosys/manual/PRESENTATION_Prog/Makefile b/yosys/manual/PRESENTATION_Prog/Makefile deleted file mode 100644 index 794f5c12c..000000000 --- a/yosys/manual/PRESENTATION_Prog/Makefile +++ /dev/null @@ -1,18 +0,0 @@ - -all: test0.log test1.log test2.log - -my_cmd.so: my_cmd.cc - ../../yosys-config --exec --cxx --cxxflags --ldflags -o my_cmd.so -shared my_cmd.cc --ldlibs - -test0.log: my_cmd.so - ../../yosys -Ql test0.log_new -m ./my_cmd.so -p 'my_cmd foo bar' absval_ref.v - mv test0.log_new test0.log - -test1.log: my_cmd.so - ../../yosys -Ql test1.log_new -m ./my_cmd.so -p 'clean; test1; dump' absval_ref.v - mv test1.log_new test1.log - -test2.log: my_cmd.so - ../../yosys -Ql test2.log_new -m ./my_cmd.so -p 'test2' sigmap_test.v - mv test2.log_new test2.log - diff --git a/yosys/manual/PRESENTATION_Prog/absval_ref.v b/yosys/manual/PRESENTATION_Prog/absval_ref.v deleted file mode 100644 index ca0a115a0..000000000 --- a/yosys/manual/PRESENTATION_Prog/absval_ref.v +++ /dev/null @@ -1,3 +0,0 @@ -module absval_ref(input signed [3:0] a, output [3:0] y); - assign y = a[3] ? -a : a; -endmodule diff --git a/yosys/manual/PRESENTATION_Prog/my_cmd.cc b/yosys/manual/PRESENTATION_Prog/my_cmd.cc deleted file mode 100644 index 5d9a7e13b..000000000 --- a/yosys/manual/PRESENTATION_Prog/my_cmd.cc +++ /dev/null @@ -1,76 +0,0 @@ -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct MyPass : public Pass { - MyPass() : Pass("my_cmd", "just a simple test") { } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log("Arguments to my_cmd:\n"); - for (auto &arg : args) - log(" %s\n", arg.c_str()); - - log("Modules in current design:\n"); - for (auto mod : design->modules()) - log(" %s (%zd wires, %zd cells)\n", log_id(mod), - GetSize(mod->wires()), GetSize(mod->cells())); - } -} MyPass; - - -struct Test1Pass : public Pass { - Test1Pass() : Pass("test1", "creating the absval module") { } - void execute(std::vector, RTLIL::Design *design) YS_OVERRIDE - { - if (design->has("\\absval") != 0) - log_error("A module with the name absval already exists!\n"); - - RTLIL::Module *module = design->addModule("\\absval"); - log("Name of this module: %s\n", log_id(module)); - - RTLIL::Wire *a = module->addWire("\\a", 4); - a->port_input = true; - a->port_id = 1; - - RTLIL::Wire *y = module->addWire("\\y", 4); - y->port_output = true; - y->port_id = 2; - - RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4); - module->addNeg(NEW_ID, a, a_inv, true); - module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 3), y); - - module->fixup_ports(); - } -} Test1Pass; - - -struct Test2Pass : public Pass { - Test2Pass() : Pass("test2", "demonstrating sigmap on test module") { } - void execute(std::vector, RTLIL::Design *design) YS_OVERRIDE - { - if (design->selection_stack.back().empty()) - log_cmd_error("This command can't operator on an empty selection!\n"); - - RTLIL::Module *module = design->modules_.at("\\test"); - - RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")), y(module->wire("\\y")); - log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0" - - SigMap sigmap(module); - log("%d %d %d\n", sigmap(a) == sigmap(x), sigmap(x) == sigmap(y), - sigmap(y) == sigmap(a)); // will print "1 1 1" - - log("Mapped signal x: %s\n", log_signal(sigmap(x))); - - log_header(design, "Doing important stuff!\n"); - log_push(); - for (int i = 0; i < 10; i++) - log("Log message #%d.\n", i); - log_pop(); - } -} Test2Pass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/manual/PRESENTATION_Prog/sigmap_test.v b/yosys/manual/PRESENTATION_Prog/sigmap_test.v deleted file mode 100644 index 18dcf5eb7..000000000 --- a/yosys/manual/PRESENTATION_Prog/sigmap_test.v +++ /dev/null @@ -1,3 +0,0 @@ -module test(input a, output x, y); -assign x = a, y = a; -endmodule diff --git a/yosys/manual/appnotes.sh b/yosys/manual/appnotes.sh deleted file mode 100755 index 0ae52862e..000000000 --- a/yosys/manual/appnotes.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -ex -for job in APPNOTE_010_Verilog_to_BLIF APPNOTE_011_Design_Investigation APPNOTE_012_Verilog_to_BTOR -do - [ -f $job.ok -a $job.ok -nt $job.tex ] && continue - if [ -f $job/make.sh ]; then - cd $job - bash make.sh - cd .. - fi - old_md5=$([ -f $job.aux ] && md5sum < $job.aux || true) - while - pdflatex -shell-escape -halt-on-error $job.tex || exit - new_md5=$(md5sum < $job.aux) - [ "$old_md5" != "$new_md5" ] - do - old_md5="$new_md5" - done - touch $job.ok -done - diff --git a/yosys/manual/clean.sh b/yosys/manual/clean.sh deleted file mode 100755 index addc34ed1..000000000 --- a/yosys/manual/clean.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -for f in $( find . -name .gitignore ); do sed -Ee "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs rm -f,;" $f; done | bash -v diff --git a/yosys/manual/command-reference-manual.tex b/yosys/manual/command-reference-manual.tex deleted file mode 100644 index bed6326e2..000000000 --- a/yosys/manual/command-reference-manual.tex +++ /dev/null @@ -1,5526 +0,0 @@ -% Generated using the yosys 'help -write-tex-command-reference-manual' command. - -\section{abc -- use ABC for technology mapping} -\label{cmd:abc} -\begin{lstlisting}[numbers=left,frame=single] - abc [options] [selection] - -This pass uses the ABC tool [1] for technology mapping of yosys's internal gate -library to a target architecture. - - -exe - use the specified command instead of "/yosys-abc" to execute ABC. - This can e.g. be used to call a specific version of ABC or a wrapper. - - -script - use the specified ABC script file instead of the default script. - - if starts with a plus sign (+), then the rest of the filename - string is interpreted as the command string to be passed to ABC. The - leading plus sign is removed and all commas (,) in the string are - replaced with blanks before the string is passed to ABC. - - if no -script parameter is given, the following scripts are used: - - for -liberty without -constr: - strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; - &nf {D}; &put - - for -liberty with -constr: - strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; - &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p - - for -lut/-luts (only one LUT size): - strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2; - lutpack {S} - - for -lut/-luts (different LUT sizes): - strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2 - - for -sop: - strash; ifraig; scorr; dc2; dretime; strash; dch -f; - cover {I} {P} - - otherwise: - strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; - &nf {D}; &put - - -fast - use different default scripts that are slightly faster (at the cost - of output quality): - - for -liberty without -constr: - strash; dretime; map {D} - - for -liberty with -constr: - strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; - stime -p - - for -lut/-luts: - strash; dretime; if - - for -sop: - strash; dretime; cover -I {I} -P {P} - - otherwise: - strash; dretime; map - - -liberty - generate netlists for the specified cell library (using the liberty - file format). - - -constr - pass this file with timing constraints to ABC. use with -liberty. - - a constr file contains two lines: - set_driving_cell - set_load - - the set_driving_cell statement defines which cell type is assumed to - drive the primary inputs and the set_load statement sets the load in - femtofarads for each primary output. - - -D - set delay target. the string {D} in the default scripts above is - replaced by this option when used, and an empty string otherwise. - this also replaces 'dretime' with 'dretime; retime -o {D}' in the - default scripts above. - - -I - maximum number of SOP inputs. - (replaces {I} in the default scripts above) - - -P - maximum number of SOP products. - (replaces {P} in the default scripts above) - - -S - maximum number of LUT inputs shared. - (replaces {S} in the default scripts above, default: -S 1) - - -lut - generate netlist using luts of (max) the specified width. - - -lut : - generate netlist using luts of (max) the specified width . All - luts with width <= have constant cost. for luts larger than - the area cost doubles with each additional input bit. the delay cost - is still constant for all lut widths. - - -luts ,,,:,.. - generate netlist using luts. Use the specified costs for luts with 1, - 2, 3, .. inputs. - - -sop - map to sum-of-product cells and inverters - - -g type1,type2,... - Map to the specified list of gate types. Supported gates types are: - AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4. - (The NOT gate is always added to this list automatically.) - - The following aliases can be used to reference common sets of gate types: - simple: AND OR XOR MUX - cmos2: NAND NOR - cmos3: NAND NOR AOI3 OAI3 - cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4 - gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT - aig: AND NAND OR NOR ANDNOT ORNOT - - Prefix a gate type with a '-' to remove it from the list. For example - the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent. - - -dff - also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many - clock domains are automatically partitioned in clock domains and each - domain is passed through ABC independently. - - -clk [!][,[!]] - use only the specified clock domain. this is like -dff, but only FF - cells that belong to the specified clock domain are used. - - -keepff - set the "keep" attribute on flip-flop output wires. (and thus preserve - them, for example for equivalence checking.) - - -nocleanup - when this option is used, the temporary files created by this pass - are not removed. this is useful for debugging. - - -showtmp - print the temp dir name in log. usually this is suppressed so that the - command output is identical across runs. - - -markgroups - set a 'abcgroup' attribute on all objects created by ABC. The value of - this attribute is a unique integer for each ABC process started. This - is useful for debugging the partitioning of clock domains. - -When neither -liberty nor -lut is used, the Yosys standard cell library is -loaded into ABC before the ABC script is executed. - -Note that this is a logic optimization pass within Yosys that is calling ABC -internally. This is not going to "run ABC on your design". It will instead run -ABC on logic snippets extracted from your design. You will not get any useful -output when passing an ABC script that writes a file. Instead write your full -design as BLIF file with write_blif and the load that into ABC externally if -you want to use ABC to convert your design into another format. - -[1] http://www.eecs.berkeley.edu/~alanmi/abc/ -\end{lstlisting} - -\section{add -- add objects to the design} -\label{cmd:add} -\begin{lstlisting}[numbers=left,frame=single] - add [selection] - -This command adds objects to the design. It operates on all fully selected -modules. So e.g. 'add -wire foo' will add a wire foo to all selected modules. - - - add {-wire|-input|-inout|-output} [selection] - -Add a wire (input, inout, output port) with the given name and width. The -command will fail if the object exists already and has different properties -than the object to be created. - - - add -global_input [selection] - -Like 'add -input', but also connect the signal between instances of the -selected modules. -\end{lstlisting} - -\section{aigmap -- map logic to and-inverter-graph circuit} -\label{cmd:aigmap} -\begin{lstlisting}[numbers=left,frame=single] - aigmap [options] [selection] - -Replace all logic cells with circuits made of only $_AND_ and -$_NOT_ cells. - - -nand - Enable creation of $_NAND_ cells -\end{lstlisting} - -\section{alumacc -- extract ALU and MACC cells} -\label{cmd:alumacc} -\begin{lstlisting}[numbers=left,frame=single] - alumacc [selection] - -This pass translates arithmetic operations like $add, $mul, $lt, etc. to $alu -and $macc cells. -\end{lstlisting} - -\section{assertpmux -- convert internal signals to module ports} -\label{cmd:assertpmux} -\begin{lstlisting}[numbers=left,frame=single] - assertpmux [options] [selection] - -This command adds asserts to the design that assert that all parallel muxes -($pmux cells) have a maximum of one of their inputs enable at any time. - - -noinit - do not enforce the pmux condition during the init state - - -always - usually the $pmux condition is only checked when the $pmux output - is used be the mux tree it drives. this option will deactivate this - additional constrained and check the $pmux condition always. -\end{lstlisting} - -\section{async2sync -- convert async FF inputs to sync circuits} -\label{cmd:async2sync} -\begin{lstlisting}[numbers=left,frame=single] - async2sync [options] [selection] - -This command replaces async FF inputs with sync circuits emulating the same -behavior for when the async signals are actually synchronized to the clock. - -This pass assumes negative hold time for the async FF inputs. For example when -a reset deasserts with the clock edge, then the FF output will still drive the -reset value in the next cycle regardless of the data-in value at the time of -the clock edge. - -Currently only $adff cells are supported by this pass. -\end{lstlisting} - -\section{attrmap -- renaming attributes} -\label{cmd:attrmap} -\begin{lstlisting}[numbers=left,frame=single] - attrmap [options] [selection] - -This command renames attributes and/or mapps key/value pairs to -other key/value pairs. - - -tocase - Match attribute names case-insensitively and set it to the specified - name. - - -rename - Rename attributes as specified - - -map = = - Map key/value pairs as indicated. - - -imap = = - Like -map, but use case-insensitive match for when - it is a string value. - - -remove = - Remove attributes matching this pattern. - - -modattr - Operate on module attributes instead of attributes on wires and cells. - -For example, mapping Xilinx-style "keep" attributes to Yosys-style: - - attrmap -tocase keep -imap keep="true" keep=1 \ - -imap keep="false" keep=0 -remove keep=0 -\end{lstlisting} - -\section{attrmvcp -- move or copy attributes from wires to driving cells} -\label{cmd:attrmvcp} -\begin{lstlisting}[numbers=left,frame=single] - attrmvcp [options] [selection] - -Move or copy attributes on wires to the cells driving them. - - -copy - By default, attributes are moved. This will only add - the attribute to the cell, without removing it from - the wire. - - -purge - If no selected cell consumes the attribute, then it is - left on the wire by default. This option will cause the - attribute to be removed from the wire, even if no selected - cell takes it. - - -driven - By default, attriburtes are moved to the cell driving the - wire. With this option set it will be moved to the cell - driven by the wire instead. - - -attr - Move or copy this attribute. This option can be used - multiple times. -\end{lstlisting} - -\section{blackbox -- change type of cells in the design} -\label{cmd:blackbox} -\begin{lstlisting}[numbers=left,frame=single] - blackbox [options] [selection] - -Convert modules into blackbox modules (remove contents and set the blackbox -module attribute). -\end{lstlisting} - -\section{cd -- a shortcut for 'select -module '} -\label{cmd:cd} -\begin{lstlisting}[numbers=left,frame=single] - cd - -This is just a shortcut for 'select -module '. - - - cd - -When no module with the specified name is found, but there is a cell -with the specified name in the current module, then this is equivalent -to 'cd '. - - cd .. - -Remove trailing substrings that start with '.' in current module name until -the name of a module in the current design is generated, then switch to that -module. Otherwise clear the current selection. - - cd - -This is just a shortcut for 'select -clear'. -\end{lstlisting} - -\section{check -- check for obvious problems in the design} -\label{cmd:check} -\begin{lstlisting}[numbers=left,frame=single] - check [options] [selection] - -This pass identifies the following problems in the current design: - - - combinatorial loops - - - two or more conflicting drivers for one wire - - - used wires that do not have a driver - -When called with -noinit then this command also checks for wires which have -the 'init' attribute set. - -When called with -initdrv then this command also checks for wires which have -the 'init' attribute set and aren't driven by a FF cell type. - -When called with -assert then the command will produce an error if any -problems are found in the current design. -\end{lstlisting} - -\section{chformal -- change formal constraints of the design} -\label{cmd:chformal} -\begin{lstlisting}[numbers=left,frame=single] - chformal [types] [mode] [options] [selection] - -Make changes to the formal constraints of the design. The [types] options -the type of constraint to operate on. If none of the folling options is given, -the command will operate on all constraint types: - - -assert $assert cells, representing assert(...) constraints - -assume $assume cells, representing assume(...) constraints - -live $live cells, representing assert(s_eventually ...) - -fair $fair cells, representing assume(s_eventually ...) - -cover $cover cells, representing cover() statements - -Exactly one of the following modes must be specified: - - -remove - remove the cells and thus constraints from the design - - -early - bypass FFs that only delay the activation of a constraint - - -delay - delay activation of the constraint by clock cycles - - -skip - ignore activation of the constraint in the first clock cycles - - -assert2assume - -assume2assert - -live2fair - -fair2live - change the roles of cells as indicated. this options can be combined -\end{lstlisting} - -\section{chparam -- re-evaluate modules with new parameters} -\label{cmd:chparam} -\begin{lstlisting}[numbers=left,frame=single] - chparam [ -set name value ]... [selection] - -Re-evaluate the selected modules with new parameters. String values must be -passed in double quotes ("). - - - chparam -list [selection] - -List the available parameters of the selected modules. -\end{lstlisting} - -\section{chtype -- change type of cells in the design} -\label{cmd:chtype} -\begin{lstlisting}[numbers=left,frame=single] - chtype [options] [selection] - -Change the types of cells in the design. - - -set - set the cell type to the given type - - -map - change cells types that match to -\end{lstlisting} - -\section{clean -- remove unused cells and wires} -\label{cmd:clean} -\begin{lstlisting}[numbers=left,frame=single] - clean [options] [selection] - -This is identical to 'opt_clean', but less verbose. - -When commands are separated using the ';;' token, this command will be executed -between the commands. - -When commands are separated using the ';;;' token, this command will be executed -in -purge mode between the commands. -\end{lstlisting} - -\section{clk2fflogic -- convert clocked FFs to generic \$ff cells} -\label{cmd:clk2fflogic} -\begin{lstlisting}[numbers=left,frame=single] - clk2fflogic [options] [selection] - -This command replaces clocked flip-flops with generic $ff cells that use the -implicit global clock. This is useful for formal verification of designs with -multiple clocks. -\end{lstlisting} - -\section{connect -- create or remove connections} -\label{cmd:connect} -\begin{lstlisting}[numbers=left,frame=single] - connect [-nomap] [-nounset] -set - -Create a connection. This is equivalent to adding the statement 'assign - = ;' to the Verilog input. Per default, all existing -drivers for are unconnected. This can be overwritten by using -the -nounset option. - - - connect [-nomap] -unset - -Unconnect all existing drivers for the specified expression. - - - connect [-nomap] -port - -Connect the specified cell port to the specified cell port. - - -Per default signal alias names are resolved and all signal names are mapped -the the signal name of the primary driver. Using the -nomap option deactivates -this behavior. - -The connect command operates in one module only. Either only one module must -be selected or an active module must be set using the 'cd' command. - -This command does not operate on module with processes. -\end{lstlisting} - -\section{connwrappers -- match width of input-output port pairs} -\label{cmd:connwrappers} -\begin{lstlisting}[numbers=left,frame=single] - connwrappers [options] [selection] - -Wrappers are used in coarse-grain synthesis to wrap cells with smaller ports -in wrapper cells with a (larger) constant port size. I.e. the upper bits -of the wrapper output are signed/unsigned bit extended. This command uses this -knowledge to rewire the inputs of the driven cells to match the output of -the driving cell. - - -signed - -unsigned - consider the specified signed/unsigned wrapper output - - -port - use the specified parameter to decide if signed or unsigned - -The options -signed, -unsigned, and -port can be specified multiple times. -\end{lstlisting} - -\section{coolrunner2\_sop -- break \$sop cells into ANDTERM/ORTERM cells} -\label{cmd:coolrunner2_sop} -\begin{lstlisting}[numbers=left,frame=single] - coolrunner2_sop [options] [selection] - -Break $sop cells into ANDTERM/ORTERM cells. -\end{lstlisting} - -\section{copy -- copy modules in the design} -\label{cmd:copy} -\begin{lstlisting}[numbers=left,frame=single] - copy old_name new_name - -Copy the specified module. Note that selection patterns are not supported -by this command. -\end{lstlisting} - -\section{cover -- print code coverage counters} -\label{cmd:cover} -\begin{lstlisting}[numbers=left,frame=single] - cover [options] [pattern] - -Print the code coverage counters collected using the cover() macro in the Yosys -C++ code. This is useful to figure out what parts of Yosys are utilized by a -test bench. - - -q - Do not print output to the normal destination (console and/or log file) - - -o file - Write output to this file, truncate if exists. - - -a file - Write output to this file, append if exists. - - -d dir - Write output to a newly created file in the specified directory. - -When one or more pattern (shell wildcards) are specified, then only counters -matching at least one pattern are printed. - - -It is also possible to instruct Yosys to print the coverage counters on program -exit to a file using environment variables: - - YOSYS_COVER_DIR="{dir-name}" yosys {args} - - This will create a file (with an auto-generated name) in this - directory and write the coverage counters to it. - - YOSYS_COVER_FILE="{file-name}" yosys {args} - - This will append the coverage counters to the specified file. - - -Hint: Use the following AWK command to consolidate Yosys coverage files: - - gawk '{ p[$3] = $1; c[$3] += $2; } END { for (i in p) - printf "%-60s %10d %s\n", p[i], c[i], i; }' {files} | sort -k3 - - -Coverage counters are only available in Yosys for Linux. -\end{lstlisting} - -\section{delete -- delete objects in the design} -\label{cmd:delete} -\begin{lstlisting}[numbers=left,frame=single] - delete [selection] - -Deletes the selected objects. This will also remove entire modules, if the -whole module is selected. - - - delete {-input|-output|-port} [selection] - -Does not delete any object but removes the input and/or output flag on the -selected wires, thus 'deleting' module ports. -\end{lstlisting} - -\section{deminout -- demote inout ports to input or output} -\label{cmd:deminout} -\begin{lstlisting}[numbers=left,frame=single] - deminout [options] [selection] - -"Demote" inout ports to input or output ports, if possible. -\end{lstlisting} - -\section{design -- save, restore and reset current design} -\label{cmd:design} -\begin{lstlisting}[numbers=left,frame=single] - design -reset - -Clear the current design. - - - design -save - -Save the current design under the given name. - - - design -stash - -Save the current design under the given name and then clear the current design. - - - design -push - -Push the current design to the stack and then clear the current design. - - - design -pop - -Reset the current design and pop the last design from the stack. - - - design -load - -Reset the current design and load the design previously saved under the given -name. - - - design -copy-from [-as ] - -Copy modules from the specified design into the current one. The selection is -evaluated in the other design. - - - design -copy-to [-as ] [selection] - -Copy modules from the current design into the specified one. - - - design -import [-as ] [selection] - -Import the specified design into the current design. The source design must -either have a selected top module or the selection must contain exactly one -module that is then used as top module for this command. - - - design -reset-vlog - -The Verilog front-end remembers defined macros and top-level declarations -between calls to 'read_verilog'. This command resets this memory. -\end{lstlisting} - -\section{dff2dffe -- transform \$dff cells to \$dffe cells} -\label{cmd:dff2dffe} -\begin{lstlisting}[numbers=left,frame=single] - dff2dffe [options] [selection] - -This pass transforms $dff cells driven by a tree of multiplexers with one or -more feedback paths to $dffe cells. It also works on gate-level cells such as -$_DFF_P_, $_DFF_N_ and $_MUX_. - - -unmap - operate in the opposite direction: replace $dffe cells with combinations - of $dff and $mux cells. the options below are ignore in unmap mode. - - -direct - map directly to external gate type. can - be any internal gate-level FF cell (except $_DFFE_??_). the - is the cell type name for a cell with an - identical interface to the , except it - also has an high-active enable port 'E'. - Usually is an intermediate cell type - that is then translated to the final type using 'techmap'. - - -direct-match - like -direct for all DFF cell types matching the expression. - this will use $__DFFE_* as matching the - internal gate type $_DFF_*_, and $__DFFSE_* for those matching - $_DFFS_*_, except for $_DFF_[NP]_, which is converted to - $_DFFE_[NP]_. -\end{lstlisting} - -\section{dff2dffs -- process sync set/reset with SR over CE priority} -\label{cmd:dff2dffs} -\begin{lstlisting}[numbers=left,frame=single] - dff2dffs [options] [selection] - -Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before -dff2dffe for SR over CE priority. -\end{lstlisting} - -\section{dffinit -- set INIT param on FF cells} -\label{cmd:dffinit} -\begin{lstlisting}[numbers=left,frame=single] - dffinit [options] [selection] - -This pass sets an FF cell parameter to the the initial value of the net it -drives. (This is primarily used in FPGA flows.) - - -ff - operate on the specified cell type. this option can be used - multiple times. - - -highlow - use the string values "high" and "low" to represent a single-bit - initial value of 1 or 0. (multi-bit values are not supported in this - mode.) -\end{lstlisting} - -\section{dfflibmap -- technology mapping of flip-flops} -\label{cmd:dfflibmap} -\begin{lstlisting}[numbers=left,frame=single] - dfflibmap [-prepare] -liberty [selection] - -Map internal flip-flop cells to the flip-flop cells in the technology -library specified in the given liberty file. - -This pass may add inverters as needed. Therefore it is recommended to -first run this pass and then map the logic paths to the target technology. - -When called with -prepare, this command will convert the internal FF cells -to the internal cell types that best match the cells found in the given -liberty file. -\end{lstlisting} - -\section{dffsr2dff -- convert DFFSR cells to simpler FF cell types} -\label{cmd:dffsr2dff} -\begin{lstlisting}[numbers=left,frame=single] - dffsr2dff [options] [selection] - -This pass converts DFFSR cells ($dffsr, $_DFFSR_???_) and ADFF cells ($adff, -$_DFF_???_) to simpler FF cell types when any of the set/reset inputs is unused. -\end{lstlisting} - -\section{dump -- print parts of the design in ilang format} -\label{cmd:dump} -\begin{lstlisting}[numbers=left,frame=single] - dump [options] [selection] - -Write the selected parts of the design to the console or specified file in -ilang format. - - -m - also dump the module headers, even if only parts of a single - module is selected - - -n - only dump the module headers if the entire module is selected - - -o - write to the specified file. - - -a - like -outfile but append instead of overwrite -\end{lstlisting} - -\section{echo -- turning echoing back of commands on and off} -\label{cmd:echo} -\begin{lstlisting}[numbers=left,frame=single] - echo on - -Print all commands to log before executing them. - - - echo off - -Do not print all commands to log before executing them. (default) -\end{lstlisting} - -\section{edgetypes -- list all types of edges in selection} -\label{cmd:edgetypes} -\begin{lstlisting}[numbers=left,frame=single] - edgetypes [options] [selection] - -This command lists all unique types of 'edges' found in the selection. An 'edge' -is a 4-tuple of source and sink cell type and port name. -\end{lstlisting} - -\section{equiv\_add -- add a \$equiv cell} -\label{cmd:equiv_add} -\begin{lstlisting}[numbers=left,frame=single] - equiv_add [-try] gold_sig gate_sig - -This command adds an $equiv cell for the specified signals. - - - equiv_add [-try] -cell gold_cell gate_cell - -This command adds $equiv cells for the ports of the specified cells. -\end{lstlisting} - -\section{equiv\_induct -- proving \$equiv cells using temporal induction} -\label{cmd:equiv_induct} -\begin{lstlisting}[numbers=left,frame=single] - equiv_induct [options] [selection] - -Uses a version of temporal induction to prove $equiv cells. - -Only selected $equiv cells are proven and only selected cells are used to -perform the proof. - - -undef - enable modelling of undef states - - -seq - the max. number of time steps to be considered (default = 4) - -This command is very effective in proving complex sequential circuits, when -the internal state of the circuit quickly propagates to $equiv cells. - -However, this command uses a weak definition of 'equivalence': This command -proves that the two circuits will not diverge after they produce equal -outputs (observable points via $equiv) for at least cycles (the -specified via -seq). - -Combined with simulation this is very powerful because simulation can give -you confidence that the circuits start out synced for at least cycles -after reset. -\end{lstlisting} - -\section{equiv\_make -- prepare a circuit for equivalence checking} -\label{cmd:equiv_make} -\begin{lstlisting}[numbers=left,frame=single] - equiv_make [options] gold_module gate_module equiv_module - -This creates a module annotated with $equiv cells from two presumably -equivalent modules. Use commands such as 'equiv_simple' and 'equiv_status' -to work with the created equivalent checking module. - - -inames - Also match cells and wires with $... names. - - -blacklist - Do not match cells or signals that match the names in the file. - - -encfile - Match FSM encodings using the description from the file. - See 'help fsm_recode' for details. - -Note: The circuit created by this command is not a miter (with something like -a trigger output), but instead uses $equiv cells to encode the equivalence -checking problem. Use 'miter -equiv' if you want to create a miter circuit. -\end{lstlisting} - -\section{equiv\_mark -- mark equivalence checking regions} -\label{cmd:equiv_mark} -\begin{lstlisting}[numbers=left,frame=single] - equiv_mark [options] [selection] - -This command marks the regions in an equivalence checking module. Region 0 is -the proven part of the circuit. Regions with higher numbers are connected -unproven subcricuits. The integer attribute 'equiv_region' is set on all -wires and cells. -\end{lstlisting} - -\section{equiv\_miter -- extract miter from equiv circuit} -\label{cmd:equiv_miter} -\begin{lstlisting}[numbers=left,frame=single] - equiv_miter [options] miter_module [selection] - -This creates a miter module for further analysis of the selected $equiv cells. - - -trigger - Create a trigger output - - -cmp - Create cmp_* outputs for individual unproven $equiv cells - - -assert - Create a $assert cell for each unproven $equiv cell - - -undef - Create compare logic that handles undefs correctly -\end{lstlisting} - -\section{equiv\_purge -- purge equivalence checking module} -\label{cmd:equiv_purge} -\begin{lstlisting}[numbers=left,frame=single] - equiv_purge [options] [selection] - -This command removes the proven part of an equivalence checking module, leaving -only the unproven segments in the design. This will also remove and add module -ports as needed. -\end{lstlisting} - -\section{equiv\_remove -- remove \$equiv cells} -\label{cmd:equiv_remove} -\begin{lstlisting}[numbers=left,frame=single] - equiv_remove [options] [selection] - -This command removes the selected $equiv cells. If neither -gold nor -gate is -used then only proven cells are removed. - - -gold - keep gold circuit - - -gate - keep gate circuit -\end{lstlisting} - -\section{equiv\_simple -- try proving simple \$equiv instances} -\label{cmd:equiv_simple} -\begin{lstlisting}[numbers=left,frame=single] - equiv_simple [options] [selection] - -This command tries to prove $equiv cells using a simple direct SAT approach. - - -v - verbose output - - -undef - enable modelling of undef states - - -short - create shorter input cones that stop at shared nodes. This yields - simpler SAT problems but sometimes fails to prove equivalence. - - -nogroup - disabling grouping of $equiv cells by output wire - - -seq - the max. number of time steps to be considered (default = 1) -\end{lstlisting} - -\section{equiv\_status -- print status of equivalent checking module} -\label{cmd:equiv_status} -\begin{lstlisting}[numbers=left,frame=single] - equiv_status [options] [selection] - -This command prints status information for all selected $equiv cells. - - -assert - produce an error if any unproven $equiv cell is found -\end{lstlisting} - -\section{equiv\_struct -- structural equivalence checking} -\label{cmd:equiv_struct} -\begin{lstlisting}[numbers=left,frame=single] - equiv_struct [options] [selection] - -This command adds additional $equiv cells based on the assumption that the -gold and gate circuit are structurally equivalent. Note that this can introduce -bad $equiv cells in cases where the netlists are not structurally equivalent, -for example when analyzing circuits with cells with commutative inputs. This -command will also de-duplicate gates. - - -fwd - by default this command performans forward sweeps until nothing can - be merged by forwards sweeps, then backward sweeps until forward - sweeps are effective again. with this option set only forward sweeps - are performed. - - -fwonly - add the specified cell type to the list of cell types that are only - merged in forward sweeps and never in backward sweeps. $equiv is in - this list automatically. - - -icells - by default, the internal RTL and gate cell types are ignored. add - this option to also process those cell types with this command. - - -maxiter - maximum number of iterations to run before aborting -\end{lstlisting} - -\section{eval -- evaluate the circuit given an input} -\label{cmd:eval} -\begin{lstlisting}[numbers=left,frame=single] - eval [options] [selection] - -This command evaluates the value of a signal given the value of all required -inputs. - - -set - set the specified signal to the specified value. - - -set-undef - set all unspecified source signals to undef (x) - - -table - create a truth table using the specified input signals - - -show - show the value for the specified signal. if no -show option is passed - then all output ports of the current module are used. -\end{lstlisting} - -\section{expose -- convert internal signals to module ports} -\label{cmd:expose} -\begin{lstlisting}[numbers=left,frame=single] - expose [options] [selection] - -This command exposes all selected internal signals of a module as additional -outputs. - - -dff - only consider wires that are directly driven by register cell. - - -cut - when exposing a wire, create an input/output pair and cut the internal - signal path at that wire. - - -input - when exposing a wire, create an input port and disconnect the internal - driver. - - -shared - only expose those signals that are shared among the selected modules. - this is useful for preparing modules for equivalence checking. - - -evert - also turn connections to instances of other modules to additional - inputs and outputs and remove the module instances. - - -evert-dff - turn flip-flops to sets of inputs and outputs. - - -sep - when creating new wire/port names, the original object name is suffixed - with this separator (default: '.') and the port name or a type - designator for the exposed signal. -\end{lstlisting} - -\section{extract -- find subcircuits and replace them with cells} -\label{cmd:extract} -\begin{lstlisting}[numbers=left,frame=single] - extract -map [options] [selection] - extract -mine [options] [selection] - -This pass looks for subcircuits that are isomorphic to any of the modules -in the given map file and replaces them with instances of this modules. The -map file can be a Verilog source file (*.v) or an ilang file (*.il). - - -map - use the modules in this file as reference. This option can be used - multiple times. - - -map % - use the modules in this in-memory design as reference. This option can - be used multiple times. - - -verbose - print debug output while analyzing - - -constports - also find instances with constant drivers. this may be much - slower than the normal operation. - - -nodefaultswaps - normally builtin port swapping rules for internal cells are used per - default. This turns that off, so e.g. 'a^b' does not match 'b^a' - when this option is used. - - -compat - Per default, the cells in the map file (needle) must have the - type as the cells in the active design (haystack). This option - can be used to register additional pairs of types that should - match. This option can be used multiple times. - - -swap ,[,...] - Register a set of swappable ports for a needle cell type. - This option can be used multiple times. - - -perm ,[,...] ,[,...] - Register a valid permutation of swappable ports for a needle - cell type. This option can be used multiple times. - - -cell_attr - Attributes on cells with the given name must match. - - -wire_attr - Attributes on wires with the given name must match. - - -ignore_parameters - Do not use parameters when matching cells. - - -ignore_param - Do not use this parameter when matching cells. - -This pass does not operate on modules with unprocessed processes in it. -(I.e. the 'proc' pass should be used first to convert processes to netlists.) - -This pass can also be used for mining for frequent subcircuits. In this mode -the following options are to be used instead of the -map option. - - -mine - mine for frequent subcircuits and write them to the given ilang file - - -mine_cells_span - only mine for subcircuits with the specified number of cells - default value: 3 5 - - -mine_min_freq - only mine for subcircuits with at least the specified number of matches - default value: 10 - - -mine_limit_matches_per_module - when calculating the number of matches for a subcircuit, don't count - more than the specified number of matches per module - - -mine_max_fanout - don't consider internal signals with more than connections - -The modules in the map file may have the attribute 'extract_order' set to an -integer value. Then this value is used to determine the order in which the pass -tries to map the modules to the design (ascending, default value is 0). - -See 'help techmap' for a pass that does the opposite thing. -\end{lstlisting} - -\section{extract\_counter -- Extract GreenPak4 counter cells} -\label{cmd:extract_counter} -\begin{lstlisting}[numbers=left,frame=single] - extract_counter [options] [selection] - -This pass converts non-resettable or async resettable down counters to -counter cells. Use a target-specific 'techmap' map file to convert those cells -to the actual target cells. - - -maxwidth N - Only extract counters up to N bits wide - - -pout X,Y,... - Only allow parallel output from the counter to the listed cell types - (if not specified, parallel outputs are not restricted) -\end{lstlisting} - -\section{extract\_fa -- find and extract full/half adders} -\label{cmd:extract_fa} -\begin{lstlisting}[numbers=left,frame=single] - extract_fa [options] [selection] - -This pass extracts full/half adders from a gate-level design. - - -fa, -ha - Enable cell types (fa=full adder, ha=half adder) - All types are enabled if none of this options is used - - -d - Set maximum depth for extracted logic cones (default=20) - - -b - Set maximum breadth for extracted logic cones (default=6) - - -v - Verbose output -\end{lstlisting} - -\section{extract\_reduce -- converts gate chains into \$reduce\_* cells} -\label{cmd:extract_reduce} -\begin{lstlisting}[numbers=left,frame=single] - extract_reduce [options] [selection] - -converts gate chains into $reduce_* cells - -This command finds chains of $_AND_, $_OR_, and $_XOR_ cells and replaces them -with their corresponding $reduce_* cells. Because this command only operates on -these cell types, it is recommended to map the design to only these cell types -using the `abc -g` command. Note that, in some cases, it may be more effective -to map the design to only $_AND_ cells, run extract_reduce, map the remaining -parts of the design to AND/OR/XOR cells, and run extract_reduce a second time. - - -allow-off-chain - Allows matching of cells that have loads outside the chain. These cells - will be replicated and folded into the $reduce_* cell, but the original - cell will remain, driving its original loads. -\end{lstlisting} - -\section{flatten -- flatten design} -\label{cmd:flatten} -\begin{lstlisting}[numbers=left,frame=single] - flatten [selection] - -This pass flattens the design by replacing cells by their implementation. This -pass is very similar to the 'techmap' pass. The only difference is that this -pass is using the current design as mapping library. - -Cells and/or modules with the 'keep_hierarchy' attribute set will not be -flattened by this command. -\end{lstlisting} - -\section{freduce -- perform functional reduction} -\label{cmd:freduce} -\begin{lstlisting}[numbers=left,frame=single] - freduce [options] [selection] - -This pass performs functional reduction in the circuit. I.e. if two nodes are -equivalent, they are merged to one node and one of the redundant drivers is -disconnected. A subsequent call to 'clean' will remove the redundant drivers. - - -v, -vv - enable verbose or very verbose output - - -inv - enable explicit handling of inverted signals - - -stop - stop after reduction operations. this is mostly used for - debugging the freduce command itself. - - -dump - dump the design to __.il after each reduction - operation. this is mostly used for debugging the freduce command. - -This pass is undef-aware, i.e. it considers don't-care values for detecting -equivalent nodes. - -All selected wires are considered for rewiring. The selected cells cover the -circuit that is analyzed. -\end{lstlisting} - -\section{fsm -- extract and optimize finite state machines} -\label{cmd:fsm} -\begin{lstlisting}[numbers=left,frame=single] - fsm [options] [selection] - -This pass calls all the other fsm_* passes in a useful order. This performs -FSM extraction and optimization. It also calls opt_clean as needed: - - fsm_detect unless got option -nodetect - fsm_extract - - fsm_opt - opt_clean - fsm_opt - - fsm_expand if got option -expand - opt_clean if got option -expand - fsm_opt if got option -expand - - fsm_recode unless got option -norecode - - fsm_info - - fsm_export if got option -export - fsm_map unless got option -nomap - -Options: - - -expand, -norecode, -export, -nomap - enable or disable passes as indicated above - - -fullexpand - call expand with -full option - - -encoding type - -fm_set_fsm_file file - -encfile file - passed through to fsm_recode pass -\end{lstlisting} - -\section{fsm\_detect -- finding FSMs in design} -\label{cmd:fsm_detect} -\begin{lstlisting}[numbers=left,frame=single] - fsm_detect [selection] - -This pass detects finite state machines by identifying the state signal. -The state signal is then marked by setting the attribute 'fsm_encoding' -on the state signal to "auto". - -Existing 'fsm_encoding' attributes are not changed by this pass. - -Signals can be protected from being detected by this pass by setting the -'fsm_encoding' attribute to "none". -\end{lstlisting} - -\section{fsm\_expand -- expand FSM cells by merging logic into it} -\label{cmd:fsm_expand} -\begin{lstlisting}[numbers=left,frame=single] - fsm_expand [-full] [selection] - -The fsm_extract pass is conservative about the cells that belong to a finite -state machine. This pass can be used to merge additional auxiliary gates into -the finite state machine. - -By default, fsm_expand is still a bit conservative regarding merging larger -word-wide cells. Call with -full to consider all cells for merging. -\end{lstlisting} - -\section{fsm\_export -- exporting FSMs to KISS2 files} -\label{cmd:fsm_export} -\begin{lstlisting}[numbers=left,frame=single] - fsm_export [-noauto] [-o filename] [-origenc] [selection] - -This pass creates a KISS2 file for every selected FSM. For FSMs with the -'fsm_export' attribute set, the attribute value is used as filename, otherwise -the module and cell name is used as filename. If the parameter '-o' is given, -the first exported FSM is written to the specified filename. This overwrites -the setting as specified with the 'fsm_export' attribute. All other FSMs are -exported to the default name as mentioned above. - - -noauto - only export FSMs that have the 'fsm_export' attribute set - - -o filename - filename of the first exported FSM - - -origenc - use binary state encoding as state names instead of s0, s1, ... -\end{lstlisting} - -\section{fsm\_extract -- extracting FSMs in design} -\label{cmd:fsm_extract} -\begin{lstlisting}[numbers=left,frame=single] - fsm_extract [selection] - -This pass operates on all signals marked as FSM state signals using the -'fsm_encoding' attribute. It consumes the logic that creates the state signal -and uses the state signal to generate control signal and replaces it with an -FSM cell. - -The generated FSM cell still generates the original state signal with its -original encoding. The 'fsm_opt' pass can be used in combination with the -'opt_clean' pass to eliminate this signal. -\end{lstlisting} - -\section{fsm\_info -- print information on finite state machines} -\label{cmd:fsm_info} -\begin{lstlisting}[numbers=left,frame=single] - fsm_info [selection] - -This pass dumps all internal information on FSM cells. It can be useful for -analyzing the synthesis process and is called automatically by the 'fsm' -pass so that this information is included in the synthesis log file. -\end{lstlisting} - -\section{fsm\_map -- mapping FSMs to basic logic} -\label{cmd:fsm_map} -\begin{lstlisting}[numbers=left,frame=single] - fsm_map [selection] - -This pass translates FSM cells to flip-flops and logic. -\end{lstlisting} - -\section{fsm\_opt -- optimize finite state machines} -\label{cmd:fsm_opt} -\begin{lstlisting}[numbers=left,frame=single] - fsm_opt [selection] - -This pass optimizes FSM cells. It detects which output signals are actually -not used and removes them from the FSM. This pass is usually used in -combination with the 'opt_clean' pass (see also 'help fsm'). -\end{lstlisting} - -\section{fsm\_recode -- recoding finite state machines} -\label{cmd:fsm_recode} -\begin{lstlisting}[numbers=left,frame=single] - fsm_recode [options] [selection] - -This pass reassign the state encodings for FSM cells. At the moment only -one-hot encoding and binary encoding is supported. - -encoding - specify the encoding scheme used for FSMs without the - 'fsm_encoding' attribute or with the attribute set to `auto'. - - -fm_set_fsm_file - generate a file containing the mapping from old to new FSM encoding - in form of Synopsys Formality set_fsm_* commands. - - -encfile - write the mappings from old to new FSM encoding to a file in the - following format: - - .fsm - .map -\end{lstlisting} - -\section{greenpak4\_dffinv -- merge greenpak4 inverters and DFF/latches} -\label{cmd:greenpak4_dffinv} -\begin{lstlisting}[numbers=left,frame=single] - greenpak4_dffinv [options] [selection] - -Merge GP_INV cells with GP_DFF* and GP_DLATCH* cells. -\end{lstlisting} - -\section{help -- display help messages} -\label{cmd:help} -\begin{lstlisting}[numbers=left,frame=single] - help ................ list all commands - help ...... print help message for given command - help -all ........... print complete command reference - - help -cells .......... list all cell types - help ..... print help message for given cell type - help + .... print verilog code for given cell type -\end{lstlisting} - -\section{hierarchy -- check, expand and clean up design hierarchy} -\label{cmd:hierarchy} -\begin{lstlisting}[numbers=left,frame=single] - hierarchy [-check] [-top ] - hierarchy -generate - -In parametric designs, a module might exists in several variations with -different parameter values. This pass looks at all modules in the current -design an re-runs the language frontends for the parametric modules as -needed. - - -check - also check the design hierarchy. this generates an error when - an unknown module is used as cell type. - - -simcheck - like -check, but also thow an error if blackbox modules are - instantiated, and throw an error if the design has no top module - - -purge_lib - by default the hierarchy command will not remove library (blackbox) - modules. use this option to also remove unused blackbox modules. - - -libdir - search for files named .v in the specified directory - for unknown modules and automatically run read_verilog for each - unknown module. - - -keep_positionals - per default this pass also converts positional arguments in cells - to arguments using port names. this option disables this behavior. - - -keep_portwidths - per default this pass adjusts the port width on cells that are - module instances when the width does not match the module port. this - option disables this behavior. - - -nokeep_asserts - per default this pass sets the "keep" attribute on all modules - that directly or indirectly contain one or more $assert cells. this - option disables this behavior. - - -top - use the specified top module to built a design hierarchy. modules - outside this tree (unused modules) are removed. - - when the -top option is used, the 'top' attribute will be set on the - specified top module. otherwise a module with the 'top' attribute set - will implicitly be used as top module, if such a module exists. - - -auto-top - automatically determine the top of the design hierarchy and mark it. - -In -generate mode this pass generates blackbox modules for the given cell -types (wildcards supported). For this the design is searched for cells that -match the given types and then the given port declarations are used to -determine the direction of the ports. The syntax for a port declaration is: - - {i|o|io}[@]: - -Input ports are specified with the 'i' prefix, output ports with the 'o' -prefix and inout ports with the 'io' prefix. The optional specifies -the position of the port in the parameter list (needed when instantiated -using positional arguments). When is not specified, the can -also contain wildcard characters. - -This pass ignores the current selection and always operates on all modules -in the current design. -\end{lstlisting} - -\section{hilomap -- technology mapping of constant hi- and/or lo-drivers} -\label{cmd:hilomap} -\begin{lstlisting}[numbers=left,frame=single] - hilomap [options] [selection] - -Map constants to 'tielo' and 'tiehi' driver cells. - - -hicell - Replace constant hi bits with this cell. - - -locell - Replace constant lo bits with this cell. - - -singleton - Create only one hi/lo cell and connect all constant bits - to that cell. Per default a separate cell is created for - each constant bit. -\end{lstlisting} - -\section{history -- show last interactive commands} -\label{cmd:history} -\begin{lstlisting}[numbers=left,frame=single] - history - -This command prints all commands in the shell history buffer. This are -all commands executed in an interactive session, but not the commands -from executed scripts. -\end{lstlisting} - -\section{ice40\_ffinit -- iCE40: handle FF init values} -\label{cmd:ice40_ffinit} -\begin{lstlisting}[numbers=left,frame=single] - ice40_ffinit [options] [selection] - -Remove zero init values for FF output signals. Add inverters to implement -nonzero init values. -\end{lstlisting} - -\section{ice40\_ffssr -- iCE40: merge synchronous set/reset into FF cells} -\label{cmd:ice40_ffssr} -\begin{lstlisting}[numbers=left,frame=single] - ice40_ffssr [options] [selection] - -Merge synchronous set/reset $_MUX_ cells into iCE40 FFs. -\end{lstlisting} - -\section{ice40\_opt -- iCE40: perform simple optimizations} -\label{cmd:ice40_opt} -\begin{lstlisting}[numbers=left,frame=single] - ice40_opt [options] [selection] - -This command executes the following script: - - do - - opt_expr -mux_undef -undriven [-full] - opt_merge - opt_rmdff - opt_clean - while - -When called with the option -unlut, this command will transform all already -mapped SB_LUT4 cells back to logic. -\end{lstlisting} - -\section{insbuf -- insert buffer cells for connected wires} -\label{cmd:insbuf} -\begin{lstlisting}[numbers=left,frame=single] - insbuf [options] [selection] - -Insert buffer cells into the design for directly connected wires. - - -buf - Use the given cell type instead of $_BUF_. (Notice that the next - call to "clean" will remove all $_BUF_ in the design.) -\end{lstlisting} - -\section{iopadmap -- technology mapping of i/o pads (or buffers)} -\label{cmd:iopadmap} -\begin{lstlisting}[numbers=left,frame=single] - iopadmap [options] [selection] - -Map module inputs/outputs to PAD cells from a library. This pass -can only map to very simple PAD cells. Use 'techmap' to further map -the resulting cells to more sophisticated PAD cells. - - -inpad [:] - Map module input ports to the given cell type with the - given output port name. if a 2nd portname is given, the - signal is passed through the pad call, using the 2nd - portname as the port facing the module port. - - -outpad [:] - -inoutpad [:] - Similar to -inpad, but for output and inout ports. - - -toutpad :[:] - Merges $_TBUF_ cells into the output pad cell. This takes precedence - over the other -outpad cell. The first portname is the enable input - of the tristate driver. - - -tinoutpad ::[:] - Merges $_TBUF_ cells into the inout pad cell. This takes precedence - over the other -inoutpad cell. The first portname is the enable input - of the tristate driver and the 2nd portname is the internal output - buffering the external signal. - - -widthparam - Use the specified parameter name to set the port width. - - -nameparam - Use the specified parameter to set the port name. - - -bits - create individual bit-wide buffers even for ports that - are wider. (the default behavior is to create word-wide - buffers using -widthparam to set the word size on the cell.) - -Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode. -\end{lstlisting} - -\section{json -- write design in JSON format} -\label{cmd:json} -\begin{lstlisting}[numbers=left,frame=single] - json [options] [selection] - -Write a JSON netlist of all selected objects. - - -o - write to the specified file. - - -aig - also include AIG models for the different gate types - -See 'help write_json' for a description of the JSON format used. -\end{lstlisting} - -\section{log -- print text and log files} -\label{cmd:log} -\begin{lstlisting}[numbers=left,frame=single] - log string - -Print the given string to the screen and/or the log file. This is useful for TCL -scripts, because the TCL command "puts" only goes to stdout but not to -logfiles. - - -stdout - Print the output to stdout too. This is useful when all Yosys is executed - with a script and the -q (quiet operation) argument to notify the user. - - -stderr - Print the output to stderr too. - - -nolog - Don't use the internal log() command. Use either -stdout or -stderr, - otherwise no output will be generated at all. - - -n - do not append a newline -\end{lstlisting} - -\section{ls -- list modules or objects in modules} -\label{cmd:ls} -\begin{lstlisting}[numbers=left,frame=single] - ls [selection] - -When no active module is selected, this prints a list of modules. - -When an active module is selected, this prints a list of objects in the module. -\end{lstlisting} - -\section{ltp -- print longest topological path} -\label{cmd:ltp} -\begin{lstlisting}[numbers=left,frame=single] - ltp [options] [selection] - -This command prints the longest topological path in the design. (Only considers -paths within a single module, so the design must be flattened.) - - -noff - automatically exclude FF cell types -\end{lstlisting} - -\section{lut2mux -- convert \$lut to \$\_MUX\_} -\label{cmd:lut2mux} -\begin{lstlisting}[numbers=left,frame=single] - lut2mux [options] [selection] - -This pass converts $lut cells to $_MUX_ gates. -\end{lstlisting} - -\section{maccmap -- mapping macc cells} -\label{cmd:maccmap} -\begin{lstlisting}[numbers=left,frame=single] - maccmap [-unmap] [selection] - -This pass maps $macc cells to yosys $fa and $alu cells. When the -unmap option -is used then the $macc cell is mapped to $add, $sub, etc. cells instead. -\end{lstlisting} - -\section{memory -- translate memories to basic cells} -\label{cmd:memory} -\begin{lstlisting}[numbers=left,frame=single] - memory [-nomap] [-nordff] [-memx] [-bram ] [selection] - -This pass calls all the other memory_* passes in a useful order: - - memory_dff [-nordff] (-memx implies -nordff) - opt_clean - memory_share - opt_clean - memory_memx (when called with -memx) - memory_collect - memory_bram -rules (when called with -bram) - memory_map (skipped if called with -nomap) - -This converts memories to word-wide DFFs and address decoders -or multiport memory blocks if called with the -nomap option. -\end{lstlisting} - -\section{memory\_bram -- map memories to block rams} -\label{cmd:memory_bram} -\begin{lstlisting}[numbers=left,frame=single] - memory_bram -rules [selection] - -This pass converts the multi-port $mem memory cells into block ram instances. -The given rules file describes the available resources and how they should be -used. - -The rules file contains a set of block ram description and a sequence of match -rules. A block ram description looks like this: - - bram RAMB1024X32 # name of BRAM cell - init 1 # set to '1' if BRAM can be initialized - abits 10 # number of address bits - dbits 32 # number of data bits - groups 2 # number of port groups - ports 1 1 # number of ports in each group - wrmode 1 0 # set to '1' if this groups is write ports - enable 4 1 # number of enable bits - transp 0 2 # transparent (for read ports) - clocks 1 2 # clock configuration - clkpol 2 2 # clock polarity configuration - endbram - -For the option 'transp' the value 0 means non-transparent, 1 means transparent -and a value greater than 1 means configurable. All groups with the same -value greater than 1 share the same configuration bit. - -For the option 'clocks' the value 0 means non-clocked, and a value greater -than 0 means clocked. All groups with the same value share the same clock -signal. - -For the option 'clkpol' the value 0 means negative edge, 1 means positive edge -and a value greater than 1 means configurable. All groups with the same value -greater than 1 share the same configuration bit. - -Using the same bram name in different bram blocks will create different variants -of the bram. Verilog configuration parameters for the bram are created as needed. - -It is also possible to create variants by repeating statements in the bram block -and appending '@