diff --git a/dev/subtree_config.xml b/dev/subtree_config.xml index a1dc1c57d70..14d01ac753e 100644 --- a/dev/subtree_config.xml +++ b/dev/subtree_config.xml @@ -58,7 +58,7 @@ name="yosys" internal_path="yosys" external_url="https://github.com/YosysHQ/yosys.git" - default_external_ref="yosys-0.26"/> + default_external_ref="yosys-0.30"/> - - If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area - or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA). - - - If you have a feature request, please fill out the appropriate issue form, this form is for bugs and/or regressions. - - - Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need - commercial support for Yosys. - - - type: input - id: yosys_version - attributes: - label: Version - description: "The version of yosys this bug was encountered on." - placeholder: "The output of `yosys --version`" - validations: - required: true - - - type: dropdown - id: os - attributes: - label: On which OS did this happen? - options: - - Linux - - macOS - - Windows - - BSD - multiple: true - validations: - required: true - - - type: markdown - attributes: - value: > - When providing steps to reproduce the issue, please ensure that the issue - is reproducible in the current git master of Yosys. Also ensure to - provide all necessary source files needed. - - - Please see [https://stackoverflow.com/help/mcve](https://stackoverflow.com/help/mcve) - for information on how to create a Minimal, Complete, and Verifiable Example - (MCVE). - - - type: textarea - id: reproduction_steps - attributes: - label: Reproduction Steps - description: "Please provide clear and concise steps to reproduce the issue." - validations: - required: true - - - type: textarea - id: expected_behavior - attributes: - label: Expected Behavior - description: "Please describe the behavior you would have expected from the tool." - validations: - required: true - - - type: textarea - id: actual_behavior - attributes: - label: Actual Behavior - description: "Please describe how the behavior you see differs from the expected behavior." - validations: - required: true diff --git a/yosys/.github/ISSUE_TEMPLATE/config.yml b/yosys/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index bef410a3c92..00000000000 --- a/yosys/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,11 +0,0 @@ -contact_links: - - name: Discussions - url: https://github.com/YosysHQ/yosys/discussions - about: "Have a question? Ask it on our discussions page!" - - name: Community Slack - url: https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA - about: "Yosys Community Slack" - - name: IRC Channel - url: https://web.libera.chat/#yosys - about: "#yosys on irc.libera.chat" - diff --git a/yosys/.github/ISSUE_TEMPLATE/feature_request.yml b/yosys/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index c521b529631..00000000000 --- a/yosys/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Feature Request -description: "Submit a feature request for Yosys" -labels: ["feature-request"] -body: - - type: markdown - attributes: - value: > - - If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area - or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA). - - - If you have a bug report, please fill out the appropriate issue form, this form is for feature requests. - - - Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need - commercial support or work done for Yosys. - - - type: textarea - id: feature_description - attributes: - label: Feature Description - description: "A clear and detailed description of the feature." - validations: - required: true - diff --git a/yosys/.github/workflows/codeql.yml b/yosys/.github/workflows/codeql.yml deleted file mode 100644 index 2a046703bc0..00000000000 --- a/yosys/.github/workflows/codeql.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: "CodeQL" - -on: - workflow_dispatch: - schedule: - - cron: '0 3 * * *' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - steps: - - name: Install deps - run: sudo apt-get install bison flex libreadline-dev tcl-dev libffi-dev - - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: cpp - queries: security-extended,security-and-quality - - - name: Build - run: make yosys -j6 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/yosys/.github/workflows/emcc.yml b/yosys/.github/workflows/emcc.yml deleted file mode 100644 index 295d9554b81..00000000000 --- a/yosys/.github/workflows/emcc.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Emscripten Build - -on: [push, pull_request] - -jobs: - emcc: - runs-on: ubuntu-latest - steps: - - uses: mymindstorm/setup-emsdk@v11 - - uses: actions/checkout@v3 - - name: Build - run: | - make config-emcc - make YOSYS_VER=latest - - uses: actions/upload-artifact@v3 - with: - name: yosysjs - path: yosysjs-latest.zip diff --git a/yosys/.github/workflows/test-linux.yml b/yosys/.github/workflows/test-linux.yml deleted file mode 100644 index eee556794af..00000000000 --- a/yosys/.github/workflows/test-linux.yml +++ /dev/null @@ -1,116 +0,0 @@ -name: Build and run tests (Linux) - -on: [push, pull_request] - -jobs: - test-linux: - runs-on: ${{ matrix.os.id }} - strategy: - matrix: - os: - - { id: ubuntu-20.04, name: focal } - compiler: - - 'clang-12' - - 'gcc-11' - cpp_std: - - 'c++11' - - 'c++14' - - 'c++17' - - 'c++20' - include: - # Limit the older compilers to C++11 mode - - os: { id: ubuntu-20.04, name: focal } - compiler: 'clang-11' - cpp_std: 'c++11' - - os: { id: ubuntu-20.04, name: focal } - compiler: 'gcc-10' - cpp_std: 'c++11' - fail-fast: false - steps: - - name: Install Dependencies - shell: bash - run: | - sudo apt-get update - sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev - - - name: Setup GCC - if: startsWith(matrix.compiler, 'gcc') - shell: bash - run: | - CXX=${CC/#gcc/g++} - sudo apt-add-repository ppa:ubuntu-toolchain-r/test - sudo apt-get update - sudo apt-get install $CC $CXX - echo "CC=$CC" >> $GITHUB_ENV - echo "CXX=$CXX" >> $GITHUB_ENV - env: - CC: ${{ matrix.compiler }} - - - name: Setup Clang - if: startsWith(matrix.compiler, 'clang') - shell: bash - run: | - wget https://apt.llvm.org/llvm-snapshot.gpg.key - sudo apt-key add llvm-snapshot.gpg.key - rm llvm-snapshot.gpg.key - sudo apt-add-repository "deb https://apt.llvm.org/${{ matrix.os.name }}/ llvm-toolchain-${{ matrix.os.name }} main" - sudo apt-get update - CXX=${CC/#clang/clang++} - sudo apt-get install $CC $CXX - echo "CC=$CC" >> $GITHUB_ENV - echo "CXX=$CXX" >> $GITHUB_ENV - env: - CC: ${{ matrix.compiler }} - - - name: Runtime environment - shell: bash - env: - WORKSPACE: ${{ github.workspace }} - run: | - echo "GITHUB_WORKSPACE=`pwd`" >> $GITHUB_ENV - echo "$GITHUB_WORKSPACE/.local/bin" >> $GITHUB_PATH - echo "procs=$(nproc)" >> $GITHUB_ENV - - - name: Tool versions - shell: bash - run: | - $CC --version - $CXX --version - - - name: Checkout Yosys - uses: actions/checkout@v3 - - - name: Get iverilog - shell: bash - run: | - git clone https://github.com/steveicarus/iverilog.git - - - name: Cache iverilog - id: cache-iverilog - uses: actions/cache@v3 - with: - path: .local/ - key: ${{ matrix.os.id }}-${{ hashFiles('iverilog/.git/refs/heads/master') }} - - - name: Build iverilog - if: steps.cache-iverilog.outputs.cache-hit != 'true' - shell: bash - run: | - mkdir -p $GITHUB_WORKSPACE/.local/ - cd iverilog - autoconf - CC=gcc CXX=g++ ./configure --prefix=$GITHUB_WORKSPACE/.local - make -j${{ env.procs }} - make install - - - name: Build yosys - shell: bash - run: | - make config-${CC%%-*} - make -j${{ env.procs }} CCXXSTD=${{ matrix.cpp_std }} CC=$CC CXX=$CC LD=$CC - - - name: Run tests - if: (matrix.cpp_std == 'c++11') && (matrix.compiler == 'gcc-11') - shell: bash - run: | - make -j${{ env.procs }} test CXXSTD=${{ matrix.cpp_std }} CC=$CC CXX=$CC LD=$CC diff --git a/yosys/.github/workflows/test-macos.yml b/yosys/.github/workflows/test-macos.yml deleted file mode 100644 index 04845723467..00000000000 --- a/yosys/.github/workflows/test-macos.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Build and run tests (macOS) - -on: [push, pull_request] - -jobs: - test-macos: - runs-on: ${{ matrix.os.id }} - strategy: - matrix: - os: - - { id: macos-11, name: 'Big Sur' } - cpp_std: - - 'c++11' - - 'c++17' - fail-fast: false - steps: - - name: Install Dependencies - run: | - brew install bison flex gawk libffi pkg-config bash - - - name: Runtime environment - shell: bash - env: - WORKSPACE: ${{ github.workspace }} - run: | - echo "GITHUB_WORKSPACE=`pwd`" >> $GITHUB_ENV - echo "$GITHUB_WORKSPACE/.local/bin" >> $GITHUB_PATH - echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH - echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH - echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV - - - name: Tool versions - shell: bash - run: | - cc --version - - - name: Checkout Yosys - uses: actions/checkout@v3 - - - name: Get iverilog - shell: bash - run: | - git clone https://github.com/steveicarus/iverilog.git - - - name: Cache iverilog - id: cache-iverilog - uses: actions/cache@v3 - with: - path: .local/ - key: ${{ matrix.os.id }}-${{ hashFiles('iverilog/.git/refs/heads/master') }} - - - name: Build iverilog - if: steps.cache-iverilog.outputs.cache-hit != 'true' - shell: bash - run: | - mkdir -p $GITHUB_WORKSPACE/.local/ - cd iverilog - autoconf - CC=gcc CXX=g++ ./configure --prefix=$GITHUB_WORKSPACE/.local/ - make -j${{ env.procs }} - make install - - - name: Build yosys - shell: bash - run: | - make config-clang - make -j${{ env.procs }} CXXSTD=${{ matrix.cpp_std }} CC=cc CXX=cc LD=cc - - - name: Run tests - if: matrix.cpp_std == 'c++11' - shell: bash - run: | - make -j${{ env.procs }} test CXXSTD=${{ matrix.cpp_std }} CC=cc CXX=cc LD=cc diff --git a/yosys/.github/workflows/version.yml b/yosys/.github/workflows/version.yml deleted file mode 100644 index c2a1756e9c6..00000000000 --- a/yosys/.github/workflows/version.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Bump version - -on: - workflow_dispatch: - schedule: - - cron: '0 0 * * *' - -jobs: - bump-version: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Take last commit - id: log - run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT - - name: Take repository - id: repo - run: echo "message=$GITHUB_REPOSITORY" >> $GITHUB_OUTPUT - - name: Bump version - if: "!contains(steps.log.outputs.message, 'Bump version') && contains(steps.repo.outputs.message, 'YosysHQ/yosys')" - run: | - make bumpversion - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot]" - git add Makefile - git commit -m "Bump version" - - name: Push changes # push the output folder to your repo - if: "!contains(steps.log.outputs.message, 'Bump version') && contains(steps.repo.outputs.message, 'YosysHQ/yosys')" - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/yosys/.github/workflows/vs.yml b/yosys/.github/workflows/vs.yml deleted file mode 100644 index 428770e7200..00000000000 --- a/yosys/.github/workflows/vs.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Visual Studio Build - -on: [push, pull_request] - -jobs: - yosys-vcxsrc: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Build - run: make vcxsrc YOSYS_VER=latest - - uses: actions/upload-artifact@v3 - with: - name: vcxsrc - path: yosys-win32-vcxsrc-latest.zip - - build: - runs-on: windows-2019 - needs: yosys-vcxsrc - steps: - - uses: actions/download-artifact@v3 - with: - name: vcxsrc - path: . - - name: unzip - run: unzip yosys-win32-vcxsrc-latest.zip - - name: setup-msbuild - uses: microsoft/setup-msbuild@v1 - - name: MSBuild - working-directory: yosys-win32-vcxsrc-latest - run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.17763.0 diff --git a/yosys/.gitignore b/yosys/.gitignore deleted file mode 100644 index 49b886e7e43..00000000000 --- a/yosys/.gitignore +++ /dev/null @@ -1,46 +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.wasm -/yosys-abc -/yosys-abc.exe -/yosys-config -/yosys-smtbmc -/yosys-smtbmc.exe -/yosys-smtbmc-script.py -/yosys-witness -/yosys-witness.exe -/yosys-witness-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/.mailmap b/yosys/.mailmap deleted file mode 100644 index 78afe1b6cc9..00000000000 --- a/yosys/.mailmap +++ /dev/null @@ -1,7 +0,0 @@ -Marcelina Kościelnicka -Marcelina Kościelnicka -Marcelina Kościelnicka -Claire Xenia Wolf -Claire Xenia Wolf -Claire Xenia Wolf -Claire Xenia Wolf diff --git a/yosys/Brewfile b/yosys/Brewfile deleted file mode 100644 index b50c70a4b0e..00000000000 --- a/yosys/Brewfile +++ /dev/null @@ -1,12 +0,0 @@ -brew "bison" -brew "flex" -brew "gawk" -brew "libffi" -brew "git" -brew "graphviz" -brew "pkg-config" -brew "python3" -brew "tcl-tk" -brew "xdot" -brew "bash" -brew 'boost-python3' diff --git a/yosys/CHANGELOG b/yosys/CHANGELOG index 1d7a6fc9d88..a461564081e 100644 --- a/yosys/CHANGELOG +++ b/yosys/CHANGELOG @@ -2,6 +2,60 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.29 .. Yosys 0.30 +-------------------------- + * New commands and options + - Added "recover_names" pass to recover names post-mapping. + + * Gowin support + - Added remaining primitives blackboxes. + + * Various + - "show -colorattr" will now color the cells, wires, and + connection arrows. + - "show -viewer none" will not execute viewer. + +Yosys 0.28 .. Yosys 0.29 +-------------------------- + * New commands and options + - Added "synthprop" pass for synthesizable properties. + + * Verific support + - Handle conditions on clocked concurrent assertions in unclocked + procedural contexts. + + * Verilog + - Fix const eval of unbased unsized constants. + - Handling of attributes for struct / union variables. + +Yosys 0.27 .. Yosys 0.28 +-------------------------- + * Verilog + - Out of bounds checking for struct/union members. + + * Verific support + - Fix enum_values support and signed attribute values. + + * ECP5 support + - Added "synth_ecp5 -iopad" + + * MachXO2 support + - Added "synth_machxo2 -ccu2" + +Yosys 0.26 .. Yosys 0.27 +-------------------------- + * New commands and options + - Added option "-make_assert" to "equiv_make" pass. + - Added option "-coverenable" to "chformal" pass. + + * Verilog + - Resolve package types in interfaces. + - Handle range offsets in packed arrays within packed structs. + - Support for data and array queries on struct/union item expressions. + + * GateMate support + - Enable register initialization. + Yosys 0.25 .. Yosys 0.26 -------------------------- * New commands and options diff --git a/yosys/CODEOWNERS b/yosys/CODEOWNERS deleted file mode 100644 index a33a9a68ccb..00000000000 --- a/yosys/CODEOWNERS +++ /dev/null @@ -1,46 +0,0 @@ -## CODE NOTIFICATIONS -# Register yourself here to be notified about modifications -# for any files you have an interest in/know your way around. - -# Each line is a file pattern followed by one or more users. -# Both github usernames and email addresses are supported. -# Order is important; the last matching pattern takes the most -# precedence. Previous matches will not be applied. - - -# PATH (can use glob) USERNAME(S) - -passes/cmds/scratchpad.cc @nakengelhardt -frontends/rpc/ @whitequark -backends/cxxrtl/ @whitequark -passes/cmds/bugpoint.cc @whitequark -passes/techmap/flowmap.cc @whitequark -passes/opt/opt_lut.cc @whitequark -passes/techmap/abc9*.cc @eddiehung @Ravenslofty -backends/aiger/xaiger.cc @eddiehung - - -## External Contributors -# Only users with write permission to the repository get review -# requests automatically, but we add information for other -# contributors here too, so we know who to ask to take a look. -# These still override previous lines, so be careful not to -# accidentally disable any of the above rules. - -frontends/verilog/ @zachjs -frontends/ast/ @zachjs - -techlibs/intel_alm/ @Ravenslofty -techlibs/gowin/ @pepijndevos -techlibs/gatemate/ @pu-cc - -# pyosys -misc/*.py @btut - -backends/firrtl @ucbjrl @azidar - -passes/sat/qbfsat.cc @boqwxp -passes/sat/qbfsat.h @boqwxp -passes/cmds/exec.cc @boqwxp -passes/cmds/glift.cc @boqwxp -passes/cmds/printattrs.cc @boqwxp diff --git a/yosys/COPYING b/yosys/COPYING deleted file mode 100644 index e8b123be234..00000000000 --- a/yosys/COPYING +++ /dev/null @@ -1,15 +0,0 @@ -ISC License - -Copyright (C) 2012 - 2020 Claire Xenia 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/Dockerfile b/yosys/Dockerfile deleted file mode 100644 index 549c73c9712..00000000000 --- a/yosys/Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -ARG IMAGE="python:3-slim-buster" - -#--- - -FROM $IMAGE AS base - -RUN apt-get update -qq \ - && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \ - ca-certificates \ - clang \ - curl \ - libffi-dev \ - libreadline-dev \ - tcl-dev \ - graphviz \ - xdot \ - && apt-get autoclean && apt-get clean && apt-get -y autoremove \ - && update-ca-certificates \ - && rm -rf /var/lib/apt/lists - -#--- - -FROM base AS build - -RUN apt-get update -qq \ - && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \ - bison \ - flex \ - gawk \ - gcc \ - git \ - iverilog \ - pkg-config \ - && apt-get autoclean && apt-get clean && apt-get -y autoremove \ - && rm -rf /var/lib/apt/lists - -COPY . /yosys - -ENV PREFIX /opt/yosys - -RUN cd /yosys \ - && make \ - && make install \ - && make test - -#--- - -FROM base - -COPY --from=build /opt/yosys /opt/yosys - -ENV PATH /opt/yosys/bin:$PATH - -RUN useradd -m yosys -USER yosys - -CMD ["yosys"] diff --git a/yosys/Makefile b/yosys/Makefile index 826562fdf48..3ff983198a8 100644 --- a/yosys/Makefile +++ b/yosys/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.26 +YOSYS_VER := 0.30 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -149,7 +149,7 @@ YOSYS_VER := 0.26 # back to calling git directly. TARBALL_GIT_REV := $(shell cat $(YOSYS_SRC)/.gitcommit) ifeq ($(TARBALL_GIT_REV),$$Format:%h$$) -GIT_REV := $(shell git ls-remote $(YOSYS_SRC) HEAD -q | $(AWK) 'BEGIN {R = "UNKNOWN"}; ($$2 == "HEAD") {R = substr($$1, 1, 9); exit} END {print R}') +GIT_REV := $(shell GIT_DIR=$(YOSYS_SRC)/.git git rev-parse --short=9 HEAD || echo UNKNOWN) else GIT_REV := $(TARBALL_GIT_REV) endif @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline e02b7f6.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 9c5a60e.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # @@ -165,7 +165,7 @@ bumpversion: # 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 = a8f0ef2 +ABCREV = 2c1c83f ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -797,13 +797,13 @@ ifneq ($(ABCREV),default) $(Q) if test -d abc && test -d abc/.git && ! git -C abc 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 -d abc && ! test -d abc/.git && ! test "`cat abc/.gitcommit | cut -c1-7`" == "$(ABCREV)"; then \ + $(Q) if test -d abc && ! test -d abc/.git && ! test "`cat abc/.gitcommit | cut -c1-7`" = "$(ABCREV)"; then \ echo 'REEBE: Qbjaybnqrq NOP irefvbaf qbrf abg zngpu! Qbjaybnq sebz:' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; echo $(ABCURL)/archive/$(ABCREV).tar.gz; false; \ fi # set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string - $(Q) if test -d abc && ! test -d abc/.git && test "`cat abc/.gitcommit | cut -c1-7`" == "$(ABCREV)"; then \ + $(Q) if test -d abc && ! test -d abc/.git && test "`cat abc/.gitcommit | cut -c1-7`" = "$(ABCREV)"; then \ echo "Compiling local copy of ABC"; \ - elif ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \ + elif ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" = "$$rev"); 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; \ @@ -837,6 +837,9 @@ ABCOPT="" endif test: $(TARGETS) $(EXTRA_TARGETS) +ifeq ($(ENABLE_VERIFIC),1) + +cd tests/verific && bash run-test.sh $(SEEDOPT) +endif +cd tests/simple && bash run-test.sh $(SEEDOPT) +cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT) +cd tests/hana && bash run-test.sh $(SEEDOPT) diff --git a/yosys/README.md b/yosys/README.md deleted file mode 100644 index f3a63cbec39..00000000000 --- a/yosys/README.md +++ /dev/null @@ -1,617 +0,0 @@ -``` -yosys -- Yosys Open SYnthesis Suite - -Copyright (C) 2012 - 2020 Claire Xenia 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: -- https://yosyshq.net/yosys/ - -The "Documentation" page on the web site contains links to more resources, -including a manual that even describes some of the Yosys internals: -- https://yosyshq.net/yosys/documentation.html - -The directory `guidelines` 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 - - -Installation -============ - -Yosys is part of the [Tabby CAD Suite](https://www.yosyshq.com/tabby-cad-datasheet) and the [OSS CAD Suite](https://github.com/YosysHQ/oss-cad-suite-build)! The easiest way to use yosys is to install the binary software suite, which contains all required dependencies and related tools. - -* [Contact YosysHQ](https://www.yosyshq.com/contact) for a [Tabby CAD Suite](https://www.yosyshq.com/tabby-cad-datasheet) Evaluation License and download link -* OR go to https://github.com/YosysHQ/oss-cad-suite-build/releases to download the free OSS CAD Suite -* Follow the [Install Instructions on GitHub](https://github.com/YosysHQ/oss-cad-suite-build#installation) - -Make sure to get a Tabby CAD Suite Evaluation License if you need features such as industry-grade SystemVerilog and VHDL parsers! - -For more information about the difference between Tabby CAD Suite and the OSS CAD Suite, please visit https://www.yosyshq.com/tabby-cad-datasheet - -Many Linux distributions also provide Yosys binaries, some more up to date than others. Check with your package manager! - -Building from Source -==================== - -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 zlib1g-dev - -Similarily, on Mac OS X Homebrew can be used to install dependencies (from within cloned yosys repository): - - $ brew tap Homebrew/bundle && brew bundle - -or MacPorts: - - $ sudo port install bison flex readline gawk libffi \ - git graphviz pkgconfig python36 boost zlib tcl - -On FreeBSD use the following command to install all prerequisites: - - # pkg install bison flex readline gawk libffi\ - git graphviz pkgconf 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,zlib-devel - -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 - -To use a separate (out-of-tree) build directory, provide a path to the Makefile. - - $ mkdir build; cd build - $ make -f ../Makefile - -Out-of-tree builds require a clean source tree. - -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 and elaborating the design using the Verilog frontend: - - yosys> read -sv tests/simple/fiedler-cooley.v - yosys> hierarchy -top up3down5 - -writing the design to the console in Yosys's internal format: - - yosys> write_ilang - -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 - -or using a simple synthesis script: - - $ cat synth.ys - read -sv tests/simple/fiedler-cooley.v - hierarchy -top up3down5 - proc; opt; techmap; opt - write_verilog synth.v - - $ ./yosys synth.ys - -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: - - # read design - read -sv tests/simple/fiedler-cooley.v - hierarchy -top up3down5 - - # the high-level stuff - 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 -as simple example. - -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``): - - read -sv tests/simple/fiedler-cooley.v - synth -top up3down5 - - # mapping to target cells - dfflibmap -liberty mycells.lib - abc -liberty mycells.lib - clean - -The command ``prep`` provides a good default word-level synthesis script, as -used in SMT-based formal verification. - - -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 ``nowrshmsk`` attribute on a register prohibits the generation of - shift-and-mask type circuits for writing to bit slices of that register. - -- 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. It should contain a single - name, or, when describing a hierarchical name in a flattened design, multiple - names separated by a single space character. - -- 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). - -- Wires marked with the ``hierconn`` attribute are connected to wires with the - same name (format ``cell_name.identifier``) when they are imported from - sub-modules by ``flatten``. - -- The ``clkbuf_driver`` attribute can be set on an output port of a blackbox - module to mark it as a clock buffer output, and thus prevent ``clkbufmap`` - from inserting another clock buffer on a net driven by such output. - -- The ``clkbuf_sink`` attribute can be set on an input port of a module to - request clock buffer insertion by the ``clkbufmap`` pass. - -- The ``clkbuf_inv`` attribute can be set on an output port of a module - with the value set to the name of an input port of that module. When - the ``clkbufmap`` would otherwise insert a clock buffer on this output, - it will instead try inserting the clock buffer on the input port (this - is used to implement clock inverter cells that clock buffer insertion - will "see through"). - -- The ``clkbuf_inhibit`` is the default attribute to set on a wire to prevent - automatic clock buffer insertion by ``clkbufmap``. This behaviour can be - overridden by providing a custom selection to ``clkbufmap``. - -- The ``invertible_pin`` attribute can be set on a port to mark it as - invertible via a cell parameter. The name of the inversion parameter - is specified as the value of this attribute. The value of the inversion - parameter must be of the same width as the port, with 1 indicating - an inverted bit and 0 indicating a non-inverted bit. - -- The ``iopad_external_pin`` attribute on a blackbox module's port marks - it as the external-facing pin of an I/O pad, and prevents ``iopadmap`` - from inserting another pad cell on it. - -- The module attribute ``abc9_lut`` is an integer attribute indicating to - `abc9` that this module describes a LUT with an area cost of this value, and - propagation delays described using `specify` statements. - -- The module attribute ``abc9_box`` is a boolean specifying a black/white-box - definition, with propagation delays described using `specify` statements, for - use by `abc9`. - -- The port attribute ``abc9_carry`` marks the carry-in (if an input port) and - carry-out (if output port) ports of a box. This information is necessary for - `abc9` to preserve the integrity of carry-chains. Specifying this attribute - onto a bus port will affect only its most significant bit. - -- The module attribute ``abc9_flop`` is a boolean marking the module as a - flip-flop. This allows `abc9` to analyse its contents in order to perform - sequential synthesis. - -- The frontend sets attributes ``always_comb``, ``always_latch`` and - ``always_ff`` on processes derived from SystemVerilog style always blocks - according to the type of the always. These are checked for correctness in - ``proc_dlatch``. - -- The cell attribute ``wildcard_port_conns`` represents wildcard port - connections (SystemVerilog ``.*``). These are resolved to concrete - connections to matching wires in ``hierarchy``. - -- 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 - -- The ``wiretype`` attribute is added by the verilog parser for wires of a - typedef'd type to indicate the type identifier. - -- Various ``enum_value_{value}`` attributes are added to wires of an enumerated type - to give a map of possible enum items to their values. - -- The ``enum_base_type`` attribute is added to enum items to indicate which - enum they belong to (enums -- anonymous and otherwise -- are - automatically named with an auto-incrementing counter). Note that enums - are currently not strongly typed. - -- 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 these blocks are ignored.) - -- The ``reprocess_after`` internal attribute is used by the Verilog frontend to - mark cells with bindings which might depend on the specified instantiated - module. Modules with such cells will be reprocessed during the ``hierarchy`` - pass once the referenced module definition(s) become available. - -- The ``smtlib2_module`` attribute can be set on a blackbox module to specify a - formal model directly using SMT-LIB 2. For such a module, the - ``smtlib2_comb_expr`` attribute can be used on output ports to define their - value using an SMT-LIB 2 expression. For example: - - (* blackbox *) - (* smtlib2_module *) - module submod(a, b); - input [7:0] a; - (* smtlib2_comb_expr = "(bvnot a)" *) - output [7:0] b; - endmodule - -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. - -- typedefs are supported (including inside packages) - - type casts are currently not supported - -- enums are supported (including inside packages) - - but are currently not strongly typed - -- packed structs and unions are supported. - -- 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 visit https://yosys.readthedocs.io/en/latest/ instead. - -In addition to those packages listed above for building Yosys from source, the -following are used for building the website: - - $ sudo apt-get install pdf2svg faketime - -PDFLaTeX, included with most LaTeX distributions, is also needed during the -build process for the website. - -The Python package, Sphinx, is needed along with those listed in -`docs/source/requirements.txt`: - - $ pip install -U sphinx -r docs/source/requirements.txt - -From the root of the repository, run `make docs`. This will build/rebuild yosys -as necessary before generating the website documentation from the yosys help -commands. To build for pdf instead of html, call -`make docs DOC_TARGET=latexpdf`. diff --git a/yosys/backends/aiger/Makefile.inc b/yosys/backends/aiger/Makefile.inc deleted file mode 100644 index 4a4cf30bd47..00000000000 --- a/yosys/backends/aiger/Makefile.inc +++ /dev/null @@ -1,4 +0,0 @@ - -OBJS += backends/aiger/aiger.o -OBJS += backends/aiger/xaiger.o - diff --git a/yosys/backends/aiger/aiger.cc b/yosys/backends/aiger/aiger.cc index 4ef28be9f3b..bb804f230fb 100644 --- a/yosys/backends/aiger/aiger.cc +++ b/yosys/backends/aiger/aiger.cc @@ -119,14 +119,14 @@ struct AigerWriter if (wire->name.isPublic()) sigmap.add(wire); - // promote input wires + // promote output wires for (auto wire : module->wires()) - if (wire->port_input) + if (wire->port_output) sigmap.add(wire); - // promote output wires + // promote input wires for (auto wire : module->wires()) - if (wire->port_output) + if (wire->port_input) sigmap.add(wire); for (auto wire : module->wires()) @@ -706,6 +706,9 @@ struct AigerWriter for (auto &it : latch_lines) f << it.second; + if (initstate_ff) + f << stringf("ninitff %d\n", ((initstate_ff >> 1)-1-aig_i)); + wire_lines.sort(); for (auto &it : wire_lines) f << it.second; @@ -733,6 +736,9 @@ struct AigerWriter auto sig_qy = cell->getPort(cell->type.in(ID($anyconst), ID($anyseq)) ? ID::Y : ID::Q); SigSpec sig = sigmap(sig_qy); + if (cell->get_bool_attribute(ID(clk2fflogic))) + sig_qy = cell->getPort(ID::D); // For a clk2fflogic $_FF_ the named signal is the D input not the Q output + for (int i = 0; i < GetSize(sig_qy); i++) { if (sig_qy[i].wire == nullptr || sig[i].wire == nullptr) continue; diff --git a/yosys/backends/aiger/xaiger.cc b/yosys/backends/aiger/xaiger.cc deleted file mode 100644 index e223f185e5e..00000000000 --- a/yosys/backends/aiger/xaiger.cc +++ /dev/null @@ -1,809 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * 2019 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. - * - */ - -// https://stackoverflow.com/a/46137633 -#ifdef _MSC_VER -#include -#define bswap32 _byteswap_ulong -#elif defined(__APPLE__) -#include -#define bswap32 OSSwapInt32 -#elif defined(__GNUC__) -#define bswap32 __builtin_bswap32 -#else -#include -inline static uint32_t bswap32(uint32_t x) -{ - // https://stackoverflow.com/a/27796212 - register uint32_t value = number_to_be_reversed; - uint8_t lolo = (value >> 0) & 0xFF; - uint8_t lohi = (value >> 8) & 0xFF; - uint8_t hilo = (value >> 16) & 0xFF; - uint8_t hihi = (value >> 24) & 0xFF; - return (hihi << 24) - | (hilo << 16) - | (lohi << 8) - | (lolo << 0); -} -#endif - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" -#include "kernel/utils.h" -#include "kernel/timinginfo.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -inline int32_t to_big_endian(int32_t i32) { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - return bswap32(i32); -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - return i32; -#else -#error "Unknown endianness" -#endif -} - -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 XAigerWriter -{ - Design *design; - Module *module; - SigMap sigmap; - - dict init_map; - pool input_bits, output_bits; - dict not_map, alias_map; - dict> and_map; - vector ci_bits, co_bits; - vector ff_list; - dict arrival_times; - - vector> aig_gates; - vector aig_outputs; - int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0; - - dict aig_map; - dict ordered_outputs; - - vector box_list; - - 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) - { - auto it = aig_map.find(bit); - if (it != aig_map.end()) { - log_assert(it->second >= 0); - return it->second; - } - - // NB: Cannot use iterator returned from aig_map.insert() - // since this function is called recursively - - int a = -1; - if (not_map.count(bit)) { - a = bit2aig(not_map.at(bit)) ^ 1; - } else - if (and_map.count(bit)) { - auto args = and_map.at(bit); - int a0 = bit2aig(args.first); - int a1 = bit2aig(args.second); - a = mkgate(a0, a1); - } else - if (alias_map.count(bit)) { - a = bit2aig(alias_map.at(bit)); - } - - if (bit == State::Sx || bit == State::Sz) { - log_debug("Design contains 'x' or 'z' bits. Treating as 1'b0.\n"); - a = aig_map.at(State::S0); - } - - log_assert(a >= 0); - aig_map[bit] = a; - return a; - } - - XAigerWriter(Module *module, bool dff_mode) : design(module->design), module(module), sigmap(module) - { - pool undriven_bits; - pool unused_bits; - - // promote public wires - for (auto wire : module->wires()) - if (wire->name.isPublic()) - sigmap.add(wire); - - // promote input wires - for (auto wire : module->wires()) - if (wire->port_input) - sigmap.add(wire); - - // promote keep wires - for (auto wire : module->wires()) - if (wire->get_bool_attribute(ID::keep)) - sigmap.add(wire); - - for (auto wire : module->wires()) { - auto it = wire->attributes.find(ID::init); - 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); - - bool keep = wire->get_bool_attribute(ID::keep); - if (wire->port_output || keep) { - if (bit != wirebit) - alias_map[wirebit] = bit; - output_bits.insert(wirebit); - } - - if (it != wire->attributes.end()) { - auto s = it->second[i]; - if (s != State::Sx) { - auto r = init_map.insert(std::make_pair(bit, it->second[i])); - if (!r.second && r.first->second != it->second[i]) - log_error("Bit '%s' has a conflicting (* init *) value.\n", log_signal(bit)); - } - } - } - } - - TimingInfo timing; - - for (auto cell : module->cells()) { - if (!cell->has_keep_attr()) { - if (cell->type == ID($_NOT_)) - { - SigBit A = sigmap(cell->getPort(ID::A).as_bit()); - SigBit Y = sigmap(cell->getPort(ID::Y).as_bit()); - unused_bits.erase(A); - undriven_bits.erase(Y); - not_map[Y] = A; - continue; - } - - if (cell->type == ID($_AND_)) - { - SigBit A = sigmap(cell->getPort(ID::A).as_bit()); - SigBit B = sigmap(cell->getPort(ID::B).as_bit()); - SigBit Y = sigmap(cell->getPort(ID::Y).as_bit()); - unused_bits.erase(A); - unused_bits.erase(B); - undriven_bits.erase(Y); - and_map[Y] = make_pair(A, B); - continue; - } - - if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep)) - { - SigBit D = sigmap(cell->getPort(ID::D).as_bit()); - SigBit Q = sigmap(cell->getPort(ID::Q).as_bit()); - unused_bits.erase(D); - undriven_bits.erase(Q); - alias_map[Q] = D; - ff_list.emplace_back(cell); - continue; - } - - if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) - continue; - } - - RTLIL::Module* inst_module = design->module(cell->type); - if (inst_module && inst_module->get_blackbox_attribute()) { - bool abc9_flop = false; - - auto it = cell->attributes.find(ID::abc9_box_seq); - if (it != cell->attributes.end()) { - log_assert(!cell->has_keep_attr()); - log_assert(cell->parameters.empty()); - int abc9_box_seq = it->second.as_int(); - if (GetSize(box_list) <= abc9_box_seq) - box_list.resize(abc9_box_seq+1); - box_list[abc9_box_seq] = cell; - // Only flop boxes may have arrival times - // (all others are combinatorial) - log_assert(cell->parameters.empty()); - abc9_flop = inst_module->get_bool_attribute(ID::abc9_flop); - if (!abc9_flop) - continue; - } - - if (!timing.count(inst_module->name)) - timing.setup_module(inst_module); - - for (auto &i : timing.at(inst_module->name).arrival) { - if (!cell->hasPort(i.first.name)) - continue; - - auto port_wire = inst_module->wire(i.first.name); - log_assert(port_wire->port_output); - - auto d = i.second.first; - if (d == 0) - continue; - auto offset = i.first.offset; - -#ifndef NDEBUG - if (ys_debug(1)) { - static pool> seen; - if (seen.emplace(inst_module->name, i.first).second) log("%s.%s[%d] abc9_arrival = %d\n", - log_id(cell->type), log_id(i.first.name), offset, d); - } -#endif - arrival_times[cell->getPort(i.first.name)[offset]] = d; - } - - if (abc9_flop) - continue; - } - - bool cell_known = inst_module || cell->known(); - for (const auto &c : cell->connections()) { - if (c.second.is_fully_const()) continue; - auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr; - auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first); - auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first); - if (!is_input && !is_output) - log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type)); - - if (is_input) - for (auto b : c.second) { - Wire *w = b.wire; - if (!w) continue; - // Do not add as PO if bit is already a PI - if (input_bits.count(b)) - continue; - if (!w->port_output || !cell_known) { - SigBit I = sigmap(b); - if (I != b) - alias_map[b] = I; - output_bits.insert(b); - } - } - } - - //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); - } - - dict> box_ports; - for (auto cell : box_list) { - log_assert(cell); - - RTLIL::Module* box_module = design->module(cell->type); - log_assert(box_module); - log_assert(box_module->has_attribute(ID::abc9_box_id)); - - auto r = box_ports.insert(cell->type); - if (r.second) { - // Make carry in the last PI, and carry out the last PO - // since ABC requires it this way - IdString carry_in, carry_out; - for (const auto &port_name : box_module->ports) { - auto w = box_module->wire(port_name); - log_assert(w); - if (w->get_bool_attribute(ID::abc9_carry)) { - if (w->port_input) { - if (carry_in != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module)); - carry_in = port_name; - } - if (w->port_output) { - if (carry_out != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module)); - carry_out = port_name; - } - } - else - r.first->second.push_back(port_name); - } - - if (carry_in != IdString() && carry_out == IdString()) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module)); - if (carry_in == IdString() && carry_out != IdString()) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module)); - if (carry_in != IdString()) { - r.first->second.push_back(carry_in); - r.first->second.push_back(carry_out); - } - } - - for (auto port_name : r.first->second) { - auto w = box_module->wire(port_name); - log_assert(w); - auto rhs = cell->connections_.at(port_name, SigSpec()); - rhs.append(Const(State::Sx, GetSize(w)-GetSize(rhs))); - if (w->port_input) - for (auto b : rhs) { - SigBit I = sigmap(b); - if (b == RTLIL::Sx) - b = State::S0; - else if (I != b) { - if (I == RTLIL::Sx) - alias_map[b] = State::S0; - else - alias_map[b] = I; - } - co_bits.emplace_back(b); - unused_bits.erase(I); - } - if (w->port_output) - for (const auto &b : rhs) { - SigBit O = sigmap(b); - if (O != b) - alias_map[O] = b; - ci_bits.emplace_back(b); - undriven_bits.erase(O); - } - } - } - - for (auto bit : input_bits) - undriven_bits.erase(bit); - for (auto bit : output_bits) - unused_bits.erase(sigmap(bit)); - for (auto bit : unused_bits) - undriven_bits.erase(bit); - - // Make all undriven bits a primary input - for (auto bit : undriven_bits) { - input_bits.insert(bit); - undriven_bits.erase(bit); - } - - struct sort_by_port_id { - bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const { - return a.wire->port_id < b.wire->port_id || - (a.wire->port_id == b.wire->port_id && a.offset < b.offset); - } - }; - input_bits.sort(sort_by_port_id()); - output_bits.sort(sort_by_port_id()); - - aig_map[State::S0] = 0; - aig_map[State::S1] = 1; - - for (const auto &bit : input_bits) { - aig_m++, aig_i++; - log_assert(!aig_map.count(bit)); - aig_map[bit] = 2*aig_m; - } - - for (auto cell : ff_list) { - const SigBit &q = sigmap(cell->getPort(ID::Q)); - aig_m++, aig_i++; - log_assert(!aig_map.count(q)); - aig_map[q] = 2*aig_m; - } - - for (auto &bit : ci_bits) { - aig_m++, aig_i++; - // 1'bx may exist here due to a box output - // that has been padded to its full width - if (bit == State::Sx) - continue; - if (aig_map.count(bit)) - log_error("Visited AIG node more than once; this could be a combinatorial loop that has not been broken\n"); - aig_map[bit] = 2*aig_m; - } - - for (auto bit : co_bits) { - ordered_outputs[bit] = aig_o++; - aig_outputs.push_back(bit2aig(bit)); - } - - for (const auto &bit : output_bits) { - ordered_outputs[bit] = aig_o++; - int aig; - // Unlike bit2aig() which checks aig_map first for - // inout/scc bits, since aig_map will point to - // the PI, first attempt to find the NOT/AND driver - // before resorting to an aig_map lookup (which - // could be another PO) - if (input_bits.count(bit)) { - if (not_map.count(bit)) { - aig = bit2aig(not_map.at(bit)) ^ 1; - } else if (and_map.count(bit)) { - auto args = and_map.at(bit); - int a0 = bit2aig(args.first); - int a1 = bit2aig(args.second); - aig = mkgate(a0, a1); - } - else - aig = aig_map.at(bit); - } - else - aig = bit2aig(bit); - aig_outputs.push_back(aig); - } - - for (auto cell : ff_list) { - const SigBit &d = sigmap(cell->getPort(ID::D)); - aig_o++; - aig_outputs.push_back(aig_map.at(d)); - } - } - - void write_aiger(std::ostream &f, bool ascii_mode) - { - int aig_obc = aig_o; - int aig_obcj = aig_obc; - int aig_obcjf = aig_obcj; - - log_assert(aig_m == aig_i + aig_l + aig_a); - log_assert(aig_obcjf == GetSize(aig_outputs)); - - f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a); - 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_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_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); - } - } - - f << "c"; - - auto write_buffer = [](std::stringstream &buffer, int i32) { - int32_t i32_be = to_big_endian(i32); - buffer.write(reinterpret_cast(&i32_be), sizeof(i32_be)); - }; - std::stringstream h_buffer; - auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1); - write_h_buffer(1); - log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ff_list) + GetSize(ci_bits)); - write_h_buffer(GetSize(input_bits) + GetSize(ff_list) + GetSize(ci_bits)); - log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(ff_list) + GetSize(co_bits)); - write_h_buffer(GetSize(output_bits) + GetSize(ff_list) + GetSize(co_bits)); - log_debug("piNum = %d\n", GetSize(input_bits) + GetSize(ff_list)); - write_h_buffer(GetSize(input_bits) + GetSize(ff_list)); - log_debug("poNum = %d\n", GetSize(output_bits) + GetSize(ff_list)); - write_h_buffer(GetSize(output_bits) + GetSize(ff_list)); - log_debug("boxNum = %d\n", GetSize(box_list)); - write_h_buffer(GetSize(box_list)); - - auto write_buffer_float = [](std::stringstream &buffer, float f32) { - buffer.write(reinterpret_cast(&f32), sizeof(f32)); - }; - std::stringstream i_buffer; - auto write_i_buffer = std::bind(write_buffer_float, std::ref(i_buffer), std::placeholders::_1); - for (auto bit : input_bits) - write_i_buffer(arrival_times.at(bit, 0)); - //std::stringstream o_buffer; - //auto write_o_buffer = std::bind(write_buffer_float, std::ref(o_buffer), std::placeholders::_1); - //for (auto bit : output_bits) - // write_o_buffer(0); - - if (!box_list.empty() || !ff_list.empty()) { - dict> cell_cache; - - int box_count = 0; - for (auto cell : box_list) { - log_assert(cell); - log_assert(cell->parameters.empty()); - - auto r = cell_cache.insert(cell->type); - auto &v = r.first->second; - if (r.second) { - RTLIL::Module* box_module = design->module(cell->type); - log_assert(box_module); - - int box_inputs = 0, box_outputs = 0; - for (auto port_name : box_module->ports) { - RTLIL::Wire *w = box_module->wire(port_name); - log_assert(w); - if (w->port_input) - box_inputs += GetSize(w); - if (w->port_output) - box_outputs += GetSize(w); - } - - std::get<0>(v) = box_inputs; - std::get<1>(v) = box_outputs; - std::get<2>(v) = box_module->attributes.at(ID::abc9_box_id).as_int(); - } - - write_h_buffer(std::get<0>(v)); - write_h_buffer(std::get<1>(v)); - write_h_buffer(std::get<2>(v)); - write_h_buffer(box_count++); - } - - std::stringstream r_buffer; - auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1); - log_debug("flopNum = %d\n", GetSize(ff_list)); - write_r_buffer(ff_list.size()); - - std::stringstream s_buffer; - auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1); - write_s_buffer(ff_list.size()); - - dict clk_to_mergeability; - for (const auto cell : ff_list) { - const SigBit &d = sigmap(cell->getPort(ID::D)); - const SigBit &q = sigmap(cell->getPort(ID::Q)); - - SigSpec clk_and_pol{sigmap(cell->getPort(ID::C)), cell->type[6] == 'P' ? State::S1 : State::S0}; - auto r = clk_to_mergeability.insert(std::make_pair(clk_and_pol, clk_to_mergeability.size()+1)); - int mergeability = r.first->second; - log_assert(mergeability > 0); - write_r_buffer(mergeability); - - State init = init_map.at(q, State::Sx); - log_debug("Cell '%s' (type %s) has (* init *) value '%s'.\n", log_id(cell), log_id(cell->type), log_signal(init)); - if (init == State::S1) - write_s_buffer(1); - else if (init == State::S0) - write_s_buffer(0); - else { - log_assert(init == State::Sx); - write_s_buffer(2); - } - - // Use arrival time from output of flop box - write_i_buffer(arrival_times.at(d, 0)); - //write_o_buffer(0); - } - - f << "r"; - std::string buffer_str = r_buffer.str(); - int32_t buffer_size_be = to_big_endian(buffer_str.size()); - f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); - f.write(buffer_str.data(), buffer_str.size()); - - f << "s"; - buffer_str = s_buffer.str(); - buffer_size_be = to_big_endian(buffer_str.size()); - f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); - f.write(buffer_str.data(), buffer_str.size()); - - RTLIL::Design *holes_design; - auto it = saved_designs.find("$abc9_holes"); - if (it != saved_designs.end()) - holes_design = it->second; - else - holes_design = nullptr; - RTLIL::Module *holes_module = holes_design ? holes_design->module(module->name) : nullptr; - if (holes_module) { - std::stringstream a_buffer; - XAigerWriter writer(holes_module, false /* dff_mode */); - writer.write_aiger(a_buffer, false /*ascii_mode*/); - - f << "a"; - std::string buffer_str = a_buffer.str(); - int32_t buffer_size_be = to_big_endian(buffer_str.size()); - f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); - f.write(buffer_str.data(), buffer_str.size()); - } - } - - f << "h"; - std::string buffer_str = h_buffer.str(); - int32_t buffer_size_be = to_big_endian(buffer_str.size()); - f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); - f.write(buffer_str.data(), buffer_str.size()); - - f << "i"; - buffer_str = i_buffer.str(); - buffer_size_be = to_big_endian(buffer_str.size()); - f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); - f.write(buffer_str.data(), buffer_str.size()); - //f << "o"; - //buffer_str = o_buffer.str(); - //buffer_size_be = to_big_endian(buffer_str.size()); - //f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); - //f.write(buffer_str.data(), buffer_str.size()); - - f << stringf("Generated by %s\n", yosys_version_str); - - design->scratchpad_set_int("write_xaiger.num_ands", and_map.size()); - design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size()); - design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size()); - design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size()); - } - - void write_map(std::ostream &f) - { - dict input_lines; - dict output_lines; - - for (auto wire : module->wires()) - { - for (int i = 0; i < GetSize(wire); i++) - { - RTLIL::SigBit b(wire, i); - if (input_bits.count(b)) { - int a = aig_map.at(b); - log_assert((a & 1) == 0); - input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, wire->start_offset+i, log_id(wire)); - } - - if (output_bits.count(b)) { - int o = ordered_outputs.at(b); - output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), wire->start_offset+i, log_id(wire)); - } - } - } - - input_lines.sort(); - for (auto &it : input_lines) - f << it.second; - log_assert(input_lines.size() == input_bits.size()); - - int box_count = 0; - for (auto cell : box_list) - f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); - - output_lines.sort(); - for (auto &it : output_lines) - f << it.second; - log_assert(output_lines.size() == output_bits.size()); - } -}; - -struct XAigerBackend : public Backend { - XAigerBackend() : Backend("xaiger", "write design to XAIGER file") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_xaiger [options] [filename]\n"); - log("\n"); - log("Write the top module (according to the (* top *) attribute or if only one module\n"); - log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, (optionally\n"); - log("$_DFF_N_, $_DFF_P_), or non (* abc9_box *) cells will be converted into psuedo-\n"); - log("inputs and pseudo-outputs. Whitebox contents will be taken from the equivalent\n"); - log("module in the '$abc9_holes' design, if it exists.\n"); - log("\n"); - log(" -ascii\n"); - log(" write ASCII version of AIGER format\n"); - log("\n"); - log(" -map \n"); - log(" write an extra file with port and box symbols\n"); - log("\n"); - log(" -dff\n"); - log(" write $_DFF_[NP]_ cells\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override - { - bool ascii_mode = false, dff_mode = false; - std::string map_filename; - - log_header(design, "Executing XAIGER backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-ascii") { - ascii_mode = true; - continue; - } - if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) { - map_filename = args[++argidx]; - continue; - } - if (args[argidx] == "-dff") { - dff_mode = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx, !ascii_mode); - - Module *top_module = design->top_module(); - - if (top_module == nullptr) - log_error("Can't find top module in current design!\n"); - - if (!design->selected_whole_module(top_module)) - log_cmd_error("Can't handle partially selected module %s!\n", log_id(top_module)); - - if (!top_module->processes.empty()) - log_error("Found unmapped processes in module %s: unmapped processes are not supported in XAIGER backend!\n", log_id(top_module)); - if (!top_module->memories.empty()) - log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", log_id(top_module)); - - XAigerWriter writer(top_module, dff_mode); - writer.write_aiger(*f, ascii_mode); - - if (!map_filename.empty()) { - 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); - } - } -} XAigerBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/blif/Makefile.inc b/yosys/backends/blif/Makefile.inc deleted file mode 100644 index 517dabaf29b..00000000000 --- 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 23d1d58fc20..00000000000 --- a/yosys/backends/blif/blif.cc +++ /dev/null @@ -1,681 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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(ID::init)) { - SigSpec initsig = sigmap(wire); - Const initval = wire->attributes.at(ID::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; - } - } - } - - pool cstr_bits_seen; - - const std::string str(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] = '?'; - return str; - } - - const std::string str(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); - - return str; - } - - const std::string str_init(RTLIL::SigBit sig) - { - sigmap.apply(sig); - - if (init_bits.count(sig) == 0) - return " 2"; - - string str = stringf(" %d", init_bits.at(sig)); - - return str; - } - - const char *subckt_or_gate(std::string cell_type) - { - if (!config->gates_mode) - return "subckt"; - if (design->module(RTLIL::escape_id(cell_type)) == nullptr) - return "gate"; - if (design->module(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, log_id(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", str(module->name).c_str()); - - std::map inputs, outputs; - - for (auto wire : module->wires()) { - 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", str(RTLIL::SigSpec(wire, i)).c_str()); - } - 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", str(RTLIL::SigSpec(wire, i)).c_str()); - } - 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 : module->cells()) - { - if (config->unbuf_types.count(cell->type)) { - auto portnames = config->unbuf_types.at(cell->type); - f << stringf(".names %s %s\n1 1\n", - str(cell->getPort(portnames.first)).c_str(), str(cell->getPort(portnames.second)).c_str()); - continue; - } - - if (!config->icells_mode && cell->type == ID($_NOT_)) { - f << stringf(".names %s %s\n0 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_AND_)) { - f << stringf(".names %s %s %s\n11 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_OR_)) { - f << stringf(".names %s %s %s\n1- 1\n-1 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_XOR_)) { - f << stringf(".names %s %s %s\n10 1\n01 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_NAND_)) { - f << stringf(".names %s %s %s\n0- 1\n-0 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_NOR_)) { - f << stringf(".names %s %s %s\n00 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_XNOR_)) { - f << stringf(".names %s %s %s\n11 1\n00 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_ANDNOT_)) { - f << stringf(".names %s %s %s\n10 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_ORNOT_)) { - f << stringf(".names %s %s %s\n1- 1\n-0 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_AOI3_)) { - f << stringf(".names %s %s %s %s\n-00 1\n0-0 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::C)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_OAI3_)) { - f << stringf(".names %s %s %s %s\n00- 1\n--0 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), str(cell->getPort(ID::C)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_AOI4_)) { - f << stringf(".names %s %s %s %s %s\n-0-0 1\n-00- 1\n0--0 1\n0-0- 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), - str(cell->getPort(ID::C)).c_str(), str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_OAI4_)) { - f << stringf(".names %s %s %s %s %s\n00-- 1\n--00 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), - str(cell->getPort(ID::C)).c_str(), str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_MUX_)) { - f << stringf(".names %s %s %s %s\n1-0 1\n-11 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), - str(cell->getPort(ID::S)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_NMUX_)) { - f << stringf(".names %s %s %s %s\n0-0 1\n-01 1\n", - str(cell->getPort(ID::A)).c_str(), str(cell->getPort(ID::B)).c_str(), - str(cell->getPort(ID::S)).c_str(), str(cell->getPort(ID::Y)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_FF_)) { - f << stringf(".latch %s %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), - str_init(cell->getPort(ID::Q)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_DFF_N_)) { - f << stringf(".latch %s %s fe %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), - str(cell->getPort(ID::C)).c_str(), str_init(cell->getPort(ID::Q)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_DFF_P_)) { - f << stringf(".latch %s %s re %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), - str(cell->getPort(ID::C)).c_str(), str_init(cell->getPort(ID::Q)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_DLATCH_N_)) { - f << stringf(".latch %s %s al %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), - str(cell->getPort(ID::E)).c_str(), str_init(cell->getPort(ID::Q)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($_DLATCH_P_)) { - f << stringf(".latch %s %s ah %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), - str(cell->getPort(ID::E)).c_str(), str_init(cell->getPort(ID::Q)).c_str()); - goto internal_cell; - } - - if (!config->icells_mode && cell->type == ID($lut)) { - f << stringf(".names"); - auto &inputs = cell->getPort(ID::A); - auto width = cell->parameters.at(ID::WIDTH).as_int(); - log_assert(inputs.size() == width); - for (int i = width-1; i >= 0; i--) - f << stringf(" %s", str(inputs.extract(i, 1)).c_str()); - auto &output = cell->getPort(ID::Y); - log_assert(output.size() == 1); - f << stringf(" %s", str(output).c_str()); - f << stringf("\n"); - RTLIL::SigSpec mask = cell->parameters.at(ID::LUT); - for (int i = 0; i < (1 << width); i++) - if (mask[i] == State::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 == ID($sop)) { - f << stringf(".names"); - auto &inputs = cell->getPort(ID::A); - auto width = cell->parameters.at(ID::WIDTH).as_int(); - auto depth = cell->parameters.at(ID::DEPTH).as_int(); - vector table = cell->parameters.at(ID::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", str(inputs.extract(i, 1)).c_str()); - auto &output = cell->getPort(ID::Y); - log_assert(output.size() == 1); - f << stringf(" %s", str(output).c_str()); - 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()), str(cell->type).c_str()); - for (auto &conn : cell->connections()) - { - if (conn.second.size() == 1) { - f << stringf(" %s=%s", str(conn.first).c_str(), str(conn.second[0]).c_str()); - 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", str(conn.first).c_str(), i, str(conn.second[i]).c_str()); - } else { - for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) { - SigBit sig(w, i); - f << stringf(" %s[%d]=%s", str(conn.first).c_str(), sig.wire->upto ? - sig.wire->start_offset+sig.wire->width-sig.offset-1 : - sig.wire->start_offset+sig.offset, str(conn.second[i]).c_str()); - } - } - } - f << stringf("\n"); - - if (config->cname_mode) - f << stringf(".cname %s\n", str(cell->name).c_str()); - 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", str(cell->name).c_str()); - 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", str(rhs_bit).c_str(), str(lhs_bit).c_str()); - 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(), str(rhs_bit).c_str(), config->buf_out.c_str(), str(lhs_bit).c_str()); - else - f << stringf(".names %s %s\n1 1\n", str(rhs_bit).c_str(), str(lhs_bit).c_str()); - } - - 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() 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\n"); - log("output 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) 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 module : design->modules()) - if (module->get_bool_attribute(ID::top)) - top_module_name = module->name.str(); - - *f << stringf("# Generated by %s\n", yosys_version_str); - - std::vector mod_list; - - design->sort(); - for (auto module : design->modules()) - { - 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", log_id(module->name)); - if (module->memories.size() != 0) - log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", log_id(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/.gitignore b/yosys/backends/btor/.gitignore deleted file mode 100644 index d23d492d733..00000000000 --- a/yosys/backends/btor/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/test_cells.tmp/ diff --git a/yosys/backends/btor/Makefile.inc b/yosys/backends/btor/Makefile.inc deleted file mode 100644 index af7ab14dcfe..00000000000 --- 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 index 4c43e91e796..9cfd967e581 100644 --- a/yosys/backends/btor/btor.cc +++ b/yosys/backends/btor/btor.cc @@ -728,7 +728,10 @@ struct BtorWorker else btorf("%d state %d %s\n", nid, sid, log_id(symbol)); - ywmap_state(sig_q); + if (cell->get_bool_attribute(ID(clk2fflogic))) + ywmap_state(cell->getPort(ID::D)); // For a clk2fflogic FF the named signal is the D input not the Q output + else + ywmap_state(sig_q); if (nid_init_val >= 0) { int nid_init = next_nid++; diff --git a/yosys/backends/btor/test_cells.sh b/yosys/backends/btor/test_cells.sh deleted file mode 100755 index 0a011932d22..00000000000 --- 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 /$divfloor /$modfloor /$shiftx' - -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 - " - btormc -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/cxxrtl/Makefile.inc b/yosys/backends/cxxrtl/Makefile.inc deleted file mode 100644 index aaa304502e0..00000000000 --- a/yosys/backends/cxxrtl/Makefile.inc +++ /dev/null @@ -1,2 +0,0 @@ - -OBJS += backends/cxxrtl/cxxrtl_backend.o diff --git a/yosys/backends/cxxrtl/cxxrtl.h b/yosys/backends/cxxrtl/cxxrtl.h deleted file mode 100644 index 073921cc49e..00000000000 --- a/yosys/backends/cxxrtl/cxxrtl.h +++ /dev/null @@ -1,1616 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2019-2020 whitequark - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted. - * - * 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 is included by the designs generated with `write_cxxrtl`. It is not used in Yosys itself. -// -// The CXXRTL support library implements compile time specialized arbitrary width arithmetics, as well as provides -// composite lvalues made out of bit slices and concatenations of lvalues. This allows the `write_cxxrtl` pass -// to perform a straightforward translation of RTLIL structures to readable C++, relying on the C++ compiler -// to unwrap the abstraction and generate efficient code. - -#ifndef CXXRTL_H -#define CXXRTL_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifndef __has_attribute -# define __has_attribute(x) 0 -#endif - -// CXXRTL essentially uses the C++ compiler as a hygienic macro engine that feeds an instruction selector. -// It generates a lot of specialized template functions with relatively large bodies that, when inlined -// into the caller and (for those with loops) unrolled, often expose many new optimization opportunities. -// Because of this, most of the CXXRTL runtime must be always inlined for best performance. -#if __has_attribute(always_inline) -#define CXXRTL_ALWAYS_INLINE inline __attribute__((__always_inline__)) -#else -#define CXXRTL_ALWAYS_INLINE inline -#endif -// Conversely, some functions in the generated code are extremely large yet very cold, with both of these -// properties being extreme enough to confuse C++ compilers into spending pathological amounts of time -// on a futile (the code becomes worse) attempt to optimize the least important parts of code. -#if __has_attribute(optnone) -#define CXXRTL_EXTREMELY_COLD __attribute__((__optnone__)) -#elif __has_attribute(optimize) -#define CXXRTL_EXTREMELY_COLD __attribute__((__optimize__(0))) -#else -#define CXXRTL_EXTREMELY_COLD -#endif - -// CXXRTL uses assert() to check for C++ contract violations (which may result in e.g. undefined behavior -// of the simulation code itself), and CXXRTL_ASSERT to check for RTL contract violations (which may at -// most result in undefined simulation results). -// -// Though by default, CXXRTL_ASSERT() expands to assert(), it may be overridden e.g. when integrating -// the simulation into another process that should survive violating RTL contracts. -#ifndef CXXRTL_ASSERT -#ifndef CXXRTL_NDEBUG -#define CXXRTL_ASSERT(x) assert(x) -#else -#define CXXRTL_ASSERT(x) -#endif -#endif - -namespace cxxrtl { - -// All arbitrary-width values in CXXRTL are backed by arrays of unsigned integers called chunks. The chunk size -// is the same regardless of the value width to simplify manipulating values via FFI interfaces, e.g. driving -// and introspecting the simulation in Python. -// -// It is practical to use chunk sizes between 32 bits and platform register size because when arithmetics on -// narrower integer types is legalized by the C++ compiler, it inserts code to clear the high bits of the register. -// However, (a) most of our operations do not change those bits in the first place because of invariants that are -// invisible to the compiler, (b) we often operate on non-power-of-2 values and have to clear the high bits anyway. -// Therefore, using relatively wide chunks and clearing the high bits explicitly and only when we know they may be -// clobbered results in simpler generated code. -typedef uint32_t chunk_t; -typedef uint64_t wide_chunk_t; - -template -struct chunk_traits { - static_assert(std::is_integral::value && std::is_unsigned::value, - "chunk type must be an unsigned integral type"); - using type = T; - static constexpr size_t bits = std::numeric_limits::digits; - static constexpr T mask = std::numeric_limits::max(); -}; - -template -struct expr_base; - -template -struct value : public expr_base> { - static constexpr size_t bits = Bits; - - using chunk = chunk_traits; - static constexpr chunk::type msb_mask = (Bits % chunk::bits == 0) ? chunk::mask - : chunk::mask >> (chunk::bits - (Bits % chunk::bits)); - - static constexpr size_t chunks = (Bits + chunk::bits - 1) / chunk::bits; - chunk::type data[chunks] = {}; - - value() = default; - template - explicit constexpr value(Init ...init) : data{init...} {} - - value(const value &) = default; - value &operator=(const value &) = default; - - value(value &&) = default; - value &operator=(value &&) = default; - - // A (no-op) helper that forces the cast to value<>. - CXXRTL_ALWAYS_INLINE - const value &val() const { - return *this; - } - - std::string str() const { - std::stringstream ss; - ss << *this; - return ss.str(); - } - - // Conversion operations. - // - // These functions ensure that a conversion is never out of range, and should be always used, if at all - // possible, instead of direct manipulation of the `data` member. For very large types, .slice() and - // .concat() can be used to split them into more manageable parts. - template - CXXRTL_ALWAYS_INLINE - IntegerT get() const { - static_assert(std::numeric_limits::is_integer && !std::numeric_limits::is_signed, - "get() requires T to be an unsigned integral type"); - static_assert(std::numeric_limits::digits >= Bits, - "get() requires T to be at least as wide as the value is"); - IntegerT result = 0; - for (size_t n = 0; n < chunks; n++) - result |= IntegerT(data[n]) << (n * chunk::bits); - return result; - } - - template - CXXRTL_ALWAYS_INLINE - void set(IntegerT other) { - static_assert(std::numeric_limits::is_integer && !std::numeric_limits::is_signed, - "set() requires T to be an unsigned integral type"); - static_assert(std::numeric_limits::digits >= Bits, - "set() requires the value to be at least as wide as T is"); - for (size_t n = 0; n < chunks; n++) - data[n] = (other >> (n * chunk::bits)) & chunk::mask; - } - - // Operations with compile-time parameters. - // - // These operations are used to implement slicing, concatenation, and blitting. - // The trunc, zext and sext operations add or remove most significant bits (i.e. on the left); - // the rtrunc and rzext operations add or remove least significant bits (i.e. on the right). - template - CXXRTL_ALWAYS_INLINE - value trunc() const { - static_assert(NewBits <= Bits, "trunc() may not increase width"); - value result; - for (size_t n = 0; n < result.chunks; n++) - result.data[n] = data[n]; - result.data[result.chunks - 1] &= result.msb_mask; - return result; - } - - template - CXXRTL_ALWAYS_INLINE - value zext() const { - static_assert(NewBits >= Bits, "zext() may not decrease width"); - value result; - for (size_t n = 0; n < chunks; n++) - result.data[n] = data[n]; - return result; - } - - template - CXXRTL_ALWAYS_INLINE - value sext() const { - static_assert(NewBits >= Bits, "sext() may not decrease width"); - value result; - for (size_t n = 0; n < chunks; n++) - result.data[n] = data[n]; - if (is_neg()) { - result.data[chunks - 1] |= ~msb_mask; - for (size_t n = chunks; n < result.chunks; n++) - result.data[n] = chunk::mask; - result.data[result.chunks - 1] &= result.msb_mask; - } - return result; - } - - template - CXXRTL_ALWAYS_INLINE - value rtrunc() const { - static_assert(NewBits <= Bits, "rtrunc() may not increase width"); - value result; - constexpr size_t shift_chunks = (Bits - NewBits) / chunk::bits; - constexpr size_t shift_bits = (Bits - NewBits) % chunk::bits; - chunk::type carry = 0; - if (shift_chunks + result.chunks < chunks) { - carry = (shift_bits == 0) ? 0 - : data[shift_chunks + result.chunks] << (chunk::bits - shift_bits); - } - for (size_t n = result.chunks; n > 0; n--) { - result.data[n - 1] = carry | (data[shift_chunks + n - 1] >> shift_bits); - carry = (shift_bits == 0) ? 0 - : data[shift_chunks + n - 1] << (chunk::bits - shift_bits); - } - return result; - } - - template - CXXRTL_ALWAYS_INLINE - value rzext() const { - static_assert(NewBits >= Bits, "rzext() may not decrease width"); - value result; - constexpr size_t shift_chunks = (NewBits - Bits) / chunk::bits; - constexpr size_t shift_bits = (NewBits - Bits) % chunk::bits; - chunk::type carry = 0; - for (size_t n = 0; n < chunks; n++) { - result.data[shift_chunks + n] = (data[n] << shift_bits) | carry; - carry = (shift_bits == 0) ? 0 - : data[n] >> (chunk::bits - shift_bits); - } - if (shift_chunks + chunks < result.chunks) - result.data[shift_chunks + chunks] = carry; - return result; - } - - // Bit blit operation, i.e. a partial read-modify-write. - template - CXXRTL_ALWAYS_INLINE - value blit(const value &source) const { - static_assert(Stop >= Start, "blit() may not reverse bit order"); - constexpr chunk::type start_mask = ~(chunk::mask << (Start % chunk::bits)); - constexpr chunk::type stop_mask = (Stop % chunk::bits + 1 == chunk::bits) ? 0 - : (chunk::mask << (Stop % chunk::bits + 1)); - value masked = *this; - if (Start / chunk::bits == Stop / chunk::bits) { - masked.data[Start / chunk::bits] &= stop_mask | start_mask; - } else { - masked.data[Start / chunk::bits] &= start_mask; - for (size_t n = Start / chunk::bits + 1; n < Stop / chunk::bits; n++) - masked.data[n] = 0; - masked.data[Stop / chunk::bits] &= stop_mask; - } - value shifted = source - .template rzext() - .template zext(); - return masked.bit_or(shifted); - } - - // Helpers for selecting extending or truncating operation depending on whether the result is wider or narrower - // than the operand. In C++17 these can be replaced with `if constexpr`. - template - struct zext_cast { - CXXRTL_ALWAYS_INLINE - value operator()(const value &val) { - return val.template zext(); - } - }; - - template - struct zext_cast::type> { - CXXRTL_ALWAYS_INLINE - value operator()(const value &val) { - return val.template trunc(); - } - }; - - template - struct sext_cast { - CXXRTL_ALWAYS_INLINE - value operator()(const value &val) { - return val.template sext(); - } - }; - - template - struct sext_cast::type> { - CXXRTL_ALWAYS_INLINE - value operator()(const value &val) { - return val.template trunc(); - } - }; - - template - CXXRTL_ALWAYS_INLINE - value zcast() const { - return zext_cast()(*this); - } - - template - CXXRTL_ALWAYS_INLINE - value scast() const { - return sext_cast()(*this); - } - - // Bit replication is far more efficient than the equivalent concatenation. - template - CXXRTL_ALWAYS_INLINE - value repeat() const { - static_assert(Bits == 1, "repeat() is implemented only for 1-bit values"); - return *this ? value().bit_not() : value(); - } - - // Operations with run-time parameters (offsets, amounts, etc). - // - // These operations are used for computations. - bool bit(size_t offset) const { - return data[offset / chunk::bits] & (1 << (offset % chunk::bits)); - } - - void set_bit(size_t offset, bool value = true) { - size_t offset_chunks = offset / chunk::bits; - size_t offset_bits = offset % chunk::bits; - data[offset_chunks] &= ~(1 << offset_bits); - data[offset_chunks] |= value ? 1 << offset_bits : 0; - } - - explicit operator bool() const { - return !is_zero(); - } - - bool is_zero() const { - for (size_t n = 0; n < chunks; n++) - if (data[n] != 0) - return false; - return true; - } - - bool is_neg() const { - return data[chunks - 1] & (1 << ((Bits - 1) % chunk::bits)); - } - - bool operator ==(const value &other) const { - for (size_t n = 0; n < chunks; n++) - if (data[n] != other.data[n]) - return false; - return true; - } - - bool operator !=(const value &other) const { - return !(*this == other); - } - - value bit_not() const { - value result; - for (size_t n = 0; n < chunks; n++) - result.data[n] = ~data[n]; - result.data[chunks - 1] &= msb_mask; - return result; - } - - value bit_and(const value &other) const { - value result; - for (size_t n = 0; n < chunks; n++) - result.data[n] = data[n] & other.data[n]; - return result; - } - - value bit_or(const value &other) const { - value result; - for (size_t n = 0; n < chunks; n++) - result.data[n] = data[n] | other.data[n]; - return result; - } - - value bit_xor(const value &other) const { - value result; - for (size_t n = 0; n < chunks; n++) - result.data[n] = data[n] ^ other.data[n]; - return result; - } - - value update(const value &val, const value &mask) const { - return bit_and(mask.bit_not()).bit_or(val.bit_and(mask)); - } - - template - value shl(const value &amount) const { - // Ensure our early return is correct by prohibiting values larger than 4 Gbit. - static_assert(Bits <= chunk::mask, "shl() of unreasonably large values is not supported"); - // Detect shifts definitely large than Bits early. - for (size_t n = 1; n < amount.chunks; n++) - if (amount.data[n] != 0) - return {}; - // Past this point we can use the least significant chunk as the shift size. - size_t shift_chunks = amount.data[0] / chunk::bits; - size_t shift_bits = amount.data[0] % chunk::bits; - if (shift_chunks >= chunks) - return {}; - value result; - chunk::type carry = 0; - for (size_t n = 0; n < chunks - shift_chunks; n++) { - result.data[shift_chunks + n] = (data[n] << shift_bits) | carry; - carry = (shift_bits == 0) ? 0 - : data[n] >> (chunk::bits - shift_bits); - } - return result; - } - - template - value shr(const value &amount) const { - // Ensure our early return is correct by prohibiting values larger than 4 Gbit. - static_assert(Bits <= chunk::mask, "shr() of unreasonably large values is not supported"); - // Detect shifts definitely large than Bits early. - for (size_t n = 1; n < amount.chunks; n++) - if (amount.data[n] != 0) - return {}; - // Past this point we can use the least significant chunk as the shift size. - size_t shift_chunks = amount.data[0] / chunk::bits; - size_t shift_bits = amount.data[0] % chunk::bits; - if (shift_chunks >= chunks) - return {}; - value result; - chunk::type carry = 0; - for (size_t n = 0; n < chunks - shift_chunks; n++) { - result.data[chunks - shift_chunks - 1 - n] = carry | (data[chunks - 1 - n] >> shift_bits); - carry = (shift_bits == 0) ? 0 - : data[chunks - 1 - n] << (chunk::bits - shift_bits); - } - if (Signed && is_neg()) { - size_t top_chunk_idx = (Bits - shift_bits) / chunk::bits; - size_t top_chunk_bits = (Bits - shift_bits) % chunk::bits; - for (size_t n = top_chunk_idx + 1; n < chunks; n++) - result.data[n] = chunk::mask; - if (shift_bits != 0) - result.data[top_chunk_idx] |= chunk::mask << top_chunk_bits; - } - return result; - } - - template - value sshr(const value &amount) const { - return shr(amount); - } - - template - value bmux(const value &sel) const { - static_assert(ResultBits << SelBits == Bits, "invalid sizes used in bmux()"); - size_t amount = sel.data[0] * ResultBits; - size_t shift_chunks = amount / chunk::bits; - size_t shift_bits = amount % chunk::bits; - value result; - chunk::type carry = 0; - if (ResultBits % chunk::bits + shift_bits > chunk::bits) - carry = data[result.chunks + shift_chunks] << (chunk::bits - shift_bits); - for (size_t n = 0; n < result.chunks; n++) { - result.data[result.chunks - 1 - n] = carry | (data[result.chunks + shift_chunks - 1 - n] >> shift_bits); - carry = (shift_bits == 0) ? 0 - : data[result.chunks + shift_chunks - 1 - n] << (chunk::bits - shift_bits); - } - return result; - } - - template - value demux(const value &sel) const { - static_assert(Bits << SelBits == ResultBits, "invalid sizes used in demux()"); - size_t amount = sel.data[0] * Bits; - size_t shift_chunks = amount / chunk::bits; - size_t shift_bits = amount % chunk::bits; - value result; - chunk::type carry = 0; - for (size_t n = 0; n < chunks; n++) { - result.data[shift_chunks + n] = (data[n] << shift_bits) | carry; - carry = (shift_bits == 0) ? 0 - : data[n] >> (chunk::bits - shift_bits); - } - if (Bits % chunk::bits + shift_bits > chunk::bits) - result.data[shift_chunks + chunks] = carry; - return result; - } - - size_t ctpop() const { - size_t count = 0; - for (size_t n = 0; n < chunks; n++) { - // This loop implements the population count idiom as recognized by LLVM and GCC. - for (chunk::type x = data[n]; x != 0; count++) - x = x & (x - 1); - } - return count; - } - - size_t ctlz() const { - size_t count = 0; - for (size_t n = 0; n < chunks; n++) { - chunk::type x = data[chunks - 1 - n]; - if (x == 0) { - count += (n == 0 ? Bits % chunk::bits : chunk::bits); - } else { - // This loop implements the find first set idiom as recognized by LLVM. - for (; x != 0; count++) - x >>= 1; - } - } - return count; - } - - template - std::pair, bool /*CarryOut*/> alu(const value &other) const { - value result; - bool carry = CarryIn; - for (size_t n = 0; n < result.chunks; n++) { - result.data[n] = data[n] + (Invert ? ~other.data[n] : other.data[n]) + carry; - if (result.chunks - 1 == n) - result.data[result.chunks - 1] &= result.msb_mask; - carry = (result.data[n] < data[n]) || - (result.data[n] == data[n] && carry); - } - return {result, carry}; - } - - value add(const value &other) const { - return alu(other).first; - } - - value sub(const value &other) const { - return alu(other).first; - } - - value neg() const { - return value { 0u }.sub(*this); - } - - bool ucmp(const value &other) const { - bool carry; - std::tie(std::ignore, carry) = alu(other); - return !carry; // a.ucmp(b) ≡ a u< b - } - - bool scmp(const value &other) const { - value result; - bool carry; - std::tie(result, carry) = alu(other); - bool overflow = (is_neg() == !other.is_neg()) && (is_neg() != result.is_neg()); - return result.is_neg() ^ overflow; // a.scmp(b) ≡ a s< b - } - - template - value mul(const value &other) const { - value result; - wide_chunk_t wide_result[result.chunks + 1] = {}; - for (size_t n = 0; n < chunks; n++) { - for (size_t m = 0; m < chunks && n + m < result.chunks; m++) { - wide_result[n + m] += wide_chunk_t(data[n]) * wide_chunk_t(other.data[m]); - wide_result[n + m + 1] += wide_result[n + m] >> chunk::bits; - wide_result[n + m] &= chunk::mask; - } - } - for (size_t n = 0; n < result.chunks; n++) { - result.data[n] = wide_result[n]; - } - result.data[result.chunks - 1] &= result.msb_mask; - return result; - } -}; - -// Expression template for a slice, usable as lvalue or rvalue, and composable with other expression templates here. -template -struct slice_expr : public expr_base> { - static_assert(Stop >= Start, "slice_expr() may not reverse bit order"); - static_assert(Start < T::bits && Stop < T::bits, "slice_expr() must be within bounds"); - static constexpr size_t bits = Stop - Start + 1; - - T &expr; - - slice_expr(T &expr) : expr(expr) {} - slice_expr(const slice_expr &) = delete; - - CXXRTL_ALWAYS_INLINE - operator value() const { - return static_cast &>(expr) - .template rtrunc() - .template trunc(); - } - - CXXRTL_ALWAYS_INLINE - slice_expr &operator=(const value &rhs) { - // Generic partial assignment implemented using a read-modify-write operation on the sliced expression. - expr = static_cast &>(expr) - .template blit(rhs); - return *this; - } - - // A helper that forces the cast to value<>, which allows deduction to work. - CXXRTL_ALWAYS_INLINE - value val() const { - return static_cast &>(*this); - } -}; - -// Expression template for a concatenation, usable as lvalue or rvalue, and composable with other expression templates here. -template -struct concat_expr : public expr_base> { - static constexpr size_t bits = T::bits + U::bits; - - T &ms_expr; - U &ls_expr; - - concat_expr(T &ms_expr, U &ls_expr) : ms_expr(ms_expr), ls_expr(ls_expr) {} - concat_expr(const concat_expr &) = delete; - - CXXRTL_ALWAYS_INLINE - operator value() const { - value ms_shifted = static_cast &>(ms_expr) - .template rzext(); - value ls_extended = static_cast &>(ls_expr) - .template zext(); - return ms_shifted.bit_or(ls_extended); - } - - CXXRTL_ALWAYS_INLINE - concat_expr &operator=(const value &rhs) { - ms_expr = rhs.template rtrunc(); - ls_expr = rhs.template trunc(); - return *this; - } - - // A helper that forces the cast to value<>, which allows deduction to work. - CXXRTL_ALWAYS_INLINE - value val() const { - return static_cast &>(*this); - } -}; - -// Base class for expression templates, providing helper methods for operations that are valid on both rvalues and lvalues. -// -// Note that expression objects (slices and concatenations) constructed in this way should NEVER be captured because -// they refer to temporaries that will, in general, only live until the end of the statement. For example, both of -// these snippets perform use-after-free: -// -// const auto &a = val.slice<7,0>().slice<1>(); -// value<1> b = a; -// -// auto &&c = val.slice<7,0>().slice<1>(); -// c = value<1>{1u}; -// -// An easy way to write code using slices and concatenations safely is to follow two simple rules: -// * Never explicitly name any type except `value` or `const value &`. -// * Never use a `const auto &` or `auto &&` in any such expression. -// Then, any code that compiles will be well-defined. -template -struct expr_base { - template - CXXRTL_ALWAYS_INLINE - slice_expr slice() const { - return {*static_cast(this)}; - } - - template - CXXRTL_ALWAYS_INLINE - slice_expr slice() { - return {*static_cast(this)}; - } - - template - CXXRTL_ALWAYS_INLINE - concat_expr::type> concat(const U &other) const { - return {*static_cast(this), other}; - } - - template - CXXRTL_ALWAYS_INLINE - concat_expr::type> concat(U &&other) { - return {*static_cast(this), other}; - } -}; - -template -std::ostream &operator<<(std::ostream &os, const value &val) { - auto old_flags = os.flags(std::ios::right); - auto old_width = os.width(0); - auto old_fill = os.fill('0'); - os << val.bits << '\'' << std::hex; - for (size_t n = val.chunks - 1; n != (size_t)-1; n--) { - if (n == val.chunks - 1 && Bits % value::chunk::bits != 0) - os.width((Bits % value::chunk::bits + 3) / 4); - else - os.width((value::chunk::bits + 3) / 4); - os << val.data[n]; - } - os.fill(old_fill); - os.width(old_width); - os.flags(old_flags); - return os; -} - -template -struct wire { - static constexpr size_t bits = Bits; - - value curr; - value next; - - wire() = default; - explicit constexpr wire(const value &init) : curr(init), next(init) {} - template - explicit constexpr wire(Init ...init) : curr{init...}, next{init...} {} - - // Copying and copy-assigning values is natural. If, however, a value is replaced with a wire, - // e.g. because a module is built with a different optimization level, then existing code could - // unintentionally copy a wire instead, which would create a subtle but serious bug. To make sure - // this doesn't happen, prohibit copying and copy-assigning wires. - wire(const wire &) = delete; - wire &operator=(const wire &) = delete; - - wire(wire &&) = default; - wire &operator=(wire &&) = default; - - template - CXXRTL_ALWAYS_INLINE - IntegerT get() const { - return curr.template get(); - } - - template - CXXRTL_ALWAYS_INLINE - void set(IntegerT other) { - next.template set(other); - } - - bool commit() { - if (curr != next) { - curr = next; - return true; - } - return false; - } -}; - -template -std::ostream &operator<<(std::ostream &os, const wire &val) { - os << val.curr; - return os; -} - -template -struct memory { - const size_t depth; - std::unique_ptr[]> data; - - explicit memory(size_t depth) : depth(depth), data(new value[depth]) {} - - memory(const memory &) = delete; - memory &operator=(const memory &) = delete; - - memory(memory &&) = default; - memory &operator=(memory &&other) { - assert(depth == other.depth); - data = std::move(other.data); - write_queue = std::move(other.write_queue); - return *this; - } - - // An operator for direct memory reads. May be used at any time during the simulation. - const value &operator [](size_t index) const { - assert(index < depth); - return data[index]; - } - - // An operator for direct memory writes. May only be used before the simulation is started. If used - // after the simulation is started, the design may malfunction. - value &operator [](size_t index) { - assert(index < depth); - return data[index]; - } - - // A simple way to make a writable memory would be to use an array of wires instead of an array of values. - // However, there are two significant downsides to this approach: first, it has large overhead (2× space - // overhead, and O(depth) time overhead during commit); second, it does not simplify handling write port - // priorities. Although in principle write ports could be ordered or conditionally enabled in generated - // code based on their priorities and selected addresses, the feedback arc set problem is computationally - // expensive, and the heuristic based algorithms are not easily modified to guarantee (rather than prefer) - // a particular write port evaluation order. - // - // The approach used here instead is to queue writes into a buffer during the eval phase, then perform - // the writes during the commit phase in the priority order. This approach has low overhead, with both space - // and time proportional to the amount of write ports. Because virtually every memory in a practical design - // has at most two write ports, linear search is used on every write, being the fastest and simplest approach. - struct write { - size_t index; - value val; - value mask; - int priority; - }; - std::vector write_queue; - - void update(size_t index, const value &val, const value &mask, int priority = 0) { - assert(index < depth); - // Queue up the write while keeping the queue sorted by priority. - write_queue.insert( - std::upper_bound(write_queue.begin(), write_queue.end(), priority, - [](const int a, const write& b) { return a < b.priority; }), - write { index, val, mask, priority }); - } - - bool commit() { - bool changed = false; - for (const write &entry : write_queue) { - value elem = data[entry.index]; - elem = elem.update(entry.val, entry.mask); - changed |= (data[entry.index] != elem); - data[entry.index] = elem; - } - write_queue.clear(); - return changed; - } -}; - -struct metadata { - const enum { - MISSING = 0, - UINT = 1, - SINT = 2, - STRING = 3, - DOUBLE = 4, - } value_type; - - // In debug mode, using the wrong .as_*() function will assert. - // In release mode, using the wrong .as_*() function will safely return a default value. - const unsigned uint_value = 0; - const signed sint_value = 0; - const std::string string_value = ""; - const double double_value = 0.0; - - metadata() : value_type(MISSING) {} - metadata(unsigned value) : value_type(UINT), uint_value(value) {} - metadata(signed value) : value_type(SINT), sint_value(value) {} - metadata(const std::string &value) : value_type(STRING), string_value(value) {} - metadata(const char *value) : value_type(STRING), string_value(value) {} - metadata(double value) : value_type(DOUBLE), double_value(value) {} - - metadata(const metadata &) = default; - metadata &operator=(const metadata &) = delete; - - unsigned as_uint() const { - assert(value_type == UINT); - return uint_value; - } - - signed as_sint() const { - assert(value_type == SINT); - return sint_value; - } - - const std::string &as_string() const { - assert(value_type == STRING); - return string_value; - } - - double as_double() const { - assert(value_type == DOUBLE); - return double_value; - } -}; - -typedef std::map metadata_map; - -// Tag class to disambiguate values/wires and their aliases. -struct debug_alias {}; - -// Tag declaration to disambiguate values and debug outlines. -using debug_outline = ::_cxxrtl_outline; - -// This structure is intended for consumption via foreign function interfaces, like Python's ctypes. -// Because of this it uses a C-style layout that is easy to parse rather than more idiomatic C++. -// -// To avoid violating strict aliasing rules, this structure has to be a subclass of the one used -// in the C API, or it would not be possible to cast between the pointers to these. -struct debug_item : ::cxxrtl_object { - // Object types. - enum : uint32_t { - VALUE = CXXRTL_VALUE, - WIRE = CXXRTL_WIRE, - MEMORY = CXXRTL_MEMORY, - ALIAS = CXXRTL_ALIAS, - OUTLINE = CXXRTL_OUTLINE, - }; - - // Object flags. - enum : uint32_t { - INPUT = CXXRTL_INPUT, - OUTPUT = CXXRTL_OUTPUT, - INOUT = CXXRTL_INOUT, - DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC, - DRIVEN_COMB = CXXRTL_DRIVEN_COMB, - UNDRIVEN = CXXRTL_UNDRIVEN, - }; - - debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {} - - template - debug_item(value &item, size_t lsb_offset = 0, uint32_t flags_ = 0) { - static_assert(sizeof(item) == value::chunks * sizeof(chunk_t), - "value is not compatible with C layout"); - type = VALUE; - flags = flags_; - width = Bits; - lsb_at = lsb_offset; - depth = 1; - zero_at = 0; - curr = item.data; - next = item.data; - outline = nullptr; - } - - template - debug_item(const value &item, size_t lsb_offset = 0) { - static_assert(sizeof(item) == value::chunks * sizeof(chunk_t), - "value is not compatible with C layout"); - type = VALUE; - flags = DRIVEN_COMB; - width = Bits; - lsb_at = lsb_offset; - depth = 1; - zero_at = 0; - curr = const_cast(item.data); - next = nullptr; - outline = nullptr; - } - - template - debug_item(wire &item, size_t lsb_offset = 0, uint32_t flags_ = 0) { - static_assert(sizeof(item.curr) == value::chunks * sizeof(chunk_t) && - sizeof(item.next) == value::chunks * sizeof(chunk_t), - "wire is not compatible with C layout"); - type = WIRE; - flags = flags_; - width = Bits; - lsb_at = lsb_offset; - depth = 1; - zero_at = 0; - curr = item.curr.data; - next = item.next.data; - outline = nullptr; - } - - template - debug_item(memory &item, size_t zero_offset = 0) { - static_assert(sizeof(item.data[0]) == value::chunks * sizeof(chunk_t), - "memory is not compatible with C layout"); - type = MEMORY; - flags = 0; - width = Width; - lsb_at = 0; - depth = item.depth; - zero_at = zero_offset; - curr = item.data ? item.data[0].data : nullptr; - next = nullptr; - outline = nullptr; - } - - template - debug_item(debug_alias, const value &item, size_t lsb_offset = 0) { - static_assert(sizeof(item) == value::chunks * sizeof(chunk_t), - "value is not compatible with C layout"); - type = ALIAS; - flags = DRIVEN_COMB; - width = Bits; - lsb_at = lsb_offset; - depth = 1; - zero_at = 0; - curr = const_cast(item.data); - next = nullptr; - outline = nullptr; - } - - template - debug_item(debug_alias, const wire &item, size_t lsb_offset = 0) { - static_assert(sizeof(item.curr) == value::chunks * sizeof(chunk_t) && - sizeof(item.next) == value::chunks * sizeof(chunk_t), - "wire is not compatible with C layout"); - type = ALIAS; - flags = DRIVEN_COMB; - width = Bits; - lsb_at = lsb_offset; - depth = 1; - zero_at = 0; - curr = const_cast(item.curr.data); - next = nullptr; - outline = nullptr; - } - - template - debug_item(debug_outline &group, const value &item, size_t lsb_offset = 0) { - static_assert(sizeof(item) == value::chunks * sizeof(chunk_t), - "value is not compatible with C layout"); - type = OUTLINE; - flags = DRIVEN_COMB; - width = Bits; - lsb_at = lsb_offset; - depth = 1; - zero_at = 0; - curr = const_cast(item.data); - next = nullptr; - outline = &group; - } - - template - IntegerT get() const { - assert(width == Bits && depth == 1); - value item; - std::copy(curr, curr + value::chunks, item.data); - return item.template get(); - } - - template - void set(IntegerT other) const { - assert(width == Bits && depth == 1); - value item; - item.template set(other); - std::copy(item.data, item.data + value::chunks, next); - } -}; -static_assert(std::is_standard_layout::value, "debug_item is not compatible with C layout"); - -struct debug_items { - std::map> table; - - void add(const std::string &name, debug_item &&item) { - std::vector &parts = table[name]; - parts.emplace_back(item); - std::sort(parts.begin(), parts.end(), - [](const debug_item &a, const debug_item &b) { - return a.lsb_at < b.lsb_at; - }); - } - - size_t count(const std::string &name) const { - if (table.count(name) == 0) - return 0; - return table.at(name).size(); - } - - const std::vector &parts_at(const std::string &name) const { - return table.at(name); - } - - const debug_item &at(const std::string &name) const { - const std::vector &parts = table.at(name); - assert(parts.size() == 1); - return parts.at(0); - } - - const debug_item &operator [](const std::string &name) const { - return at(name); - } -}; - -// Tag class to disambiguate the default constructor used by the toplevel module that calls reset(), -// and the constructor of interior modules that should not call it. -struct interior {}; - -struct module { - module() {} - virtual ~module() {} - - // Modules with black boxes cannot be copied. Although not all designs include black boxes, - // delete the copy constructor and copy assignment operator to make sure that any downstream - // code that manipulates modules doesn't accidentally depend on their availability. - module(const module &) = delete; - module &operator=(const module &) = delete; - - module(module &&) = default; - module &operator=(module &&) = default; - - virtual void reset() = 0; - - virtual bool eval() = 0; - virtual bool commit() = 0; - - size_t step() { - size_t deltas = 0; - bool converged = false; - do { - converged = eval(); - deltas++; - } while (commit() && !converged); - return deltas; - } - - virtual void debug_info(debug_items &items, std::string path = "") { - (void)items, (void)path; - } -}; - -} // namespace cxxrtl - -// Internal structures used to communicate with the implementation of the C interface. - -typedef struct _cxxrtl_toplevel { - std::unique_ptr module; -} *cxxrtl_toplevel; - -typedef struct _cxxrtl_outline { - std::function eval; -} *cxxrtl_outline; - -// Definitions of internal Yosys cells. Other than the functions in this namespace, CXXRTL is fully generic -// and indepenent of Yosys implementation details. -// -// The `write_cxxrtl` pass translates internal cells (cells with names that start with `$`) to calls of these -// functions. All of Yosys arithmetic and logical cells perform sign or zero extension on their operands, -// whereas basic operations on arbitrary width values require operands to be of the same width. These functions -// bridge the gap by performing the necessary casts. They are named similar to `cell_A[B]`, where A and B are `u` -// if the corresponding operand is unsigned, and `s` if it is signed. -namespace cxxrtl_yosys { - -using namespace cxxrtl; - -// std::max isn't constexpr until C++14 for no particular reason (it's an oversight), so we define our own. -template -CXXRTL_ALWAYS_INLINE -constexpr T max(const T &a, const T &b) { - return a > b ? a : b; -} - -// Logic operations -template -CXXRTL_ALWAYS_INLINE -value logic_not(const value &a) { - return value { a ? 0u : 1u }; -} - -template -CXXRTL_ALWAYS_INLINE -value logic_and(const value &a, const value &b) { - return value { (bool(a) && bool(b)) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value logic_or(const value &a, const value &b) { - return value { (bool(a) || bool(b)) ? 1u : 0u }; -} - -// Reduction operations -template -CXXRTL_ALWAYS_INLINE -value reduce_and(const value &a) { - return value { a.bit_not().is_zero() ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value reduce_or(const value &a) { - return value { a ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value reduce_xor(const value &a) { - return value { (a.ctpop() % 2) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value reduce_xnor(const value &a) { - return value { (a.ctpop() % 2) ? 0u : 1u }; -} - -template -CXXRTL_ALWAYS_INLINE -value reduce_bool(const value &a) { - return value { a ? 1u : 0u }; -} - -// Bitwise operations -template -CXXRTL_ALWAYS_INLINE -value not_u(const value &a) { - return a.template zcast().bit_not(); -} - -template -CXXRTL_ALWAYS_INLINE -value not_s(const value &a) { - return a.template scast().bit_not(); -} - -template -CXXRTL_ALWAYS_INLINE -value and_uu(const value &a, const value &b) { - return a.template zcast().bit_and(b.template zcast()); -} - -template -CXXRTL_ALWAYS_INLINE -value and_ss(const value &a, const value &b) { - return a.template scast().bit_and(b.template scast()); -} - -template -CXXRTL_ALWAYS_INLINE -value or_uu(const value &a, const value &b) { - return a.template zcast().bit_or(b.template zcast()); -} - -template -CXXRTL_ALWAYS_INLINE -value or_ss(const value &a, const value &b) { - return a.template scast().bit_or(b.template scast()); -} - -template -CXXRTL_ALWAYS_INLINE -value xor_uu(const value &a, const value &b) { - return a.template zcast().bit_xor(b.template zcast()); -} - -template -CXXRTL_ALWAYS_INLINE -value xor_ss(const value &a, const value &b) { - return a.template scast().bit_xor(b.template scast()); -} - -template -CXXRTL_ALWAYS_INLINE -value xnor_uu(const value &a, const value &b) { - return a.template zcast().bit_xor(b.template zcast()).bit_not(); -} - -template -CXXRTL_ALWAYS_INLINE -value xnor_ss(const value &a, const value &b) { - return a.template scast().bit_xor(b.template scast()).bit_not(); -} - -template -CXXRTL_ALWAYS_INLINE -value shl_uu(const value &a, const value &b) { - return a.template zcast().shl(b); -} - -template -CXXRTL_ALWAYS_INLINE -value shl_su(const value &a, const value &b) { - return a.template scast().shl(b); -} - -template -CXXRTL_ALWAYS_INLINE -value sshl_uu(const value &a, const value &b) { - return a.template zcast().shl(b); -} - -template -CXXRTL_ALWAYS_INLINE -value sshl_su(const value &a, const value &b) { - return a.template scast().shl(b); -} - -template -CXXRTL_ALWAYS_INLINE -value shr_uu(const value &a, const value &b) { - return a.shr(b).template zcast(); -} - -template -CXXRTL_ALWAYS_INLINE -value shr_su(const value &a, const value &b) { - return a.shr(b).template scast(); -} - -template -CXXRTL_ALWAYS_INLINE -value sshr_uu(const value &a, const value &b) { - return a.shr(b).template zcast(); -} - -template -CXXRTL_ALWAYS_INLINE -value sshr_su(const value &a, const value &b) { - return a.sshr(b).template scast(); -} - -template -CXXRTL_ALWAYS_INLINE -value shift_uu(const value &a, const value &b) { - return shr_uu(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value shift_su(const value &a, const value &b) { - return shr_su(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value shift_us(const value &a, const value &b) { - return b.is_neg() ? shl_uu(a, b.template sext().neg()) : shr_uu(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value shift_ss(const value &a, const value &b) { - return b.is_neg() ? shl_su(a, b.template sext().neg()) : shr_su(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value shiftx_uu(const value &a, const value &b) { - return shift_uu(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value shiftx_su(const value &a, const value &b) { - return shift_su(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value shiftx_us(const value &a, const value &b) { - return shift_us(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value shiftx_ss(const value &a, const value &b) { - return shift_ss(a, b); -} - -// Comparison operations -template -CXXRTL_ALWAYS_INLINE -value eq_uu(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value{ a.template zext() == b.template zext() ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value eq_ss(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value{ a.template sext() == b.template sext() ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value ne_uu(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value{ a.template zext() != b.template zext() ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value ne_ss(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value{ a.template sext() != b.template sext() ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value eqx_uu(const value &a, const value &b) { - return eq_uu(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value eqx_ss(const value &a, const value &b) { - return eq_ss(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value nex_uu(const value &a, const value &b) { - return ne_uu(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value nex_ss(const value &a, const value &b) { - return ne_ss(a, b); -} - -template -CXXRTL_ALWAYS_INLINE -value gt_uu(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value { b.template zext().ucmp(a.template zext()) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value gt_ss(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value { b.template sext().scmp(a.template sext()) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value ge_uu(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value { !a.template zext().ucmp(b.template zext()) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value ge_ss(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value { !a.template sext().scmp(b.template sext()) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value lt_uu(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value { a.template zext().ucmp(b.template zext()) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value lt_ss(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value { a.template sext().scmp(b.template sext()) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value le_uu(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value { !b.template zext().ucmp(a.template zext()) ? 1u : 0u }; -} - -template -CXXRTL_ALWAYS_INLINE -value le_ss(const value &a, const value &b) { - constexpr size_t BitsExt = max(BitsA, BitsB); - return value { !b.template sext().scmp(a.template sext()) ? 1u : 0u }; -} - -// Arithmetic operations -template -CXXRTL_ALWAYS_INLINE -value pos_u(const value &a) { - return a.template zcast(); -} - -template -CXXRTL_ALWAYS_INLINE -value pos_s(const value &a) { - return a.template scast(); -} - -template -CXXRTL_ALWAYS_INLINE -value neg_u(const value &a) { - return a.template zcast().neg(); -} - -template -CXXRTL_ALWAYS_INLINE -value neg_s(const value &a) { - return a.template scast().neg(); -} - -template -CXXRTL_ALWAYS_INLINE -value add_uu(const value &a, const value &b) { - return a.template zcast().add(b.template zcast()); -} - -template -CXXRTL_ALWAYS_INLINE -value add_ss(const value &a, const value &b) { - return a.template scast().add(b.template scast()); -} - -template -CXXRTL_ALWAYS_INLINE -value sub_uu(const value &a, const value &b) { - return a.template zcast().sub(b.template zcast()); -} - -template -CXXRTL_ALWAYS_INLINE -value sub_ss(const value &a, const value &b) { - return a.template scast().sub(b.template scast()); -} - -template -CXXRTL_ALWAYS_INLINE -value mul_uu(const value &a, const value &b) { - constexpr size_t BitsM = BitsA >= BitsB ? BitsA : BitsB; - return a.template zcast().template mul(b.template zcast()); -} - -template -CXXRTL_ALWAYS_INLINE -value mul_ss(const value &a, const value &b) { - return a.template scast().template mul(b.template scast()); -} - -template -CXXRTL_ALWAYS_INLINE -std::pair, value> divmod_uu(const value &a, const value &b) { - constexpr size_t Bits = max(BitsY, max(BitsA, BitsB)); - value quotient; - value dividend = a.template zext(); - value divisor = b.template zext(); - if (dividend.ucmp(divisor)) - return {/*quotient=*/value { 0u }, /*remainder=*/dividend.template trunc()}; - uint32_t divisor_shift = dividend.ctlz() - divisor.ctlz(); - divisor = divisor.shl(value<32> { divisor_shift }); - for (size_t step = 0; step <= divisor_shift; step++) { - quotient = quotient.shl(value<1> { 1u }); - if (!dividend.ucmp(divisor)) { - dividend = dividend.sub(divisor); - quotient.set_bit(0, true); - } - divisor = divisor.shr(value<1> { 1u }); - } - return {quotient.template trunc(), /*remainder=*/dividend.template trunc()}; -} - -template -CXXRTL_ALWAYS_INLINE -std::pair, value> divmod_ss(const value &a, const value &b) { - value ua = a.template sext(); - value ub = b.template sext(); - if (ua.is_neg()) ua = ua.neg(); - if (ub.is_neg()) ub = ub.neg(); - value y, r; - std::tie(y, r) = divmod_uu(ua, ub); - if (a.is_neg() != b.is_neg()) y = y.neg(); - if (a.is_neg()) r = r.neg(); - return {y, r}; -} - -template -CXXRTL_ALWAYS_INLINE -value div_uu(const value &a, const value &b) { - return divmod_uu(a, b).first; -} - -template -CXXRTL_ALWAYS_INLINE -value div_ss(const value &a, const value &b) { - return divmod_ss(a, b).first; -} - -template -CXXRTL_ALWAYS_INLINE -value mod_uu(const value &a, const value &b) { - return divmod_uu(a, b).second; -} - -template -CXXRTL_ALWAYS_INLINE -value mod_ss(const value &a, const value &b) { - return divmod_ss(a, b).second; -} - -template -CXXRTL_ALWAYS_INLINE -value modfloor_uu(const value &a, const value &b) { - return divmod_uu(a, b).second; -} - -// GHDL Modfloor operator. Returns r=a mod b, such that r has the same sign as b and -// a=b*N+r where N is some integer -// In practical terms, when a and b have different signs and the remainder returned by divmod_ss is not 0 -// then return the remainder + b -template -CXXRTL_ALWAYS_INLINE -value modfloor_ss(const value &a, const value &b) { - value r; - r = divmod_ss(a, b).second; - if((b.is_neg() != a.is_neg()) && !r.is_zero()) - return add_ss(b, r); - return r; -} - - -// Memory helper -struct memory_index { - bool valid; - size_t index; - - template - memory_index(const value &addr, size_t offset, size_t depth) { - static_assert(value::chunks <= 1, "memory address is too wide"); - size_t offset_index = addr.data[0]; - - valid = (offset_index >= offset && offset_index < offset + depth); - index = offset_index - offset; - } -}; - -} // namespace cxxrtl_yosys - -#endif diff --git a/yosys/backends/cxxrtl/cxxrtl_backend.cc b/yosys/backends/cxxrtl/cxxrtl_backend.cc deleted file mode 100644 index 62768bd3395..00000000000 --- a/yosys/backends/cxxrtl/cxxrtl_backend.cc +++ /dev/null @@ -1,3428 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2019-2020 whitequark - * - * 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/utils.h" -#include "kernel/celltypes.h" -#include "kernel/mem.h" -#include "kernel/log.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -// [[CITE]] -// Peter Eades; Xuemin Lin; W. F. Smyth, "A Fast Effective Heuristic For The Feedback Arc Set Problem" -// Information Processing Letters, Vol. 47, pp 319-323, 1993 -// https://pdfs.semanticscholar.org/c7ed/d9acce96ca357876540e19664eb9d976637f.pdf - -// A topological sort (on a cell/wire graph) is always possible in a fully flattened RTLIL design without -// processes or logic loops where every wire has a single driver. Logic loops are illegal in RTLIL and wires -// with multiple drivers can be split by the `splitnets` pass; however, interdependencies between processes -// or module instances can create strongly connected components without introducing evaluation nondeterminism. -// We wish to support designs with such benign SCCs (as well as designs with multiple drivers per wire), so -// we sort the graph in a way that minimizes feedback arcs. If there are no feedback arcs in the sorted graph, -// then a more efficient evaluation method is possible, since eval() will always immediately converge. -template -struct Scheduler { - struct Vertex { - T *data; - Vertex *prev, *next; - pool preds, succs; - - Vertex() : data(NULL), prev(this), next(this) {} - Vertex(T *data) : data(data), prev(NULL), next(NULL) {} - - bool empty() const - { - log_assert(data == NULL); - if (next == this) { - log_assert(prev == next); - return true; - } - return false; - } - - void link(Vertex *list) - { - log_assert(prev == NULL && next == NULL); - next = list; - prev = list->prev; - list->prev->next = this; - list->prev = this; - } - - void unlink() - { - log_assert(prev->next == this && next->prev == this); - prev->next = next; - next->prev = prev; - next = prev = NULL; - } - - int delta() const - { - return succs.size() - preds.size(); - } - }; - - std::vector vertices; - Vertex *sources = new Vertex; - Vertex *sinks = new Vertex; - dict bins; - - ~Scheduler() - { - delete sources; - delete sinks; - for (auto bin : bins) - delete bin.second; - for (auto vertex : vertices) - delete vertex; - } - - Vertex *add(T *data) - { - Vertex *vertex = new Vertex(data); - vertices.push_back(vertex); - return vertex; - } - - void relink(Vertex *vertex) - { - if (vertex->succs.empty()) - vertex->link(sinks); - else if (vertex->preds.empty()) - vertex->link(sources); - else { - int delta = vertex->delta(); - if (!bins.count(delta)) - bins[delta] = new Vertex; - vertex->link(bins[delta]); - } - } - - Vertex *remove(Vertex *vertex) - { - vertex->unlink(); - for (auto pred : vertex->preds) { - if (pred == vertex) - continue; - log_assert(pred->succs[vertex]); - pred->unlink(); - pred->succs.erase(vertex); - relink(pred); - } - for (auto succ : vertex->succs) { - if (succ == vertex) - continue; - log_assert(succ->preds[vertex]); - succ->unlink(); - succ->preds.erase(vertex); - relink(succ); - } - vertex->preds.clear(); - vertex->succs.clear(); - return vertex; - } - - std::vector schedule() - { - std::vector s1, s2r; - for (auto vertex : vertices) - relink(vertex); - bool bins_empty = false; - while (!(sinks->empty() && sources->empty() && bins_empty)) { - while (!sinks->empty()) - s2r.push_back(remove(sinks->next)); - while (!sources->empty()) - s1.push_back(remove(sources->next)); - // Choosing u in this implementation isn't O(1), but the paper handwaves which data structure they suggest - // using to get O(1) relinking *and* find-max-key ("it is clear"... no it isn't), so this code uses a very - // naive implementation of find-max-key. - bins_empty = true; - bins.template sort>(); - for (auto bin : bins) { - if (!bin.second->empty()) { - bins_empty = false; - s1.push_back(remove(bin.second->next)); - break; - } - } - } - s1.insert(s1.end(), s2r.rbegin(), s2r.rend()); - return s1; - } -}; - -bool is_unary_cell(RTLIL::IdString type) -{ - return type.in( - ID($not), ID($logic_not), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), - ID($pos), ID($neg)); -} - -bool is_binary_cell(RTLIL::IdString type) -{ - return type.in( - ID($and), ID($or), ID($xor), ID($xnor), ID($logic_and), ID($logic_or), - ID($shl), ID($sshl), ID($shr), ID($sshr), ID($shift), ID($shiftx), - ID($eq), ID($ne), ID($eqx), ID($nex), ID($gt), ID($ge), ID($lt), ID($le), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor)); -} - -bool is_extending_cell(RTLIL::IdString type) -{ - return !type.in( - ID($logic_not), ID($logic_and), ID($logic_or), - ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool)); -} - -bool is_inlinable_cell(RTLIL::IdString type) -{ - return is_unary_cell(type) || is_binary_cell(type) || type.in( - ID($mux), ID($concat), ID($slice), ID($pmux), ID($bmux), ID($demux)); -} - -bool is_ff_cell(RTLIL::IdString type) -{ - return type.in( - ID($dff), ID($dffe), ID($sdff), ID($sdffe), ID($sdffce), - ID($adff), ID($adffe), ID($dffsr), ID($dffsre), - ID($aldff), ID($aldffe), - ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr)); -} - -bool is_internal_cell(RTLIL::IdString type) -{ - return !type.isPublic() && !type.begins_with("$paramod"); -} - -bool is_effectful_cell(RTLIL::IdString type) -{ - return type.isPublic(); -} - -bool is_cxxrtl_blackbox_cell(const RTLIL::Cell *cell) -{ - RTLIL::Module *cell_module = cell->module->design->module(cell->type); - log_assert(cell_module != nullptr); - return cell_module->get_bool_attribute(ID(cxxrtl_blackbox)); -} - -bool is_memwr_process(const RTLIL::Process *process) -{ - for (auto sync : process->syncs) - if (!sync->mem_write_actions.empty()) - return true; - return false; -} - -enum class CxxrtlPortType { - UNKNOWN = 0, // or mixed comb/sync - COMB = 1, - SYNC = 2, -}; - -CxxrtlPortType cxxrtl_port_type(RTLIL::Module *module, RTLIL::IdString port) -{ - RTLIL::Wire *output_wire = module->wire(port); - log_assert(output_wire != nullptr); - bool is_comb = output_wire->get_bool_attribute(ID(cxxrtl_comb)); - bool is_sync = output_wire->get_bool_attribute(ID(cxxrtl_sync)); - if (is_comb && is_sync) - log_cmd_error("Port `%s.%s' is marked as both `cxxrtl_comb` and `cxxrtl_sync`.\n", - log_id(module), log_signal(output_wire)); - else if (is_comb) - return CxxrtlPortType::COMB; - else if (is_sync) - return CxxrtlPortType::SYNC; - return CxxrtlPortType::UNKNOWN; -} - -CxxrtlPortType cxxrtl_port_type(const RTLIL::Cell *cell, RTLIL::IdString port) -{ - RTLIL::Module *cell_module = cell->module->design->module(cell->type); - if (cell_module == nullptr || !cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) - return CxxrtlPortType::UNKNOWN; - return cxxrtl_port_type(cell_module, port); -} - -bool is_cxxrtl_comb_port(const RTLIL::Cell *cell, RTLIL::IdString port) -{ - return cxxrtl_port_type(cell, port) == CxxrtlPortType::COMB; -} - -bool is_cxxrtl_sync_port(const RTLIL::Cell *cell, RTLIL::IdString port) -{ - return cxxrtl_port_type(cell, port) == CxxrtlPortType::SYNC; -} - -struct FlowGraph { - struct Node { - enum class Type { - CONNECT, - CELL_SYNC, - CELL_EVAL, - PROCESS_SYNC, - PROCESS_CASE, - MEM_RDPORT, - MEM_WRPORTS, - }; - - Type type; - RTLIL::SigSig connect = {}; - const RTLIL::Cell *cell = nullptr; - const RTLIL::Process *process = nullptr; - const Mem *mem = nullptr; - int portidx; - }; - - std::vector nodes; - dict> wire_comb_defs, wire_sync_defs, wire_uses; - dict, hash_ptr_ops> node_comb_defs, node_sync_defs, node_uses; - dict wire_def_inlinable; - dict> wire_use_inlinable; - dict bit_has_state; - - ~FlowGraph() - { - for (auto node : nodes) - delete node; - } - - void add_defs(Node *node, const RTLIL::SigSpec &sig, bool is_ff, bool inlinable) - { - for (auto chunk : sig.chunks()) - if (chunk.wire) { - if (is_ff) { - // A sync def means that a wire holds design state because it is driven directly by - // a flip-flop output. Such a wire can never be unbuffered. - wire_sync_defs[chunk.wire].insert(node); - node_sync_defs[node].insert(chunk.wire); - } else { - // A comb def means that a wire doesn't hold design state. It might still be connected, - // indirectly, to a flip-flop output. - wire_comb_defs[chunk.wire].insert(node); - node_comb_defs[node].insert(chunk.wire); - } - } - for (auto bit : sig.bits()) - bit_has_state[bit] |= is_ff; - // Only comb defs of an entire wire in the right order can be inlined. - if (!is_ff && sig.is_wire()) { - // Only a single def of a wire can be inlined. (Multiple defs of a wire are unsound, but we - // handle them anyway to avoid assertion failures later.) - if (!wire_def_inlinable.count(sig.as_wire())) - wire_def_inlinable[sig.as_wire()] = inlinable; - else - wire_def_inlinable[sig.as_wire()] = false; - } - } - - void add_uses(Node *node, const RTLIL::SigSpec &sig) - { - for (auto chunk : sig.chunks()) - if (chunk.wire) { - wire_uses[chunk.wire].insert(node); - node_uses[node].insert(chunk.wire); - // Only a single use of an entire wire in the right order can be inlined. (But the use can include - // other chunks.) This is tracked per-node because a wire used by multiple nodes can still be inlined - // if all but one of those nodes is dead. - if (!wire_use_inlinable[chunk.wire].count(node)) - wire_use_inlinable[chunk.wire][node] = true; - else - wire_use_inlinable[chunk.wire][node] = false; - } - } - - bool is_inlinable(const RTLIL::Wire *wire) const - { - // Can the wire be inlined at all? - if (wire_def_inlinable.count(wire)) - return wire_def_inlinable.at(wire); - return false; - } - - bool is_inlinable(const RTLIL::Wire *wire, const pool &nodes) const - { - // Can the wire be inlined, knowing that the given nodes are reachable? - if (nodes.size() != 1) - return false; - Node *node = *nodes.begin(); - log_assert(node_uses.at(node).count(wire)); - if (is_inlinable(wire) && wire_use_inlinable.count(wire) && wire_use_inlinable.at(wire).count(node)) - return wire_use_inlinable.at(wire).at(node); - return false; - } - - // Connections - void add_connect_defs_uses(Node *node, const RTLIL::SigSig &conn) - { - add_defs(node, conn.first, /*is_ff=*/false, /*inlinable=*/true); - add_uses(node, conn.second); - } - - Node *add_node(const RTLIL::SigSig &conn) - { - Node *node = new Node; - node->type = Node::Type::CONNECT; - node->connect = conn; - nodes.push_back(node); - add_connect_defs_uses(node, conn); - return node; - } - - // Cells - void add_cell_sync_defs(Node *node, const RTLIL::Cell *cell) - { - // To understand why this node type is necessary and why it produces comb defs, consider a cell - // with input \i and sync output \o, used in a design such that \i is connected to \o. This does - // not result in a feedback arc because the output is synchronous. However, a naive implementation - // of code generation for cells that assigns to inputs, evaluates cells, assigns from outputs - // would not be able to immediately converge... - // - // wire<1> i_tmp; - // cell->p_i = i_tmp.curr; - // cell->eval(); - // i_tmp.next = cell->p_o.curr; - // - // ... since the wire connecting the input and output ports would not be localizable. To solve - // this, the cell is split into two scheduling nodes; one exclusively for sync outputs, and - // another for inputs and all non-sync outputs. This way the generated code can be rearranged... - // - // value<1> i_tmp; - // i_tmp = cell->p_o.curr; - // cell->p_i = i_tmp; - // cell->eval(); - // - // eliminating the unnecessary delta cycle. Conceptually, the CELL_SYNC node type is a series of - // connections of the form `connect \lhs \cell.\sync_output`; the right-hand side of these is not - // expressible as a wire in RTLIL. If it was expressible, then `\cell.\sync_output` would have - // a sync def, and this node would be an ordinary CONNECT node, with `\lhs` having a comb def. - // Because it isn't, a special node type is used, the right-hand side does not appear anywhere, - // and the left-hand side has a comb def. - for (auto conn : cell->connections()) - if (cell->output(conn.first)) - if (is_cxxrtl_sync_port(cell, conn.first)) { - // See note regarding inlinability below. - add_defs(node, conn.second, /*is_ff=*/false, /*inlinable=*/false); - } - } - - void add_cell_eval_defs_uses(Node *node, const RTLIL::Cell *cell) - { - for (auto conn : cell->connections()) { - if (cell->output(conn.first)) { - if (is_inlinable_cell(cell->type)) - add_defs(node, conn.second, /*is_ff=*/false, /*inlinable=*/true); - else if (is_ff_cell(cell->type)) - add_defs(node, conn.second, /*is_ff=*/true, /*inlinable=*/false); - else if (is_internal_cell(cell->type)) - add_defs(node, conn.second, /*is_ff=*/false, /*inlinable=*/false); - else if (!is_cxxrtl_sync_port(cell, conn.first)) { - // Although at first it looks like outputs of user-defined cells may always be inlined, the reality is - // more complex. Fully sync outputs produce no defs and so don't participate in inlining. Fully comb - // outputs are assigned in a different way depending on whether the cell's eval() immediately converged. - // Unknown/mixed outputs could be inlined, but should be rare in practical designs and don't justify - // the infrastructure required to inline outputs of cells with many of them. - add_defs(node, conn.second, /*is_ff=*/false, /*inlinable=*/false); - } - } - if (cell->input(conn.first)) - add_uses(node, conn.second); - } - } - - Node *add_node(const RTLIL::Cell *cell) - { - log_assert(cell->known()); - - bool has_fully_sync_outputs = false; - for (auto conn : cell->connections()) - if (cell->output(conn.first) && is_cxxrtl_sync_port(cell, conn.first)) { - has_fully_sync_outputs = true; - break; - } - if (has_fully_sync_outputs) { - Node *node = new Node; - node->type = Node::Type::CELL_SYNC; - node->cell = cell; - nodes.push_back(node); - add_cell_sync_defs(node, cell); - } - - Node *node = new Node; - node->type = Node::Type::CELL_EVAL; - node->cell = cell; - nodes.push_back(node); - add_cell_eval_defs_uses(node, cell); - return node; - } - - // Processes - void add_case_rule_defs_uses(Node *node, const RTLIL::CaseRule *case_) - { - for (auto &action : case_->actions) { - add_defs(node, action.first, /*is_ff=*/false, /*inlinable=*/false); - add_uses(node, action.second); - } - for (auto sub_switch : case_->switches) { - add_uses(node, sub_switch->signal); - for (auto sub_case : sub_switch->cases) { - for (auto &compare : sub_case->compare) - add_uses(node, compare); - add_case_rule_defs_uses(node, sub_case); - } - } - } - - void add_sync_rules_defs_uses(Node *node, const RTLIL::Process *process) - { - for (auto sync : process->syncs) { - for (auto &action : sync->actions) { - if (sync->type == RTLIL::STp || sync->type == RTLIL::STn || sync->type == RTLIL::STe) - add_defs(node, action.first, /*is_ff=*/true, /*inlinable=*/false); - else - add_defs(node, action.first, /*is_ff=*/false, /*inlinable=*/false); - add_uses(node, action.second); - } - for (auto &memwr : sync->mem_write_actions) { - add_uses(node, memwr.address); - add_uses(node, memwr.data); - add_uses(node, memwr.enable); - } - } - } - - Node *add_node(const RTLIL::Process *process) - { - Node *node = new Node; - node->type = Node::Type::PROCESS_SYNC; - node->process = process; - nodes.push_back(node); - add_sync_rules_defs_uses(node, process); - - node = new Node; - node->type = Node::Type::PROCESS_CASE; - node->process = process; - nodes.push_back(node); - add_case_rule_defs_uses(node, &process->root_case); - return node; - } - - // Memories - void add_node(const Mem *mem) { - for (int i = 0; i < GetSize(mem->rd_ports); i++) { - auto &port = mem->rd_ports[i]; - Node *node = new Node; - node->type = Node::Type::MEM_RDPORT; - node->mem = mem; - node->portidx = i; - nodes.push_back(node); - add_defs(node, port.data, /*is_ff=*/port.clk_enable, /*inlinable=*/false); - add_uses(node, port.clk); - add_uses(node, port.en); - add_uses(node, port.arst); - add_uses(node, port.srst); - add_uses(node, port.addr); - bool transparent = false; - for (int j = 0; j < GetSize(mem->wr_ports); j++) { - auto &wrport = mem->wr_ports[j]; - if (port.transparency_mask[j]) { - // Our implementation of transparent read ports reads en, addr and data from every write port - // the read port is transparent with. - add_uses(node, wrport.en); - add_uses(node, wrport.addr); - add_uses(node, wrport.data); - transparent = true; - } - } - // Also we read the read address twice in this case (prevent inlining). - if (transparent) - add_uses(node, port.addr); - } - if (!mem->wr_ports.empty()) { - Node *node = new Node; - node->type = Node::Type::MEM_WRPORTS; - node->mem = mem; - nodes.push_back(node); - for (auto &port : mem->wr_ports) { - add_uses(node, port.clk); - add_uses(node, port.en); - add_uses(node, port.addr); - add_uses(node, port.data); - } - } - } -}; - -std::vector split_by(const std::string &str, const std::string &sep) -{ - std::vector result; - size_t prev = 0; - while (true) { - size_t curr = str.find_first_of(sep, prev); - if (curr == std::string::npos) { - std::string part = str.substr(prev); - if (!part.empty()) result.push_back(part); - break; - } else { - std::string part = str.substr(prev, curr - prev); - if (!part.empty()) result.push_back(part); - prev = curr + 1; - } - } - return result; -} - -std::string escape_cxx_string(const std::string &input) -{ - std::string output = "\""; - for (auto c : input) { - if (::isprint(c)) { - if (c == '\\') - output.push_back('\\'); - output.push_back(c); - } else { - char l = c & 0xf, h = (c >> 4) & 0xf; - output.append("\\x"); - output.push_back((h < 10 ? '0' + h : 'a' + h - 10)); - output.push_back((l < 10 ? '0' + l : 'a' + l - 10)); - } - } - output.push_back('"'); - if (output.find('\0') != std::string::npos) { - output.insert(0, "std::string {"); - output.append(stringf(", %zu}", input.size())); - } - return output; -} - -template -std::string get_hdl_name(T *object) -{ - if (object->has_attribute(ID::hdlname)) - return object->get_string_attribute(ID::hdlname); - else - return object->name.str().substr(1); -} - -struct WireType { - enum Type { - // Non-referenced wire; is not a part of the design. - UNUSED, - // Double-buffered wire; is a class member, and holds design state. - BUFFERED, - // Single-buffered wire; is a class member, but holds no state. - MEMBER, - // Single-buffered wire; is a class member, and is computed on demand. - OUTLINE, - // Local wire; is a local variable in eval method. - LOCAL, - // Inline wire; is an unnamed temporary in eval method. - INLINE, - // Alias wire; is replaced with aliasee, except in debug info. - ALIAS, - // Const wire; is replaced with constant, except in debug info. - CONST, - }; - - Type type = UNUSED; - const RTLIL::Cell *cell_subst = nullptr; // for INLINE - RTLIL::SigSpec sig_subst = {}; // for INLINE, ALIAS, and CONST - - WireType() = default; - - WireType(Type type) : type(type) { - log_assert(type == UNUSED || type == BUFFERED || type == MEMBER || type == OUTLINE || type == LOCAL); - } - - WireType(Type type, const RTLIL::Cell *cell) : type(type), cell_subst(cell) { - log_assert(type == INLINE && is_inlinable_cell(cell->type)); - } - - WireType(Type type, RTLIL::SigSpec sig) : type(type), sig_subst(sig) { - log_assert(type == INLINE || (type == ALIAS && sig.is_wire()) || (type == CONST && sig.is_fully_const())); - } - - bool is_buffered() const { return type == BUFFERED; } - bool is_member() const { return type == BUFFERED || type == MEMBER || type == OUTLINE; } - bool is_outline() const { return type == OUTLINE; } - bool is_named() const { return is_member() || type == LOCAL; } - bool is_local() const { return type == LOCAL || type == INLINE; } - bool is_exact() const { return type == ALIAS || type == CONST; } -}; - -// Tests for a SigSpec that is a valid clock input, clocks have to have a backing wire and be a single bit -// using this instead of sig.is_wire() solves issues when the clock is a slice instead of a full wire -bool is_valid_clock(const RTLIL::SigSpec& sig) { - return sig.is_chunk() && sig.is_bit() && sig[0].wire; -} - -struct CxxrtlWorker { - bool split_intf = false; - std::string intf_filename; - std::string design_ns = "cxxrtl_design"; - std::ostream *impl_f = nullptr; - std::ostream *intf_f = nullptr; - - bool print_wire_types = false; - bool print_debug_wire_types = false; - bool run_hierarchy = false; - bool run_flatten = false; - bool run_proc = false; - - bool unbuffer_internal = false; - bool unbuffer_public = false; - bool localize_internal = false; - bool localize_public = false; - bool inline_internal = false; - bool inline_public = false; - - bool debug_info = false; - bool debug_member = false; - bool debug_alias = false; - bool debug_eval = false; - - std::ostringstream f; - std::string indent; - int temporary = 0; - - dict sigmaps; - dict> mod_memories; - pool> writable_memories; - pool edge_wires; - dict wire_init; - dict edge_types; - dict> schedule, debug_schedule; - dict wire_types, debug_wire_types; - dict bit_has_state; - dict> blackbox_specializations; - dict eval_converges; - - void inc_indent() { - indent += "\t"; - } - void dec_indent() { - indent.resize(indent.size() - 1); - } - - // RTLIL allows any characters in names other than whitespace. This presents an issue for generating C++ code - // because C++ identifiers may be only alphanumeric, cannot clash with C++ keywords, and cannot clash with cxxrtl - // identifiers. This issue can be solved with a name mangling scheme. We choose a name mangling scheme that results - // in readable identifiers, does not depend on an up-to-date list of C++ keywords, and is easy to apply. Its rules: - // 1. All generated identifiers start with `_`. - // 1a. Generated identifiers for public names (beginning with `\`) start with `p_`. - // 1b. Generated identifiers for internal names (beginning with `$`) start with `i_`. - // 2. An underscore is escaped with another underscore, i.e. `__`. - // 3. Any other non-alnum character is escaped with underscores around its lowercase hex code, e.g. `@` as `_40_`. - std::string mangle_name(const RTLIL::IdString &name) - { - std::string mangled; - bool first = true; - for (char c : name.str()) { - if (first) { - first = false; - if (c == '\\') - mangled += "p_"; - else if (c == '$') - mangled += "i_"; - else - log_assert(false); - } else { - if (isalnum(c)) { - mangled += c; - } else if (c == '_') { - mangled += "__"; - } else { - char l = c & 0xf, h = (c >> 4) & 0xf; - mangled += '_'; - mangled += (h < 10 ? '0' + h : 'a' + h - 10); - mangled += (l < 10 ? '0' + l : 'a' + l - 10); - mangled += '_'; - } - } - } - return mangled; - } - - std::string mangle_module_name(const RTLIL::IdString &name, bool is_blackbox = false) - { - // Class namespace. - if (is_blackbox) - return "bb_" + mangle_name(name); - return mangle_name(name); - } - - std::string mangle_memory_name(const RTLIL::IdString &name) - { - // Class member namespace. - return "memory_" + mangle_name(name); - } - - std::string mangle_cell_name(const RTLIL::IdString &name) - { - // Class member namespace. - return "cell_" + mangle_name(name); - } - - std::string mangle_wire_name(const RTLIL::IdString &name) - { - // Class member namespace. - return mangle_name(name); - } - - std::string mangle(const RTLIL::Module *module) - { - return mangle_module_name(module->name, /*is_blackbox=*/module->get_bool_attribute(ID(cxxrtl_blackbox))); - } - - std::string mangle(const Mem *mem) - { - return mangle_memory_name(mem->memid); - } - - std::string mangle(const RTLIL::Memory *memory) - { - return mangle_memory_name(memory->name); - } - - std::string mangle(const RTLIL::Cell *cell) - { - return mangle_cell_name(cell->name); - } - - std::string mangle(const RTLIL::Wire *wire) - { - return mangle_wire_name(wire->name); - } - - std::string mangle(RTLIL::SigBit sigbit) - { - log_assert(sigbit.wire != NULL); - if (sigbit.wire->width == 1) - return mangle(sigbit.wire); - return mangle(sigbit.wire) + "_" + std::to_string(sigbit.offset); - } - - std::vector template_param_names(const RTLIL::Module *module) - { - if (!module->has_attribute(ID(cxxrtl_template))) - return {}; - - if (module->attributes.at(ID(cxxrtl_template)).flags != RTLIL::CONST_FLAG_STRING) - log_cmd_error("Attribute `cxxrtl_template' of module `%s' is not a string.\n", log_id(module)); - - std::vector param_names = split_by(module->get_string_attribute(ID(cxxrtl_template)), " \t"); - for (const auto ¶m_name : param_names) { - // Various lowercase prefixes (p_, i_, cell_, ...) are used for member variables, so require - // parameters to start with an uppercase letter to avoid name conflicts. (This is the convention - // in both Verilog and C++, anyway.) - if (!isupper(param_name[0])) - log_cmd_error("Attribute `cxxrtl_template' of module `%s' includes a parameter `%s', " - "which does not start with an uppercase letter.\n", - log_id(module), param_name.c_str()); - } - return param_names; - } - - std::string template_params(const RTLIL::Module *module, bool is_decl) - { - std::vector param_names = template_param_names(module); - if (param_names.empty()) - return ""; - - std::string params = "<"; - bool first = true; - for (const auto ¶m_name : param_names) { - if (!first) - params += ", "; - first = false; - if (is_decl) - params += "size_t "; - params += param_name; - } - params += ">"; - return params; - } - - std::string template_args(const RTLIL::Cell *cell) - { - RTLIL::Module *cell_module = cell->module->design->module(cell->type); - log_assert(cell_module != nullptr); - if (!cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) - return ""; - - std::vector param_names = template_param_names(cell_module); - if (param_names.empty()) - return ""; - - std::string params = "<"; - bool first = true; - for (const auto ¶m_name : param_names) { - if (!first) - params += ", "; - first = false; - params += "/*" + param_name + "=*/"; - RTLIL::IdString id_param_name = '\\' + param_name; - if (!cell->hasParam(id_param_name)) - log_cmd_error("Cell `%s.%s' does not have a parameter `%s', which is required by the templated module `%s'.\n", - log_id(cell->module), log_id(cell), param_name.c_str(), log_id(cell_module)); - RTLIL::Const param_value = cell->getParam(id_param_name); - if (((param_value.flags & ~RTLIL::CONST_FLAG_SIGNED) != 0) || param_value.as_int() < 0) - log_cmd_error("Parameter `%s' of cell `%s.%s', which is required by the templated module `%s', " - "is not a positive integer.\n", - param_name.c_str(), log_id(cell->module), log_id(cell), log_id(cell_module)); - params += std::to_string(cell->getParam(id_param_name).as_int()); - } - params += ">"; - return params; - } - - std::string fresh_temporary() - { - return stringf("tmp_%d", temporary++); - } - - void dump_attrs(const RTLIL::AttrObject *object) - { - for (auto attr : object->attributes) { - f << indent << "// " << attr.first.str() << ": "; - if (attr.second.flags & RTLIL::CONST_FLAG_STRING) { - f << attr.second.decode_string(); - } else { - f << attr.second.as_int(/*is_signed=*/attr.second.flags & RTLIL::CONST_FLAG_SIGNED); - } - f << "\n"; - } - } - - void dump_const_init(const RTLIL::Const &data, int width, int offset = 0, bool fixed_width = false) - { - const int CHUNK_SIZE = 32; - f << "{"; - while (width > 0) { - int chunk_width = min(width, CHUNK_SIZE); - uint32_t chunk = data.extract(offset, chunk_width).as_int(); - if (fixed_width) - f << stringf("0x%.*xu", (3 + chunk_width) / 4, chunk); - else - f << stringf("%#xu", chunk); - if (width > CHUNK_SIZE) - f << ','; - offset += CHUNK_SIZE; - width -= CHUNK_SIZE; - } - f << "}"; - } - - void dump_const(const RTLIL::Const &data, int width, int offset = 0, bool fixed_width = false) - { - f << "value<" << width << ">"; - dump_const_init(data, width, offset, fixed_width); - } - - void dump_const(const RTLIL::Const &data) - { - dump_const(data, data.size()); - } - - bool dump_sigchunk(const RTLIL::SigChunk &chunk, bool is_lhs, bool for_debug = false) - { - if (chunk.wire == NULL) { - dump_const(chunk.data, chunk.width, chunk.offset); - return false; - } else { - const auto &wire_type = (for_debug ? debug_wire_types : wire_types)[chunk.wire]; - switch (wire_type.type) { - case WireType::BUFFERED: - f << mangle(chunk.wire) << (is_lhs ? ".next" : ".curr"); - break; - case WireType::MEMBER: - case WireType::LOCAL: - case WireType::OUTLINE: - f << mangle(chunk.wire); - break; - case WireType::INLINE: - log_assert(!is_lhs); - if (wire_type.cell_subst != nullptr) { - dump_cell_expr(wire_type.cell_subst, for_debug); - break; - } - YS_FALLTHROUGH - case WireType::ALIAS: - case WireType::CONST: - log_assert(!is_lhs); - return dump_sigspec(wire_type.sig_subst.extract(chunk.offset, chunk.width), is_lhs, for_debug); - case WireType::UNUSED: - log_assert(is_lhs); - f << "value<" << chunk.width << ">()"; - return false; - } - if (chunk.width == chunk.wire->width && chunk.offset == 0) - return false; - else if (chunk.width == 1) - f << ".slice<" << chunk.offset << ">()"; - else - f << ".slice<" << chunk.offset+chunk.width-1 << "," << chunk.offset << ">()"; - return true; - } - } - - bool dump_sigspec(const RTLIL::SigSpec &sig, bool is_lhs, bool for_debug = false) - { - if (sig.empty()) { - f << "value<0>()"; - return false; - } else if (sig.is_chunk()) { - return dump_sigchunk(sig.as_chunk(), is_lhs, for_debug); - } else { - bool first = true; - auto chunks = sig.chunks(); - for (auto it = chunks.rbegin(); it != chunks.rend(); it++) { - if (!first) - f << ".concat("; - bool is_complex = dump_sigchunk(*it, is_lhs, for_debug); - if (!is_lhs && it->width == 1) { - size_t repeat = 1; - while ((it + repeat) != chunks.rend() && *(it + repeat) == *it) - repeat++; - if (repeat > 1) { - if (is_complex) - f << ".val()"; - f << ".repeat<" << repeat << ">()"; - } - it += repeat - 1; - } - if (!first) - f << ")"; - first = false; - } - return true; - } - } - - void dump_sigspec_lhs(const RTLIL::SigSpec &sig, bool for_debug = false) - { - dump_sigspec(sig, /*is_lhs=*/true, for_debug); - } - - void dump_sigspec_rhs(const RTLIL::SigSpec &sig, bool for_debug = false) - { - // In the contexts where we want template argument deduction to occur for `template ... value`, - // it is necessary to have the argument to already be a `value`, since template argument deduction and implicit - // type conversion are mutually exclusive. In these contexts, we use dump_sigspec_rhs() to emit an explicit - // type conversion, but only if the expression needs it. - bool is_complex = dump_sigspec(sig, /*is_lhs=*/false, for_debug); - if (is_complex) - f << ".val()"; - } - - void dump_inlined_cells(const std::vector &cells) - { - if (cells.empty()) { - f << indent << "// connection\n"; - } else if (cells.size() == 1) { - dump_attrs(cells.front()); - f << indent << "// cell " << cells.front()->name.str() << "\n"; - } else { - f << indent << "// cells"; - for (auto cell : cells) - f << " " << cell->name.str(); - f << "\n"; - } - } - - void collect_sigspec_rhs(const RTLIL::SigSpec &sig, bool for_debug, std::vector &cells) - { - for (auto chunk : sig.chunks()) { - if (!chunk.wire) - continue; - const auto &wire_type = wire_types[chunk.wire]; - switch (wire_type.type) { - case WireType::INLINE: - if (wire_type.cell_subst != nullptr) { - collect_cell_eval(wire_type.cell_subst, for_debug, cells); - break; - } - YS_FALLTHROUGH - case WireType::ALIAS: - collect_sigspec_rhs(wire_type.sig_subst, for_debug, cells); - break; - default: - break; - } - } - } - - void dump_connect_expr(const RTLIL::SigSig &conn, bool for_debug = false) - { - dump_sigspec_rhs(conn.second, for_debug); - } - - void dump_connect(const RTLIL::SigSig &conn, bool for_debug = false) - { - std::vector inlined_cells; - collect_sigspec_rhs(conn.second, for_debug, inlined_cells); - dump_inlined_cells(inlined_cells); - - f << indent; - dump_sigspec_lhs(conn.first, for_debug); - f << " = "; - dump_connect_expr(conn, for_debug); - f << ";\n"; - } - - void collect_connect(const RTLIL::SigSig &conn, bool for_debug, std::vector &cells) - { - collect_sigspec_rhs(conn.second, for_debug, cells); - } - - void dump_cell_sync(const RTLIL::Cell *cell, bool for_debug = false) - { - const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : "."; - f << indent << "// cell " << cell->name.str() << " syncs\n"; - for (auto conn : cell->connections()) - if (cell->output(conn.first)) - if (is_cxxrtl_sync_port(cell, conn.first)) { - f << indent; - dump_sigspec_lhs(conn.second, for_debug); - f << " = " << mangle(cell) << access << mangle_wire_name(conn.first) << ".curr;\n"; - } - } - - void dump_cell_expr(const RTLIL::Cell *cell, bool for_debug = false) - { - // Unary cells - if (is_unary_cell(cell->type)) { - f << cell->type.substr(1); - if (is_extending_cell(cell->type)) - f << '_' << (cell->getParam(ID::A_SIGNED).as_bool() ? 's' : 'u'); - f << "<" << cell->getParam(ID::Y_WIDTH).as_int() << ">("; - dump_sigspec_rhs(cell->getPort(ID::A), for_debug); - f << ")"; - // Binary cells - } else if (is_binary_cell(cell->type)) { - f << cell->type.substr(1); - if (is_extending_cell(cell->type)) - f << '_' << (cell->getParam(ID::A_SIGNED).as_bool() ? 's' : 'u') << - (cell->getParam(ID::B_SIGNED).as_bool() ? 's' : 'u'); - f << "<" << cell->getParam(ID::Y_WIDTH).as_int() << ">("; - dump_sigspec_rhs(cell->getPort(ID::A), for_debug); - f << ", "; - dump_sigspec_rhs(cell->getPort(ID::B), for_debug); - f << ")"; - // Muxes - } else if (cell->type == ID($mux)) { - f << "("; - dump_sigspec_rhs(cell->getPort(ID::S), for_debug); - f << " ? "; - dump_sigspec_rhs(cell->getPort(ID::B), for_debug); - f << " : "; - dump_sigspec_rhs(cell->getPort(ID::A), for_debug); - f << ")"; - // Parallel (one-hot) muxes - } else if (cell->type == ID($pmux)) { - int width = cell->getParam(ID::WIDTH).as_int(); - int s_width = cell->getParam(ID::S_WIDTH).as_int(); - for (int part = 0; part < s_width; part++) { - f << "("; - dump_sigspec_rhs(cell->getPort(ID::S).extract(part), for_debug); - f << " ? "; - dump_sigspec_rhs(cell->getPort(ID::B).extract(part * width, width), for_debug); - f << " : "; - } - dump_sigspec_rhs(cell->getPort(ID::A), for_debug); - for (int part = 0; part < s_width; part++) { - f << ")"; - } - // Big muxes - } else if (cell->type == ID($bmux)) { - dump_sigspec_rhs(cell->getPort(ID::A), for_debug); - f << ".bmux<"; - f << cell->getParam(ID::WIDTH).as_int(); - f << ">("; - dump_sigspec_rhs(cell->getPort(ID::S), for_debug); - f << ").val()"; - // Demuxes - } else if (cell->type == ID($demux)) { - dump_sigspec_rhs(cell->getPort(ID::A), for_debug); - f << ".demux<"; - f << GetSize(cell->getPort(ID::Y)); - f << ">("; - dump_sigspec_rhs(cell->getPort(ID::S), for_debug); - f << ").val()"; - // Concats - } else if (cell->type == ID($concat)) { - dump_sigspec_rhs(cell->getPort(ID::B), for_debug); - f << ".concat("; - dump_sigspec_rhs(cell->getPort(ID::A), for_debug); - f << ").val()"; - // Slices - } else if (cell->type == ID($slice)) { - dump_sigspec_rhs(cell->getPort(ID::A), for_debug); - f << ".slice<"; - f << cell->getParam(ID::OFFSET).as_int() + cell->getParam(ID::Y_WIDTH).as_int() - 1; - f << ","; - f << cell->getParam(ID::OFFSET).as_int(); - f << ">().val()"; - } else { - log_assert(false); - } - } - - void dump_cell_eval(const RTLIL::Cell *cell, bool for_debug = false) - { - std::vector inlined_cells; - collect_cell_eval(cell, for_debug, inlined_cells); - dump_inlined_cells(inlined_cells); - - // Elidable cells - if (is_inlinable_cell(cell->type)) { - f << indent; - dump_sigspec_lhs(cell->getPort(ID::Y), for_debug); - f << " = "; - dump_cell_expr(cell, for_debug); - f << ";\n"; - // Flip-flops - } else if (is_ff_cell(cell->type)) { - log_assert(!for_debug); - // Clocks might be slices of larger signals but should only ever be single bit - if (cell->hasPort(ID::CLK) && is_valid_clock(cell->getPort(ID::CLK))) { - // Edge-sensitive logic - RTLIL::SigBit clk_bit = cell->getPort(ID::CLK)[0]; - clk_bit = sigmaps[clk_bit.wire->module](clk_bit); - if (clk_bit.wire) { - f << indent << "if (" << (cell->getParam(ID::CLK_POLARITY).as_bool() ? "posedge_" : "negedge_") - << mangle(clk_bit) << ") {\n"; - } else { - f << indent << "if (false) {\n"; - } - inc_indent(); - if (cell->hasPort(ID::EN)) { - f << indent << "if ("; - dump_sigspec_rhs(cell->getPort(ID::EN)); - f << " == value<1> {" << cell->getParam(ID::EN_POLARITY).as_bool() << "u}) {\n"; - inc_indent(); - } - f << indent; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << " = "; - dump_sigspec_rhs(cell->getPort(ID::D)); - f << ";\n"; - if (cell->hasPort(ID::EN) && cell->type != ID($sdffce)) { - dec_indent(); - f << indent << "}\n"; - } - if (cell->hasPort(ID::SRST)) { - f << indent << "if ("; - dump_sigspec_rhs(cell->getPort(ID::SRST)); - f << " == value<1> {" << cell->getParam(ID::SRST_POLARITY).as_bool() << "u}) {\n"; - inc_indent(); - f << indent; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << " = "; - dump_const(cell->getParam(ID::SRST_VALUE)); - f << ";\n"; - dec_indent(); - f << indent << "}\n"; - } - if (cell->hasPort(ID::EN) && cell->type == ID($sdffce)) { - dec_indent(); - f << indent << "}\n"; - } - dec_indent(); - f << indent << "}\n"; - } else if (cell->hasPort(ID::EN)) { - // Level-sensitive logic - f << indent << "if ("; - dump_sigspec_rhs(cell->getPort(ID::EN)); - f << " == value<1> {" << cell->getParam(ID::EN_POLARITY).as_bool() << "u}) {\n"; - inc_indent(); - f << indent; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << " = "; - dump_sigspec_rhs(cell->getPort(ID::D)); - f << ";\n"; - dec_indent(); - f << indent << "}\n"; - } - if (cell->hasPort(ID::ARST)) { - // Asynchronous reset (entire coarse cell at once) - f << indent << "if ("; - dump_sigspec_rhs(cell->getPort(ID::ARST)); - f << " == value<1> {" << cell->getParam(ID::ARST_POLARITY).as_bool() << "u}) {\n"; - inc_indent(); - f << indent; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << " = "; - dump_const(cell->getParam(ID::ARST_VALUE)); - f << ";\n"; - dec_indent(); - f << indent << "}\n"; - } - if (cell->hasPort(ID::ALOAD)) { - // Asynchronous load - f << indent << "if ("; - dump_sigspec_rhs(cell->getPort(ID::ALOAD)); - f << " == value<1> {" << cell->getParam(ID::ALOAD_POLARITY).as_bool() << "u}) {\n"; - inc_indent(); - f << indent; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << " = "; - dump_sigspec_rhs(cell->getPort(ID::AD)); - f << ";\n"; - dec_indent(); - f << indent << "}\n"; - } - if (cell->hasPort(ID::SET)) { - // Asynchronous set (for individual bits) - f << indent; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << " = "; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << ".update("; - dump_const(RTLIL::Const(RTLIL::S1, cell->getParam(ID::WIDTH).as_int())); - f << ", "; - dump_sigspec_rhs(cell->getPort(ID::SET)); - f << (cell->getParam(ID::SET_POLARITY).as_bool() ? "" : ".bit_not()") << ");\n"; - } - if (cell->hasPort(ID::CLR)) { - // Asynchronous clear (for individual bits; priority over set) - f << indent; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << " = "; - dump_sigspec_lhs(cell->getPort(ID::Q)); - f << ".update("; - dump_const(RTLIL::Const(RTLIL::S0, cell->getParam(ID::WIDTH).as_int())); - f << ", "; - dump_sigspec_rhs(cell->getPort(ID::CLR)); - f << (cell->getParam(ID::CLR_POLARITY).as_bool() ? "" : ".bit_not()") << ");\n"; - } - // Internal cells - } else if (is_internal_cell(cell->type)) { - log_cmd_error("Unsupported internal cell `%s'.\n", cell->type.c_str()); - // User cells - } else { - log_assert(!for_debug); - log_assert(cell->known()); - bool buffered_inputs = false; - const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : "."; - for (auto conn : cell->connections()) - if (cell->input(conn.first)) { - RTLIL::Module *cell_module = cell->module->design->module(cell->type); - log_assert(cell_module != nullptr && cell_module->wire(conn.first)); - RTLIL::Wire *cell_module_wire = cell_module->wire(conn.first); - f << indent << mangle(cell) << access << mangle_wire_name(conn.first); - if (!is_cxxrtl_blackbox_cell(cell) && wire_types[cell_module_wire].is_buffered()) { - buffered_inputs = true; - f << ".next"; - } - f << " = "; - dump_sigspec_rhs(conn.second); - f << ";\n"; - if (getenv("CXXRTL_VOID_MY_WARRANTY") && conn.second.is_wire()) { - // Until we have proper clock tree detection, this really awful hack that opportunistically - // propagates prev_* values for clocks can be used to estimate how much faster a design could - // be if only one clock edge was simulated by replacing: - // top.p_clk = value<1>{0u}; top.step(); - // top.p_clk = value<1>{1u}; top.step(); - // with: - // top.prev_p_clk = value<1>{0u}; top.p_clk = value<1>{1u}; top.step(); - // Don't rely on this; it will be removed without warning. - if (edge_wires[conn.second.as_wire()] && edge_wires[cell_module_wire]) { - f << indent << mangle(cell) << access << "prev_" << mangle(cell_module_wire) << " = "; - f << "prev_" << mangle(conn.second.as_wire()) << ";\n"; - } - } - } - auto assign_from_outputs = [&](bool cell_converged) { - for (auto conn : cell->connections()) { - if (cell->output(conn.first)) { - if (conn.second.empty()) - continue; // ignore disconnected ports - if (is_cxxrtl_sync_port(cell, conn.first)) - continue; // fully sync ports are handled in CELL_SYNC nodes - f << indent; - dump_sigspec_lhs(conn.second); - f << " = " << mangle(cell) << access << mangle_wire_name(conn.first); - // Similarly to how there is no purpose to buffering cell inputs, there is also no purpose to buffering - // combinatorial cell outputs in case the cell converges within one cycle. (To convince yourself that - // this optimization is valid, consider that, since the cell converged within one cycle, it would not - // have any buffered wires if they were not output ports. Imagine inlining the cell's eval() function, - // and consider the fate of the localized wires that used to be output ports.) - // - // It is not possible to know apriori whether the cell (which may be late bound) will converge immediately. - // Because of this, the choice between using .curr (appropriate for buffered outputs) and .next (appropriate - // for unbuffered outputs) is made at runtime. - if (cell_converged && is_cxxrtl_comb_port(cell, conn.first)) - f << ".next;\n"; - else - f << ".curr;\n"; - } - } - }; - if (buffered_inputs) { - // If we have any buffered inputs, there's no chance of converging immediately. - f << indent << mangle(cell) << access << "eval();\n"; - f << indent << "converged = false;\n"; - assign_from_outputs(/*cell_converged=*/false); - } else { - f << indent << "if (" << mangle(cell) << access << "eval()) {\n"; - inc_indent(); - assign_from_outputs(/*cell_converged=*/true); - dec_indent(); - f << indent << "} else {\n"; - inc_indent(); - f << indent << "converged = false;\n"; - assign_from_outputs(/*cell_converged=*/false); - dec_indent(); - f << indent << "}\n"; - } - } - } - - void collect_cell_eval(const RTLIL::Cell *cell, bool for_debug, std::vector &cells) - { - cells.push_back(cell); - for (auto port : cell->connections()) - if (cell->input(port.first)) - collect_sigspec_rhs(port.second, for_debug, cells); - } - - void dump_assign(const RTLIL::SigSig &sigsig, bool for_debug = false) - { - f << indent; - dump_sigspec_lhs(sigsig.first, for_debug); - f << " = "; - dump_sigspec_rhs(sigsig.second, for_debug); - f << ";\n"; - } - - void dump_case_rule(const RTLIL::CaseRule *rule, bool for_debug = false) - { - for (auto action : rule->actions) - dump_assign(action, for_debug); - for (auto switch_ : rule->switches) - dump_switch_rule(switch_, for_debug); - } - - void dump_switch_rule(const RTLIL::SwitchRule *rule, bool for_debug = false) - { - // The switch attributes are printed before the switch condition is captured. - dump_attrs(rule); - std::string signal_temp = fresh_temporary(); - f << indent << "const value<" << rule->signal.size() << "> &" << signal_temp << " = "; - dump_sigspec(rule->signal, /*is_lhs=*/false, for_debug); - f << ";\n"; - - bool first = true; - for (auto case_ : rule->cases) { - // The case attributes (for nested cases) are printed before the if/else if/else statement. - dump_attrs(rule); - f << indent; - if (!first) - f << "} else "; - first = false; - if (!case_->compare.empty()) { - f << "if ("; - bool first = true; - for (auto &compare : case_->compare) { - if (!first) - f << " || "; - first = false; - if (compare.is_fully_def()) { - f << signal_temp << " == "; - dump_sigspec(compare, /*is_lhs=*/false, for_debug); - } else if (compare.is_fully_const()) { - RTLIL::Const compare_mask, compare_value; - for (auto bit : compare.as_const()) { - switch (bit) { - case RTLIL::S0: - case RTLIL::S1: - compare_mask.bits.push_back(RTLIL::S1); - compare_value.bits.push_back(bit); - break; - - case RTLIL::Sx: - case RTLIL::Sz: - case RTLIL::Sa: - compare_mask.bits.push_back(RTLIL::S0); - compare_value.bits.push_back(RTLIL::S0); - break; - - default: - log_assert(false); - } - } - f << "and_uu<" << compare.size() << ">(" << signal_temp << ", "; - dump_const(compare_mask); - f << ") == "; - dump_const(compare_value); - } else { - log_assert(false); - } - } - f << ") "; - } - f << "{\n"; - inc_indent(); - dump_case_rule(case_, for_debug); - dec_indent(); - } - f << indent << "}\n"; - } - - void dump_process_case(const RTLIL::Process *proc, bool for_debug = false) - { - dump_attrs(proc); - f << indent << "// process " << proc->name.str() << " case\n"; - // The case attributes (for root case) are always empty. - log_assert(proc->root_case.attributes.empty()); - dump_case_rule(&proc->root_case, for_debug); - } - - void dump_process_syncs(const RTLIL::Process *proc, bool for_debug = false) - { - dump_attrs(proc); - f << indent << "// process " << proc->name.str() << " syncs\n"; - for (auto sync : proc->syncs) { - log_assert(!for_debug || sync->type == RTLIL::STa); - - RTLIL::SigBit sync_bit; - if (!sync->signal.empty()) { - sync_bit = sync->signal[0]; - sync_bit = sigmaps[sync_bit.wire->module](sync_bit); - if (!sync_bit.is_wire()) - continue; // a clock, or more commonly a reset, can be tied to a constant driver - } - - pool events; - switch (sync->type) { - case RTLIL::STp: - log_assert(sync_bit.wire != nullptr); - events.insert("posedge_" + mangle(sync_bit)); - break; - case RTLIL::STn: - log_assert(sync_bit.wire != nullptr); - events.insert("negedge_" + mangle(sync_bit)); - break; - case RTLIL::STe: - log_assert(sync_bit.wire != nullptr); - events.insert("posedge_" + mangle(sync_bit)); - events.insert("negedge_" + mangle(sync_bit)); - break; - - case RTLIL::STa: - events.insert("true"); - break; - - case RTLIL::ST0: - case RTLIL::ST1: - case RTLIL::STg: - case RTLIL::STi: - log_assert(false); - } - if (!events.empty()) { - f << indent << "if ("; - bool first = true; - for (auto &event : events) { - if (!first) - f << " || "; - first = false; - f << event; - } - f << ") {\n"; - inc_indent(); - for (auto &action : sync->actions) - dump_assign(action, for_debug); - for (auto &memwr : sync->mem_write_actions) { - RTLIL::Memory *memory = proc->module->memories.at(memwr.memid); - std::string valid_index_temp = fresh_temporary(); - f << indent << "auto " << valid_index_temp << " = memory_index("; - dump_sigspec_rhs(memwr.address); - f << ", " << memory->start_offset << ", " << memory->size << ");\n"; - // See below for rationale of having both the assert and the condition. - // - // If assertions are disabled, out of bounds writes are defined to do nothing. - f << indent << "CXXRTL_ASSERT(" << valid_index_temp << ".valid && \"out of bounds write\");\n"; - f << indent << "if (" << valid_index_temp << ".valid) {\n"; - inc_indent(); - f << indent << mangle(memory) << ".update(" << valid_index_temp << ".index, "; - dump_sigspec_rhs(memwr.data); - f << ", "; - dump_sigspec_rhs(memwr.enable); - f << ");\n"; - dec_indent(); - f << indent << "}\n"; - } - dec_indent(); - f << indent << "}\n"; - } - } - } - - void dump_mem_rdport(const Mem *mem, int portidx, bool for_debug = false) - { - auto &port = mem->rd_ports[portidx]; - dump_attrs(&port); - f << indent << "// memory " << mem->memid.str() << " read port " << portidx << "\n"; - if (port.clk_enable) { - log_assert(!for_debug); - RTLIL::SigBit clk_bit = port.clk[0]; - clk_bit = sigmaps[clk_bit.wire->module](clk_bit); - if (clk_bit.wire) { - f << indent << "if (" << (port.clk_polarity ? "posedge_" : "negedge_") - << mangle(clk_bit) << ") {\n"; - } else { - f << indent << "if (false) {\n"; - } - inc_indent(); - } - std::vector inlined_cells_addr; - collect_sigspec_rhs(port.addr, for_debug, inlined_cells_addr); - if (!inlined_cells_addr.empty()) - dump_inlined_cells(inlined_cells_addr); - std::string valid_index_temp = fresh_temporary(); - f << indent << "auto " << valid_index_temp << " = memory_index("; - // Almost all non-elidable cells cannot appear in debug_eval(), but $memrd is an exception; asynchronous - // memory read ports can. - dump_sigspec_rhs(port.addr, for_debug); - f << ", " << mem->start_offset << ", " << mem->size << ");\n"; - bool has_enable = port.clk_enable && !port.en.is_fully_ones(); - if (has_enable) { - std::vector inlined_cells_en; - collect_sigspec_rhs(port.en, for_debug, inlined_cells_en); - if (!inlined_cells_en.empty()) - dump_inlined_cells(inlined_cells_en); - f << indent << "if ("; - dump_sigspec_rhs(port.en); - f << ") {\n"; - inc_indent(); - } - // The generated code has two bounds checks; one in an assertion, and another that guards the read. - // This is done so that the code does not invoke undefined behavior under any conditions, but nevertheless - // loudly crashes if an illegal condition is encountered. The assert may be turned off with -DCXXRTL_NDEBUG - // not only for release builds, but also to make sure the simulator (which is presumably embedded in some - // larger program) will never crash the code that calls into it. - // - // If assertions are disabled, out of bounds reads are defined to return zero. - f << indent << "CXXRTL_ASSERT(" << valid_index_temp << ".valid && \"out of bounds read\");\n"; - f << indent << "if(" << valid_index_temp << ".valid) {\n"; - inc_indent(); - if (!mem->wr_ports.empty()) { - std::string lhs_temp = fresh_temporary(); - f << indent << "value<" << mem->width << "> " << lhs_temp << " = " - << mangle(mem) << "[" << valid_index_temp << ".index];\n"; - bool transparent = false; - for (auto bit : port.transparency_mask) - if (bit) - transparent = true; - if (transparent) { - std::string addr_temp = fresh_temporary(); - f << indent << "const value<" << port.addr.size() << "> &" << addr_temp << " = "; - dump_sigspec_rhs(port.addr); - f << ";\n"; - for (int i = 0; i < GetSize(mem->wr_ports); i++) { - auto &wrport = mem->wr_ports[i]; - if (!port.transparency_mask[i]) - continue; - f << indent << "if (" << addr_temp << " == "; - dump_sigspec_rhs(wrport.addr); - f << ") {\n"; - inc_indent(); - f << indent << lhs_temp << " = " << lhs_temp; - f << ".update("; - dump_sigspec_rhs(wrport.data); - f << ", "; - dump_sigspec_rhs(wrport.en); - f << ");\n"; - dec_indent(); - f << indent << "}\n"; - } - } - f << indent; - dump_sigspec_lhs(port.data); - f << " = " << lhs_temp << ";\n"; - } else { - f << indent; - dump_sigspec_lhs(port.data); - f << " = " << mangle(mem) << "[" << valid_index_temp << ".index];\n"; - } - dec_indent(); - f << indent << "} else {\n"; - inc_indent(); - f << indent; - dump_sigspec_lhs(port.data); - f << " = value<" << mem->width << "> {};\n"; - dec_indent(); - f << indent << "}\n"; - if (has_enable && !port.ce_over_srst) { - dec_indent(); - f << indent << "}\n"; - } - if (port.srst != State::S0) { - // Synchronous reset - std::vector inlined_cells_srst; - collect_sigspec_rhs(port.srst, for_debug, inlined_cells_srst); - if (!inlined_cells_srst.empty()) - dump_inlined_cells(inlined_cells_srst); - f << indent << "if ("; - dump_sigspec_rhs(port.srst); - f << " == value<1> {1u}) {\n"; - inc_indent(); - f << indent; - dump_sigspec_lhs(port.data); - f << " = "; - dump_const(port.srst_value); - f << ";\n"; - dec_indent(); - f << indent << "}\n"; - } - if (has_enable && port.ce_over_srst) { - dec_indent(); - f << indent << "}\n"; - } - if (port.clk_enable) { - dec_indent(); - f << indent << "}\n"; - } - if (port.arst != State::S0) { - // Asynchronous reset - std::vector inlined_cells_arst; - collect_sigspec_rhs(port.arst, for_debug, inlined_cells_arst); - if (!inlined_cells_arst.empty()) - dump_inlined_cells(inlined_cells_arst); - f << indent << "if ("; - dump_sigspec_rhs(port.arst); - f << " == value<1> {1u}) {\n"; - inc_indent(); - f << indent; - dump_sigspec_lhs(port.data); - f << " = "; - dump_const(port.arst_value); - f << ";\n"; - dec_indent(); - f << indent << "}\n"; - } - } - - void dump_mem_wrports(const Mem *mem, bool for_debug = false) - { - log_assert(!for_debug); - for (int portidx = 0; portidx < GetSize(mem->wr_ports); portidx++) { - auto &port = mem->wr_ports[portidx]; - dump_attrs(&port); - f << indent << "// memory " << mem->memid.str() << " write port " << portidx << "\n"; - if (port.clk_enable) { - RTLIL::SigBit clk_bit = port.clk[0]; - clk_bit = sigmaps[clk_bit.wire->module](clk_bit); - if (clk_bit.wire) { - f << indent << "if (" << (port.clk_polarity ? "posedge_" : "negedge_") - << mangle(clk_bit) << ") {\n"; - } else { - f << indent << "if (false) {\n"; - } - inc_indent(); - } - std::vector inlined_cells_addr; - collect_sigspec_rhs(port.addr, for_debug, inlined_cells_addr); - if (!inlined_cells_addr.empty()) - dump_inlined_cells(inlined_cells_addr); - std::string valid_index_temp = fresh_temporary(); - f << indent << "auto " << valid_index_temp << " = memory_index("; - dump_sigspec_rhs(port.addr); - f << ", " << mem->start_offset << ", " << mem->size << ");\n"; - // See above for rationale of having both the assert and the condition. - // - // If assertions are disabled, out of bounds writes are defined to do nothing. - f << indent << "CXXRTL_ASSERT(" << valid_index_temp << ".valid && \"out of bounds write\");\n"; - f << indent << "if (" << valid_index_temp << ".valid) {\n"; - inc_indent(); - std::vector inlined_cells; - collect_sigspec_rhs(port.data, for_debug, inlined_cells); - collect_sigspec_rhs(port.en, for_debug, inlined_cells); - if (!inlined_cells.empty()) - dump_inlined_cells(inlined_cells); - f << indent << mangle(mem) << ".update(" << valid_index_temp << ".index, "; - dump_sigspec_rhs(port.data); - f << ", "; - dump_sigspec_rhs(port.en); - f << ", " << portidx << ");\n"; - dec_indent(); - f << indent << "}\n"; - if (port.clk_enable) { - dec_indent(); - f << indent << "}\n"; - } - } - } - - void dump_wire(const RTLIL::Wire *wire, bool is_local) - { - const auto &wire_type = wire_types[wire]; - if (!wire_type.is_named() || wire_type.is_local() != is_local) - return; - - dump_attrs(wire); - f << indent; - if (wire->port_input && wire->port_output) - f << "/*inout*/ "; - else if (wire->port_input) - f << "/*input*/ "; - else if (wire->port_output) - f << "/*output*/ "; - f << (wire_type.is_buffered() ? "wire" : "value"); - if (wire->module->has_attribute(ID(cxxrtl_blackbox)) && wire->has_attribute(ID(cxxrtl_width))) { - f << "<" << wire->get_string_attribute(ID(cxxrtl_width)) << ">"; - } else { - f << "<" << wire->width << ">"; - } - f << " " << mangle(wire) << ";\n"; - if (edge_wires[wire]) { - if (!wire_type.is_buffered()) { - f << indent << "value<" << wire->width << "> prev_" << mangle(wire) << ";\n"; - } - for (auto edge_type : edge_types) { - if (edge_type.first.wire == wire) { - std::string prev, next; - if (!wire_type.is_buffered()) { - prev = "prev_" + mangle(edge_type.first.wire); - next = mangle(edge_type.first.wire); - } else { - prev = mangle(edge_type.first.wire) + ".curr"; - next = mangle(edge_type.first.wire) + ".next"; - } - prev += ".slice<" + std::to_string(edge_type.first.offset) + ">().val()"; - next += ".slice<" + std::to_string(edge_type.first.offset) + ">().val()"; - if (edge_type.second != RTLIL::STn) { - f << indent << "bool posedge_" << mangle(edge_type.first) << "() const {\n"; - inc_indent(); - f << indent << "return !" << prev << " && " << next << ";\n"; - dec_indent(); - f << indent << "}\n"; - } - if (edge_type.second != RTLIL::STp) { - f << indent << "bool negedge_" << mangle(edge_type.first) << "() const {\n"; - inc_indent(); - f << indent << "return " << prev << " && !" << next << ";\n"; - dec_indent(); - f << indent << "}\n"; - } - } - } - } - } - - void dump_debug_wire(const RTLIL::Wire *wire, bool is_local) - { - const auto &wire_type = wire_types[wire]; - if (wire_type.is_member()) - return; - - const auto &debug_wire_type = debug_wire_types[wire]; - if (!debug_wire_type.is_named() || debug_wire_type.is_local() != is_local) - return; - - dump_attrs(wire); - f << indent; - if (debug_wire_type.is_outline()) - f << "/*outline*/ "; - f << "value<" << wire->width << "> " << mangle(wire) << ";\n"; - } - - void dump_reset_method(RTLIL::Module *module) - { - int mem_init_idx = 0; - inc_indent(); - for (auto wire : module->wires()) { - const auto &wire_type = wire_types[wire]; - if (!wire_type.is_named() || wire_type.is_local()) continue; - if (!wire_init.count(wire)) continue; - - f << indent << mangle(wire) << " = "; - if (wire_types[wire].is_buffered()) { - f << "wire<" << wire->width << ">"; - } else { - f << "value<" << wire->width << ">"; - } - dump_const_init(wire_init.at(wire), wire->width); - f << ";\n"; - - if (edge_wires[wire] && !wire_types[wire].is_buffered()) { - f << indent << "prev_" << mangle(wire) << " = "; - dump_const(wire_init.at(wire), wire->width); - f << ";\n"; - } - } - for (auto &mem : mod_memories[module]) { - for (auto &init : mem.inits) { - if (init.removed) - continue; - dump_attrs(&init); - int words = GetSize(init.data) / mem.width; - f << indent << "static const value<" << mem.width << "> "; - f << "mem_init_" << ++mem_init_idx << "[" << words << "] {"; - inc_indent(); - for (int n = 0; n < words; n++) { - if (n % 4 == 0) - f << "\n" << indent; - else - f << " "; - dump_const(init.data, mem.width, n * mem.width, /*fixed_width=*/true); - f << ","; - } - dec_indent(); - f << "\n"; - f << indent << "};\n"; - f << indent << "std::copy(std::begin(mem_init_" << mem_init_idx << "), "; - f << "std::end(mem_init_" << mem_init_idx << "), "; - f << "&" << mangle(&mem) << ".data[" << stringf("%#x", init.addr.as_int()) << "]);\n"; - } - } - for (auto cell : module->cells()) { - if (is_internal_cell(cell->type)) - continue; - f << indent << mangle(cell); - RTLIL::Module *cell_module = module->design->module(cell->type); - if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) { - f << "->reset();\n"; - } else { - f << ".reset();\n"; - } - } - dec_indent(); - } - - void dump_eval_method(RTLIL::Module *module) - { - inc_indent(); - f << indent << "bool converged = " << (eval_converges.at(module) ? "true" : "false") << ";\n"; - if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { - for (auto wire : module->wires()) { - if (edge_wires[wire]) { - for (auto edge_type : edge_types) { - if (edge_type.first.wire == wire) { - if (edge_type.second != RTLIL::STn) { - f << indent << "bool posedge_" << mangle(edge_type.first) << " = "; - f << "this->posedge_" << mangle(edge_type.first) << "();\n"; - } - if (edge_type.second != RTLIL::STp) { - f << indent << "bool negedge_" << mangle(edge_type.first) << " = "; - f << "this->negedge_" << mangle(edge_type.first) << "();\n"; - } - } - } - } - } - for (auto wire : module->wires()) - dump_wire(wire, /*is_local=*/true); - for (auto node : schedule[module]) { - switch (node.type) { - case FlowGraph::Node::Type::CONNECT: - dump_connect(node.connect); - break; - case FlowGraph::Node::Type::CELL_SYNC: - dump_cell_sync(node.cell); - break; - case FlowGraph::Node::Type::CELL_EVAL: - dump_cell_eval(node.cell); - break; - case FlowGraph::Node::Type::PROCESS_CASE: - dump_process_case(node.process); - break; - case FlowGraph::Node::Type::PROCESS_SYNC: - dump_process_syncs(node.process); - break; - case FlowGraph::Node::Type::MEM_RDPORT: - dump_mem_rdport(node.mem, node.portidx); - break; - case FlowGraph::Node::Type::MEM_WRPORTS: - dump_mem_wrports(node.mem); - break; - } - } - } - f << indent << "return converged;\n"; - dec_indent(); - } - - void dump_debug_eval_method(RTLIL::Module *module) - { - inc_indent(); - for (auto wire : module->wires()) - dump_debug_wire(wire, /*is_local=*/true); - for (auto node : debug_schedule[module]) { - switch (node.type) { - case FlowGraph::Node::Type::CONNECT: - dump_connect(node.connect, /*for_debug=*/true); - break; - case FlowGraph::Node::Type::CELL_SYNC: - dump_cell_sync(node.cell, /*for_debug=*/true); - break; - case FlowGraph::Node::Type::CELL_EVAL: - dump_cell_eval(node.cell, /*for_debug=*/true); - break; - case FlowGraph::Node::Type::PROCESS_CASE: - dump_process_case(node.process, /*for_debug=*/true); - break; - case FlowGraph::Node::Type::PROCESS_SYNC: - dump_process_syncs(node.process, /*for_debug=*/true); - break; - case FlowGraph::Node::Type::MEM_RDPORT: - dump_mem_rdport(node.mem, node.portidx, /*for_debug=*/true); - break; - case FlowGraph::Node::Type::MEM_WRPORTS: - dump_mem_wrports(node.mem, /*for_debug=*/true); - break; - default: - log_abort(); - } - } - dec_indent(); - } - - void dump_commit_method(RTLIL::Module *module) - { - inc_indent(); - f << indent << "bool changed = false;\n"; - for (auto wire : module->wires()) { - const auto &wire_type = wire_types[wire]; - if (wire_type.type == WireType::MEMBER && edge_wires[wire]) - f << indent << "prev_" << mangle(wire) << " = " << mangle(wire) << ";\n"; - if (wire_type.is_buffered()) - f << indent << "if (" << mangle(wire) << ".commit()) changed = true;\n"; - } - if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { - for (auto &mem : mod_memories[module]) { - if (!writable_memories.count({module, mem.memid})) - continue; - f << indent << "if (" << mangle(&mem) << ".commit()) changed = true;\n"; - } - for (auto cell : module->cells()) { - if (is_internal_cell(cell->type)) - continue; - const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : "."; - f << indent << "if (" << mangle(cell) << access << "commit()) changed = true;\n"; - } - } - f << indent << "return changed;\n"; - dec_indent(); - } - - void dump_debug_info_method(RTLIL::Module *module) - { - size_t count_public_wires = 0; - size_t count_member_wires = 0; - size_t count_undriven = 0; - size_t count_driven_sync = 0; - size_t count_driven_comb = 0; - size_t count_mixed_driver = 0; - size_t count_alias_wires = 0; - size_t count_const_wires = 0; - size_t count_inline_wires = 0; - size_t count_skipped_wires = 0; - inc_indent(); - f << indent << "assert(path.empty() || path[path.size() - 1] == ' ');\n"; - for (auto wire : module->wires()) { - const auto &debug_wire_type = debug_wire_types[wire]; - if (!wire->name.isPublic()) - continue; - count_public_wires++; - switch (debug_wire_type.type) { - case WireType::BUFFERED: - case WireType::MEMBER: { - // Member wire - std::vector flags; - - if (wire->port_input && wire->port_output) - flags.push_back("INOUT"); - else if (wire->port_output) - flags.push_back("OUTPUT"); - else if (wire->port_input) - flags.push_back("INPUT"); - - bool has_driven_sync = false; - bool has_driven_comb = false; - bool has_undriven = false; - if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { - for (auto bit : SigSpec(wire)) - if (!bit_has_state.count(bit)) - has_undriven = true; - else if (bit_has_state[bit]) - has_driven_sync = true; - else - has_driven_comb = true; - } else if (wire->port_output) { - switch (cxxrtl_port_type(module, wire->name)) { - case CxxrtlPortType::SYNC: - has_driven_sync = true; - break; - case CxxrtlPortType::COMB: - has_driven_comb = true; - break; - case CxxrtlPortType::UNKNOWN: - has_driven_sync = has_driven_comb = true; - break; - } - } else { - has_undriven = true; - } - if (has_undriven) - flags.push_back("UNDRIVEN"); - if (!has_driven_sync && !has_driven_comb && has_undriven) - count_undriven++; - if (has_driven_sync) - flags.push_back("DRIVEN_SYNC"); - if (has_driven_sync && !has_driven_comb && !has_undriven) - count_driven_sync++; - if (has_driven_comb) - flags.push_back("DRIVEN_COMB"); - if (!has_driven_sync && has_driven_comb && !has_undriven) - count_driven_comb++; - if (has_driven_sync + has_driven_comb + has_undriven > 1) - count_mixed_driver++; - - f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(" << mangle(wire) << ", " << wire->start_offset; - bool first = true; - for (auto flag : flags) { - if (first) { - first = false; - f << ", "; - } else { - f << "|"; - } - f << "debug_item::" << flag; - } - f << "));\n"; - count_member_wires++; - break; - } - case WireType::ALIAS: { - // Alias of a member wire - const RTLIL::Wire *aliasee = debug_wire_type.sig_subst.as_wire(); - f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item("; - // If the aliasee is an outline, then the alias must be an outline, too; otherwise downstream - // tooling has no way to find out about the outline. - if (debug_wire_types[aliasee].is_outline()) - f << "debug_eval_outline"; - else - f << "debug_alias()"; - f << ", " << mangle(aliasee) << ", " << wire->start_offset << "));\n"; - count_alias_wires++; - break; - } - case WireType::CONST: { - // Wire tied to a constant - f << indent << "static const value<" << wire->width << "> const_" << mangle(wire) << " = "; - dump_const(debug_wire_type.sig_subst.as_const()); - f << ";\n"; - f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "));\n"; - count_const_wires++; - break; - } - case WireType::OUTLINE: { - // Localized or inlined, but rematerializable wire - f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "));\n"; - count_inline_wires++; - break; - } - default: { - // Localized or inlined wire with no debug information - count_skipped_wires++; - break; - } - } - } - if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { - for (auto &mem : mod_memories[module]) { - if (!mem.memid.isPublic()) - continue; - f << indent << "items.add(path + " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem)); - f << ", debug_item(" << mangle(&mem) << ", "; - f << mem.start_offset << "));\n"; - } - for (auto cell : module->cells()) { - if (is_internal_cell(cell->type)) - continue; - const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : "."; - f << indent << mangle(cell) << access << "debug_info(items, "; - f << "path + " << escape_cxx_string(get_hdl_name(cell) + ' ') << ");\n"; - } - } - dec_indent(); - - log_debug("Debug information statistics for module `%s':\n", log_id(module)); - log_debug(" Public wires: %zu, of which:\n", count_public_wires); - log_debug(" Member wires: %zu, of which:\n", count_member_wires); - log_debug(" Undriven: %zu (incl. inputs)\n", count_undriven); - log_debug(" Driven sync: %zu\n", count_driven_sync); - log_debug(" Driven comb: %zu\n", count_driven_comb); - log_debug(" Mixed driver: %zu\n", count_mixed_driver); - if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { - log_debug(" Inline wires: %zu\n", count_inline_wires); - log_debug(" Alias wires: %zu\n", count_alias_wires); - log_debug(" Const wires: %zu\n", count_const_wires); - log_debug(" Other wires: %zu%s\n", count_skipped_wires, - count_skipped_wires > 0 ? " (debug unavailable)" : ""); - } - } - - void dump_metadata_map(const dict &metadata_map) - { - if (metadata_map.empty()) { - f << "metadata_map()"; - return; - } - f << "metadata_map({\n"; - inc_indent(); - for (auto metadata_item : metadata_map) { - if (!metadata_item.first.begins_with("\\")) - continue; - f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", "; - if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) { - f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint; - } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) { - f << escape_cxx_string(metadata_item.second.decode_string()); - } else { - f << metadata_item.second.as_int(/*is_signed=*/metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED); - if (!(metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED)) - f << "u"; - } - f << " },\n"; - } - dec_indent(); - f << indent << "})"; - } - - void dump_module_intf(RTLIL::Module *module) - { - dump_attrs(module); - if (module->get_bool_attribute(ID(cxxrtl_blackbox))) { - if (module->has_attribute(ID(cxxrtl_template))) - f << indent << "template" << template_params(module, /*is_decl=*/true) << "\n"; - f << indent << "struct " << mangle(module) << " : public module {\n"; - inc_indent(); - for (auto wire : module->wires()) { - if (wire->port_id != 0) - dump_wire(wire, /*is_local=*/false); - } - f << "\n"; - f << indent << "void reset() override {\n"; - dump_reset_method(module); - f << indent << "}\n"; - f << "\n"; - f << indent << "bool eval() override {\n"; - dump_eval_method(module); - f << indent << "}\n"; - f << "\n"; - f << indent << "bool commit() override {\n"; - dump_commit_method(module); - f << indent << "}\n"; - f << "\n"; - if (debug_info) { - f << indent << "void debug_info(debug_items &items, std::string path = \"\") override {\n"; - dump_debug_info_method(module); - f << indent << "}\n"; - f << "\n"; - } - f << indent << "static std::unique_ptr<" << mangle(module); - f << template_params(module, /*is_decl=*/false) << "> "; - f << "create(std::string name, metadata_map parameters, metadata_map attributes);\n"; - dec_indent(); - f << indent << "}; // struct " << mangle(module) << "\n"; - f << "\n"; - if (blackbox_specializations.count(module)) { - // If templated black boxes are used, the constructor of any module which includes the black box cell - // (which calls the declared but not defined in the generated code `create` function) may only be used - // if (a) the create function is defined in the same translation unit, or (b) the create function has - // a forward-declared explicit specialization. - // - // Option (b) makes it possible to have the generated code and the black box implementation in different - // translation units, which is convenient. Of course, its downside is that black boxes must predefine - // a specialization for every combination of parameters the generated code may use; but since the main - // purpose of templated black boxes is abstracting over datapath width, it is expected that there would - // be very few such combinations anyway. - for (auto specialization : blackbox_specializations[module]) { - f << indent << "template<>\n"; - f << indent << "std::unique_ptr<" << mangle(module) << specialization << "> "; - f << mangle(module) << specialization << "::"; - f << "create(std::string name, metadata_map parameters, metadata_map attributes);\n"; - f << "\n"; - } - } - } else { - f << indent << "struct " << mangle(module) << " : public module {\n"; - inc_indent(); - for (auto wire : module->wires()) - dump_wire(wire, /*is_local=*/false); - for (auto wire : module->wires()) - dump_debug_wire(wire, /*is_local=*/false); - bool has_memories = false; - for (auto &mem : mod_memories[module]) { - dump_attrs(&mem); - f << indent << "memory<" << mem.width << "> " << mangle(&mem) - << " { " << mem.size << "u };\n"; - has_memories = true; - } - if (has_memories) - f << "\n"; - bool has_cells = false; - for (auto cell : module->cells()) { - if (is_internal_cell(cell->type)) - continue; - dump_attrs(cell); - RTLIL::Module *cell_module = module->design->module(cell->type); - log_assert(cell_module != nullptr); - if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) { - f << indent << "std::unique_ptr<" << mangle(cell_module) << template_args(cell) << "> "; - f << mangle(cell) << " = " << mangle(cell_module) << template_args(cell); - f << "::create(" << escape_cxx_string(get_hdl_name(cell)) << ", "; - dump_metadata_map(cell->parameters); - f << ", "; - dump_metadata_map(cell->attributes); - f << ");\n"; - } else { - f << indent << mangle(cell_module) << " " << mangle(cell) << " {interior()};\n"; - } - has_cells = true; - } - if (has_cells) - f << "\n"; - f << indent << mangle(module) << "(interior) {}\n"; - f << indent << mangle(module) << "() {\n"; - inc_indent(); - f << indent << "reset();\n"; - dec_indent(); - f << indent << "};\n"; - f << "\n"; - f << indent << "void reset() override;\n"; - f << indent << "bool eval() override;\n"; - f << indent << "bool commit() override;\n"; - if (debug_info) { - if (debug_eval) { - f << "\n"; - f << indent << "void debug_eval();\n"; - for (auto wire : module->wires()) - if (debug_wire_types[wire].is_outline()) { - f << indent << "debug_outline debug_eval_outline { std::bind(&" - << mangle(module) << "::debug_eval, this) };\n"; - break; - } - } - f << "\n"; - f << indent << "void debug_info(debug_items &items, std::string path = \"\") override;\n"; - } - dec_indent(); - f << indent << "}; // struct " << mangle(module) << "\n"; - f << "\n"; - } - } - - void dump_module_impl(RTLIL::Module *module) - { - if (module->get_bool_attribute(ID(cxxrtl_blackbox))) - return; - f << indent << "void " << mangle(module) << "::reset() {\n"; - dump_reset_method(module); - f << indent << "}\n"; - f << "\n"; - f << indent << "bool " << mangle(module) << "::eval() {\n"; - dump_eval_method(module); - f << indent << "}\n"; - f << "\n"; - f << indent << "bool " << mangle(module) << "::commit() {\n"; - dump_commit_method(module); - f << indent << "}\n"; - f << "\n"; - if (debug_info) { - if (debug_eval) { - f << indent << "void " << mangle(module) << "::debug_eval() {\n"; - dump_debug_eval_method(module); - f << indent << "}\n"; - f << "\n"; - } - f << indent << "CXXRTL_EXTREMELY_COLD\n"; - f << indent << "void " << mangle(module) << "::debug_info(debug_items &items, std::string path) {\n"; - dump_debug_info_method(module); - f << indent << "}\n"; - f << "\n"; - } - } - - void dump_design(RTLIL::Design *design) - { - RTLIL::Module *top_module = nullptr; - std::vector modules; - TopoSort topo_design; - for (auto module : design->modules()) { - if (!design->selected_module(module)) - continue; - if (module->get_bool_attribute(ID(cxxrtl_blackbox))) - modules.push_back(module); // cxxrtl blackboxes first - if (module->get_blackbox_attribute() || module->get_bool_attribute(ID(cxxrtl_blackbox))) - continue; - if (module->get_bool_attribute(ID::top)) - top_module = module; - - topo_design.node(module); - for (auto cell : module->cells()) { - if (is_internal_cell(cell->type) || is_cxxrtl_blackbox_cell(cell)) - continue; - RTLIL::Module *cell_module = design->module(cell->type); - log_assert(cell_module != nullptr); - topo_design.edge(cell_module, module); - } - } - bool no_loops = topo_design.sort(); - log_assert(no_loops); - modules.insert(modules.end(), topo_design.sorted.begin(), topo_design.sorted.end()); - - if (split_intf) { - // The only thing more depraved than include guards, is mangling filenames to turn them into include guards. - std::string include_guard = design_ns + "_header"; - std::transform(include_guard.begin(), include_guard.end(), include_guard.begin(), ::toupper); - - f << "#ifndef " << include_guard << "\n"; - f << "#define " << include_guard << "\n"; - f << "\n"; - if (top_module != nullptr && debug_info) { - f << "#include \n"; - f << "\n"; - f << "#ifdef __cplusplus\n"; - f << "extern \"C\" {\n"; - f << "#endif\n"; - f << "\n"; - f << "cxxrtl_toplevel " << design_ns << "_create();\n"; - f << "\n"; - f << "#ifdef __cplusplus\n"; - f << "}\n"; - f << "#endif\n"; - f << "\n"; - } else { - f << "// The CXXRTL C API is not available because the design is built without debug information.\n"; - f << "\n"; - } - f << "#ifdef __cplusplus\n"; - f << "\n"; - f << "#include \n"; - f << "\n"; - f << "using namespace cxxrtl;\n"; - f << "\n"; - f << "namespace " << design_ns << " {\n"; - f << "\n"; - for (auto module : modules) - dump_module_intf(module); - f << "} // namespace " << design_ns << "\n"; - f << "\n"; - f << "#endif // __cplusplus\n"; - f << "\n"; - f << "#endif\n"; - *intf_f << f.str(); f.str(""); - } - - if (split_intf) - f << "#include \"" << intf_filename << "\"\n"; - else - f << "#include \n"; - f << "\n"; - f << "#if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \\\n"; - f << " defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)\n"; - f << "#include \n"; - f << "#endif\n"; - f << "\n"; - f << "#if defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)\n"; - f << "#include \n"; - f << "#endif\n"; - f << "\n"; - f << "using namespace cxxrtl_yosys;\n"; - f << "\n"; - f << "namespace " << design_ns << " {\n"; - f << "\n"; - for (auto module : modules) { - if (!split_intf) - dump_module_intf(module); - dump_module_impl(module); - } - f << "} // namespace " << design_ns << "\n"; - f << "\n"; - if (top_module != nullptr && debug_info) { - f << "extern \"C\"\n"; - f << "cxxrtl_toplevel " << design_ns << "_create() {\n"; - inc_indent(); - std::string top_type = design_ns + "::" + mangle(top_module); - f << indent << "return new _cxxrtl_toplevel { "; - f << "std::unique_ptr<" << top_type << ">(new " + top_type + ")"; - f << " };\n"; - dec_indent(); - f << "}\n"; - } - - *impl_f << f.str(); f.str(""); - } - - // Edge-type sync rules require us to emit edge detectors, which require coordination between - // eval and commit phases. To do this we need to collect them upfront. - // - // Note that the simulator commit phase operates at wire granularity but edge-type sync rules - // operate at wire bit granularity; it is possible to have code similar to: - // wire [3:0] clocks; - // always @(posedge clocks[0]) ... - // To handle this we track edge sensitivity both for wires and wire bits. - void register_edge_signal(SigMap &sigmap, RTLIL::SigSpec signal, RTLIL::SyncType type) - { - signal = sigmap(signal); - if (signal.is_fully_const()) - return; // a clock, or more commonly a reset, can be tied to a constant driver - log_assert(is_valid_clock(signal)); - log_assert(type == RTLIL::STp || type == RTLIL::STn || type == RTLIL::STe); - - RTLIL::SigBit sigbit = signal[0]; - if (!edge_types.count(sigbit)) - edge_types[sigbit] = type; - else if (edge_types[sigbit] != type) - edge_types[sigbit] = RTLIL::STe; - // Cannot use as_wire because signal might not be a full wire, instead extract the wire from the sigbit - edge_wires.insert(sigbit.wire); - } - - void analyze_design(RTLIL::Design *design) - { - bool has_feedback_arcs = false; - bool has_buffered_comb_wires = false; - - for (auto module : design->modules()) { - if (!design->selected_module(module)) - continue; - - SigMap &sigmap = sigmaps[module]; - sigmap.set(module); - - std::vector &memories = mod_memories[module]; - memories = Mem::get_all_memories(module); - for (auto &mem : memories) { - mem.narrow(); - mem.coalesce_inits(); - } - - if (module->get_bool_attribute(ID(cxxrtl_blackbox))) { - for (auto port : module->ports) { - RTLIL::Wire *wire = module->wire(port); - if (wire->port_input && !wire->port_output) { - wire_types[wire] = debug_wire_types[wire] = {WireType::MEMBER}; - } else if (wire->port_input || wire->port_output) { - wire_types[wire] = debug_wire_types[wire] = {WireType::BUFFERED}; - } - if (wire->has_attribute(ID(cxxrtl_edge))) { - RTLIL::Const edge_attr = wire->attributes[ID(cxxrtl_edge)]; - if (!(edge_attr.flags & RTLIL::CONST_FLAG_STRING) || (int)edge_attr.decode_string().size() != GetSize(wire)) - log_cmd_error("Attribute `cxxrtl_edge' of port `%s.%s' is not a string with one character per bit.\n", - log_id(module), log_signal(wire)); - - std::string edges = wire->get_string_attribute(ID(cxxrtl_edge)); - for (int i = 0; i < GetSize(wire); i++) { - RTLIL::SigSpec wire_sig = wire; - switch (edges[i]) { - case '-': break; - case 'p': register_edge_signal(sigmap, wire_sig[i], RTLIL::STp); break; - case 'n': register_edge_signal(sigmap, wire_sig[i], RTLIL::STn); break; - case 'a': register_edge_signal(sigmap, wire_sig[i], RTLIL::STe); break; - default: - log_cmd_error("Attribute `cxxrtl_edge' of port `%s.%s' contains specifiers " - "other than '-', 'p', 'n', or 'a'.\n", - log_id(module), log_signal(wire)); - } - } - } - } - - // Black boxes converge by default, since their implementations are quite unlikely to require - // internal propagation of comb signals. - eval_converges[module] = true; - continue; - } - - for (auto wire : module->wires()) - if (wire->has_attribute(ID::init)) - wire_init[wire] = wire->attributes.at(ID::init); - - // Construct a flow graph where each node is a basic computational operation generally corresponding - // to a fragment of the RTLIL netlist. - FlowGraph flow; - - for (auto conn : module->connections()) - flow.add_node(conn); - - for (auto cell : module->cells()) { - if (!cell->known()) - log_cmd_error("Unknown cell `%s'.\n", log_id(cell->type)); - - if (cell->is_mem_cell()) - continue; - - RTLIL::Module *cell_module = design->module(cell->type); - if (cell_module && - cell_module->get_blackbox_attribute() && - !cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) - log_cmd_error("External blackbox cell `%s' is not marked as a CXXRTL blackbox.\n", log_id(cell->type)); - - if (cell_module && - cell_module->get_bool_attribute(ID(cxxrtl_blackbox)) && - cell_module->get_bool_attribute(ID(cxxrtl_template))) - blackbox_specializations[cell_module].insert(template_args(cell)); - - flow.add_node(cell); - - // Various DFF cells are treated like posedge/negedge processes, see above for details. - if (cell->type.in(ID($dff), ID($dffe), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($dffsr), ID($dffsre), ID($sdff), ID($sdffe), ID($sdffce))) { - if (is_valid_clock(cell->getPort(ID::CLK))) - register_edge_signal(sigmap, cell->getPort(ID::CLK), - cell->parameters[ID::CLK_POLARITY].as_bool() ? RTLIL::STp : RTLIL::STn); - } - } - - for (auto &mem : memories) { - flow.add_node(&mem); - - // Clocked memory cells are treated like posedge/negedge processes as well. - for (auto &port : mem.rd_ports) { - if (port.clk_enable) - if (is_valid_clock(port.clk)) - register_edge_signal(sigmap, port.clk, - port.clk_polarity ? RTLIL::STp : RTLIL::STn); - // For read ports, also move initial value to wire_init (if any). - for (int i = 0; i < GetSize(port.data); i++) { - if (port.init_value[i] != State::Sx) { - SigBit bit = port.data[i]; - if (bit.wire) { - auto &init = wire_init[bit.wire]; - if (init == RTLIL::Const()) { - init = RTLIL::Const(State::Sx, GetSize(bit.wire)); - } - init[bit.offset] = port.init_value[i]; - } - } - } - } - for (auto &port : mem.wr_ports) { - if (port.clk_enable) - if (is_valid_clock(port.clk)) - register_edge_signal(sigmap, port.clk, - port.clk_polarity ? RTLIL::STp : RTLIL::STn); - } - - if (!mem.wr_ports.empty()) - writable_memories.insert({module, mem.memid}); - } - - for (auto proc : module->processes) { - flow.add_node(proc.second); - - for (auto sync : proc.second->syncs) { - switch (sync->type) { - // Edge-type sync rules require pre-registration. - case RTLIL::STp: - case RTLIL::STn: - case RTLIL::STe: - register_edge_signal(sigmap, sync->signal, sync->type); - break; - - // Level-type sync rules require no special handling. - case RTLIL::ST0: - case RTLIL::ST1: - case RTLIL::STa: - break; - - case RTLIL::STg: - log_cmd_error("Global clock is not supported.\n"); - - // Handling of init-type sync rules is delegated to the `proc_init` pass, so we can use the wire - // attribute regardless of input. - case RTLIL::STi: - log_assert(false); - } - for (auto &memwr : sync->mem_write_actions) { - writable_memories.insert({module, memwr.memid}); - } - } - } - - // Construct a linear order of the flow graph that minimizes the amount of feedback arcs. A flow graph - // without feedback arcs can generally be evaluated in a single pass, i.e. it always requires only - // a single delta cycle. - Scheduler scheduler; - dict::Vertex*, hash_ptr_ops> node_vertex_map; - for (auto node : flow.nodes) - node_vertex_map[node] = scheduler.add(node); - for (auto node_comb_def : flow.node_comb_defs) { - auto vertex = node_vertex_map[node_comb_def.first]; - for (auto wire : node_comb_def.second) - for (auto succ_node : flow.wire_uses[wire]) { - auto succ_vertex = node_vertex_map[succ_node]; - vertex->succs.insert(succ_vertex); - succ_vertex->preds.insert(vertex); - } - } - - // Find out whether the order includes any feedback arcs. - std::vector node_order; - pool evaluated_nodes; - pool feedback_wires; - for (auto vertex : scheduler.schedule()) { - auto node = vertex->data; - node_order.push_back(node); - // Any wire that is an output of node vo and input of node vi where vo is scheduled later than vi - // is a feedback wire. Feedback wires indicate apparent logic loops in the design, which may be - // caused by a true logic loop, but usually are a benign result of dependency tracking that works - // on wire, not bit, level. Nevertheless, feedback wires cannot be unbuffered. - evaluated_nodes.insert(node); - for (auto wire : flow.node_comb_defs[node]) - for (auto succ_node : flow.wire_uses[wire]) - if (evaluated_nodes[succ_node]) - feedback_wires.insert(wire); - } - if (!feedback_wires.empty()) { - has_feedback_arcs = true; - log("Module `%s' contains feedback arcs through wires:\n", log_id(module)); - for (auto wire : feedback_wires) - log(" %s\n", log_id(wire)); - } - - // Conservatively assign wire types. Assignment of types BUFFERED and MEMBER is final, but assignment - // of type LOCAL may be further refined to UNUSED or INLINE. - for (auto wire : module->wires()) { - auto &wire_type = wire_types[wire]; - wire_type = {WireType::BUFFERED}; - - if (feedback_wires[wire]) continue; - if (wire->port_output && !module->get_bool_attribute(ID::top)) continue; - if (!wire->name.isPublic() && !unbuffer_internal) continue; - if (wire->name.isPublic() && !unbuffer_public) continue; - if (flow.wire_sync_defs.count(wire) > 0) continue; - wire_type = {WireType::MEMBER}; - - if (edge_wires[wire]) continue; - if (wire->get_bool_attribute(ID::keep)) continue; - if (wire->port_input || wire->port_output) continue; - if (!wire->name.isPublic() && !localize_internal) continue; - if (wire->name.isPublic() && !localize_public) continue; - wire_type = {WireType::LOCAL}; - } - - // Discover nodes reachable from primary outputs (i.e. members) and collect reachable wire users. - pool worklist; - for (auto node : flow.nodes) { - if (node->type == FlowGraph::Node::Type::CELL_EVAL && is_effectful_cell(node->cell->type)) - worklist.insert(node); // node has effects - else if (node->type == FlowGraph::Node::Type::MEM_WRPORTS) - worklist.insert(node); // node is memory write - else if (node->type == FlowGraph::Node::Type::PROCESS_SYNC && is_memwr_process(node->process)) - worklist.insert(node); // node is memory write - else if (flow.node_sync_defs.count(node)) - worklist.insert(node); // node is a flip-flop - else if (flow.node_comb_defs.count(node)) { - for (auto wire : flow.node_comb_defs[node]) - if (wire_types[wire].is_member()) - worklist.insert(node); // node drives public wires - } - } - dict> live_wires; - pool live_nodes; - while (!worklist.empty()) { - auto node = worklist.pop(); - live_nodes.insert(node); - for (auto wire : flow.node_uses[node]) { - live_wires[wire].insert(node); - for (auto pred_node : flow.wire_comb_defs[wire]) - if (!live_nodes[pred_node]) - worklist.insert(pred_node); - } - } - - // Refine wire types taking into account the amount of uses from reachable nodes only. - for (auto wire : module->wires()) { - auto &wire_type = wire_types[wire]; - if (!wire_type.is_local()) continue; - if (live_wires[wire].empty()) { - wire_type = {WireType::UNUSED}; // wire never used - continue; - } - - if (!wire->name.isPublic() && !inline_internal) continue; - if (wire->name.isPublic() && !inline_public) continue; - if (flow.is_inlinable(wire, live_wires[wire])) { - if (flow.wire_comb_defs[wire].size() > 1) - log_cmd_error("Wire %s.%s has multiple drivers!\n", log_id(module), log_id(wire)); - log_assert(flow.wire_comb_defs[wire].size() == 1); - FlowGraph::Node *node = *flow.wire_comb_defs[wire].begin(); - switch (node->type) { - case FlowGraph::Node::Type::CELL_EVAL: - if (!is_inlinable_cell(node->cell->type)) continue; - wire_type = {WireType::INLINE, node->cell}; // wire replaced with cell - break; - case FlowGraph::Node::Type::CONNECT: - wire_type = {WireType::INLINE, node->connect.second}; // wire replaced with sig - break; - default: continue; - } - live_nodes.erase(node); - } - } - - // Emit reachable nodes in eval(). - for (auto node : node_order) - if (live_nodes[node]) - schedule[module].push_back(*node); - - // For maximum performance, the state of the simulation (which is the same as the set of its double buffered - // wires, since using a singly buffered wire for any kind of state introduces a race condition) should contain - // no wires attached to combinatorial outputs. Feedback wires, by definition, make that impossible. However, - // it is possible that a design with no feedback arcs would end up with doubly buffered wires in such cases - // as a wire with multiple drivers where one of them is combinatorial and the other is synchronous. Such designs - // also require more than one delta cycle to converge. - pool buffered_comb_wires; - for (auto wire : module->wires()) - if (wire_types[wire].is_buffered() && !feedback_wires[wire] && flow.wire_comb_defs[wire].size() > 0) - buffered_comb_wires.insert(wire); - if (!buffered_comb_wires.empty()) { - has_buffered_comb_wires = true; - log("Module `%s' contains buffered combinatorial wires:\n", log_id(module)); - for (auto wire : buffered_comb_wires) - log(" %s\n", log_id(wire)); - } - - // Record whether eval() requires only one delta cycle in this module. - eval_converges[module] = feedback_wires.empty() && buffered_comb_wires.empty(); - - if (debug_info) { - // Annotate wire bits with the type of their driver; this is exposed in the debug metadata. - for (auto item : flow.bit_has_state) - bit_has_state.insert(item); - - // Assign debug information wire types to public wires according to the chosen debug level. - // Unlike with optimized wire types, all assignments here are final. - for (auto wire : module->wires()) { - const auto &wire_type = wire_types[wire]; - auto &debug_wire_type = debug_wire_types[wire]; - - if (!debug_info) continue; - if (wire->port_input || wire_type.is_buffered()) - debug_wire_type = wire_type; // wire contains state - else if (!wire->name.isPublic()) - continue; // internal and stateless - - if (!debug_member) continue; - if (wire_type.is_member()) - debug_wire_type = wire_type; // wire is a member - - if (!debug_alias) continue; - const RTLIL::Wire *it = wire; - while (flow.is_inlinable(it)) { - log_assert(flow.wire_comb_defs[it].size() == 1); - FlowGraph::Node *node = *flow.wire_comb_defs[it].begin(); - if (node->type != FlowGraph::Node::Type::CONNECT) break; // not an alias - RTLIL::SigSpec rhs = node->connect.second; - if (rhs.is_fully_const()) { - debug_wire_type = {WireType::CONST, rhs}; // wire replaced with const - } else if (rhs.is_wire()) { - if (wire_types[rhs.as_wire()].is_member()) - debug_wire_type = {WireType::ALIAS, rhs}; // wire replaced with wire - else if (debug_eval && rhs.as_wire()->name.isPublic()) - debug_wire_type = {WireType::ALIAS, rhs}; // wire replaced with outline - it = rhs.as_wire(); // and keep looking - continue; - } - break; - } - - if (!debug_eval) continue; - if (!debug_wire_type.is_exact() && !wire_type.is_member()) - debug_wire_type = {WireType::OUTLINE}; // wire is local or inlined - } - - // Discover nodes reachable from primary outputs (i.e. outlines) up until primary inputs (i.e. members) - // and collect reachable wire users. - pool worklist; - for (auto node : flow.nodes) { - if (flow.node_comb_defs.count(node)) - for (auto wire : flow.node_comb_defs[node]) - if (debug_wire_types[wire].is_outline()) - worklist.insert(node); // node drives outline - } - dict> debug_live_wires; - pool debug_live_nodes; - while (!worklist.empty()) { - auto node = worklist.pop(); - debug_live_nodes.insert(node); - for (auto wire : flow.node_uses[node]) { - if (debug_wire_types[wire].is_member()) - continue; // node uses member - if (debug_wire_types[wire].is_exact()) - continue; // node uses alias or const - debug_live_wires[wire].insert(node); - for (auto pred_node : flow.wire_comb_defs[wire]) - if (!debug_live_nodes[pred_node]) - worklist.insert(pred_node); - } - } - - // Assign debug information wire types to internal wires used by reachable nodes. This is similar - // to refining optimized wire types with the exception that the assignments here are first and final. - for (auto wire : module->wires()) { - const auto &wire_type = wire_types[wire]; - auto &debug_wire_type = debug_wire_types[wire]; - if (wire->name.isPublic()) continue; - - if (debug_live_wires[wire].empty()) { - continue; // wire never used - } else if (flow.is_inlinable(wire, debug_live_wires[wire])) { - log_assert(flow.wire_comb_defs[wire].size() == 1); - FlowGraph::Node *node = *flow.wire_comb_defs[wire].begin(); - switch (node->type) { - case FlowGraph::Node::Type::CELL_EVAL: - if (!is_inlinable_cell(node->cell->type)) continue; - debug_wire_type = {WireType::INLINE, node->cell}; // wire replaced with cell - break; - case FlowGraph::Node::Type::CONNECT: - debug_wire_type = {WireType::INLINE, node->connect.second}; // wire replaced with sig - break; - default: continue; - } - debug_live_nodes.erase(node); - } else if (wire_type.is_member() || wire_type.type == WireType::LOCAL) { - debug_wire_type = wire_type; // wire not inlinable - } else { - log_assert(wire_type.type == WireType::INLINE || - wire_type.type == WireType::UNUSED); - if (flow.wire_comb_defs[wire].size() == 0) { - if (wire_init.count(wire)) { // wire never modified - debug_wire_type = {WireType::CONST, wire_init.at(wire)}; - } else { - debug_wire_type = {WireType::CONST, RTLIL::SigSpec(RTLIL::S0, wire->width)}; - } - } else { - debug_wire_type = {WireType::LOCAL}; // wire used only for debug - } - } - } - - // Emit reachable nodes in debug_eval(). - for (auto node : node_order) - if (debug_live_nodes[node]) - debug_schedule[module].push_back(*node); - } - - auto show_wire_type = [&](const RTLIL::Wire* wire, const WireType &wire_type) { - const char *type_str; - switch (wire_type.type) { - case WireType::UNUSED: type_str = "UNUSED"; break; - case WireType::BUFFERED: type_str = "BUFFERED"; break; - case WireType::MEMBER: type_str = "MEMBER"; break; - case WireType::OUTLINE: type_str = "OUTLINE"; break; - case WireType::LOCAL: type_str = "LOCAL"; break; - case WireType::INLINE: type_str = "INLINE"; break; - case WireType::ALIAS: type_str = "ALIAS"; break; - case WireType::CONST: type_str = "CONST"; break; - default: type_str = "(invalid)"; - } - if (wire_type.sig_subst.empty()) - log_debug(" %s: %s\n", log_signal((RTLIL::Wire*)wire), type_str); - else - log_debug(" %s: %s = %s\n", log_signal((RTLIL::Wire*)wire), type_str, log_signal(wire_type.sig_subst)); - }; - if (print_wire_types && !wire_types.empty()) { - log_debug("Wire types:\n"); - for (auto wire_type : wire_types) - show_wire_type(wire_type.first, wire_type.second); - } - if (print_debug_wire_types && !debug_wire_types.empty()) { - log_debug("Debug wire types:\n"); - for (auto debug_wire_type : debug_wire_types) - show_wire_type(debug_wire_type.first, debug_wire_type.second); - } - } - if (has_feedback_arcs || has_buffered_comb_wires) { - // Although both non-feedback buffered combinatorial wires and apparent feedback wires may be eliminated - // by optimizing the design, if after `proc; flatten` there are any feedback wires remaining, it is very - // likely that these feedback wires are indicative of a true logic loop, so they get emphasized in the message. - const char *why_pessimistic = nullptr; - if (has_feedback_arcs) - why_pessimistic = "feedback wires"; - else if (has_buffered_comb_wires) - why_pessimistic = "buffered combinatorial wires"; - log_warning("Design contains %s, which require delta cycles during evaluation.\n", why_pessimistic); - if (!run_flatten) - log("Flattening may eliminate %s from the design.\n", why_pessimistic); - if (!run_proc) - log("Converting processes to netlists may eliminate %s from the design.\n", why_pessimistic); - } - } - - void check_design(RTLIL::Design *design, bool &has_sync_init) - { - has_sync_init = false; - - for (auto module : design->modules()) { - if (module->get_blackbox_attribute() && !module->has_attribute(ID(cxxrtl_blackbox))) - continue; - - if (!design->selected_whole_module(module)) - if (design->selected_module(module)) - log_cmd_error("Can't handle partially selected module `%s'!\n", id2cstr(module->name)); - if (!design->selected_module(module)) - continue; - - for (auto proc : module->processes) - for (auto sync : proc.second->syncs) - if (sync->type == RTLIL::STi) - has_sync_init = true; - } - } - - void prepare_design(RTLIL::Design *design) - { - bool did_anything = false; - bool has_sync_init; - log_push(); - check_design(design, has_sync_init); - if (run_hierarchy) { - Pass::call(design, "hierarchy -auto-top"); - did_anything = true; - } - if (run_flatten) { - Pass::call(design, "flatten"); - did_anything = true; - } - if (run_proc) { - Pass::call(design, "proc"); - did_anything = true; - } else if (has_sync_init) { - // We're only interested in proc_init, but it depends on proc_prune and proc_clean, so call those - // in case they weren't already. (This allows `yosys foo.v -o foo.cc` to work.) - Pass::call(design, "proc_prune"); - Pass::call(design, "proc_clean"); - Pass::call(design, "proc_init"); - did_anything = true; - } - // Recheck the design if it was modified. - if (did_anything) - check_design(design, has_sync_init); - log_assert(!has_sync_init); - log_pop(); - if (did_anything) - log_spacer(); - analyze_design(design); - } -}; - -struct CxxrtlBackend : public Backend { - static const int DEFAULT_OPT_LEVEL = 6; - static const int DEFAULT_DEBUG_LEVEL = 4; - - CxxrtlBackend() : Backend("cxxrtl", "convert design to C++ RTL simulation") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_cxxrtl [options] [filename]\n"); - log("\n"); - log("Write C++ code that simulates the design. The generated code requires a driver\n"); - log("that instantiates the design, toggles its clock, and interacts with its ports.\n"); - log("\n"); - log("The following driver may be used as an example for a design with a single clock\n"); - log("driving rising edge triggered flip-flops:\n"); - log("\n"); - log(" #include \"top.cc\"\n"); - log("\n"); - log(" int main() {\n"); - log(" cxxrtl_design::p_top top;\n"); - log(" top.step();\n"); - log(" while (1) {\n"); - log(" /* user logic */\n"); - log(" top.p_clk.set(false);\n"); - log(" top.step();\n"); - log(" top.p_clk.set(true);\n"); - log(" top.step();\n"); - log(" }\n"); - log(" }\n"); - log("\n"); - log("Note that CXXRTL simulations, just like the hardware they are simulating, are\n"); - log("subject to race conditions. If, in the example above, the user logic would run\n"); - log("simultaneously with the rising edge of the clock, the design would malfunction.\n"); - log("\n"); - log("This backend supports replacing parts of the design with black boxes implemented\n"); - log("in C++. If a module marked as a CXXRTL black box, its implementation is ignored,\n"); - log("and the generated code consists only of an interface and a factory function.\n"); - log("The driver must implement the factory function that creates an implementation of\n"); - log("the black box, taking into account the parameters it is instantiated with.\n"); - log("\n"); - log("For example, the following Verilog code defines a CXXRTL black box interface for\n"); - log("a synchronous debug sink:\n"); - log("\n"); - log(" (* cxxrtl_blackbox *)\n"); - log(" module debug(...);\n"); - log(" (* cxxrtl_edge = \"p\" *) input clk;\n"); - log(" input en;\n"); - log(" input [7:0] i_data;\n"); - log(" (* cxxrtl_sync *) output [7:0] o_data;\n"); - log(" endmodule\n"); - log("\n"); - log("For this HDL interface, this backend will generate the following C++ interface:\n"); - log("\n"); - log(" struct bb_p_debug : public module {\n"); - log(" value<1> p_clk;\n"); - log(" bool posedge_p_clk() const { /* ... */ }\n"); - log(" value<1> p_en;\n"); - log(" value<8> p_i_data;\n"); - log(" wire<8> p_o_data;\n"); - log("\n"); - log(" bool eval() override;\n"); - log(" bool commit() override;\n"); - log("\n"); - log(" static std::unique_ptr\n"); - log(" create(std::string name, metadata_map parameters, metadata_map attributes);\n"); - log(" };\n"); - log("\n"); - log("The `create' function must be implemented by the driver. For example, it could\n"); - log("always provide an implementation logging the values to standard error stream:\n"); - log("\n"); - log(" namespace cxxrtl_design {\n"); - log("\n"); - log(" struct stderr_debug : public bb_p_debug {\n"); - log(" bool eval() override {\n"); - log(" if (posedge_p_clk() && p_en)\n"); - log(" fprintf(stderr, \"debug: %%02x\\n\", p_i_data.data[0]);\n"); - log(" p_o_data.next = p_i_data;\n"); - log(" return bb_p_debug::eval();\n"); - log(" }\n"); - log(" };\n"); - log("\n"); - log(" std::unique_ptr\n"); - log(" bb_p_debug::create(std::string name, cxxrtl::metadata_map parameters,\n"); - log(" cxxrtl::metadata_map attributes) {\n"); - log(" return std::make_unique();\n"); - log(" }\n"); - log("\n"); - log(" }\n"); - log("\n"); - log("For complex applications of black boxes, it is possible to parameterize their\n"); - log("port widths. For example, the following Verilog code defines a CXXRTL black box\n"); - log("interface for a configurable width debug sink:\n"); - log("\n"); - log(" (* cxxrtl_blackbox, cxxrtl_template = \"WIDTH\" *)\n"); - log(" module debug(...);\n"); - log(" parameter WIDTH = 8;\n"); - log(" (* cxxrtl_edge = \"p\" *) input clk;\n"); - log(" input en;\n"); - log(" (* cxxrtl_width = \"WIDTH\" *) input [WIDTH - 1:0] i_data;\n"); - log(" (* cxxrtl_width = \"WIDTH\" *) output [WIDTH - 1:0] o_data;\n"); - log(" endmodule\n"); - log("\n"); - log("For this parametric HDL interface, this backend will generate the following C++\n"); - log("interface (only the differences are shown):\n"); - log("\n"); - log(" template\n"); - log(" struct bb_p_debug : public module {\n"); - log(" // ...\n"); - log(" value p_i_data;\n"); - log(" wire p_o_data;\n"); - log(" // ...\n"); - log(" static std::unique_ptr>\n"); - log(" create(std::string name, metadata_map parameters, metadata_map attributes);\n"); - log(" };\n"); - log("\n"); - log("The `create' function must be implemented by the driver, specialized for every\n"); - log("possible combination of template parameters. (Specialization is necessary to\n"); - log("enable separate compilation of generated code and black box implementations.)\n"); - log("\n"); - log(" template\n"); - log(" struct stderr_debug : public bb_p_debug {\n"); - log(" // ...\n"); - log(" };\n"); - log("\n"); - log(" template<>\n"); - log(" std::unique_ptr>\n"); - log(" bb_p_debug<8>::create(std::string name, cxxrtl::metadata_map parameters,\n"); - log(" cxxrtl::metadata_map attributes) {\n"); - log(" return std::make_unique>();\n"); - log(" }\n"); - log("\n"); - log("The following attributes are recognized by this backend:\n"); - log("\n"); - log(" cxxrtl_blackbox\n"); - log(" only valid on modules. if specified, the module contents are ignored,\n"); - log(" and the generated code includes only the module interface and a factory\n"); - log(" function, which will be called to instantiate the module.\n"); - log("\n"); - log(" cxxrtl_edge\n"); - log(" only valid on inputs of black boxes. must be one of \"p\", \"n\", \"a\".\n"); - log(" if specified on signal `clk`, the generated code includes edge detectors\n"); - log(" `posedge_p_clk()` (if \"p\"), `negedge_p_clk()` (if \"n\"), or both (if\n"); - log(" \"a\"), simplifying implementation of clocked black boxes.\n"); - log("\n"); - log(" cxxrtl_template\n"); - log(" only valid on black boxes. must contain a space separated sequence of\n"); - log(" identifiers that have a corresponding black box parameters. for each\n"); - log(" of them, the generated code includes a `size_t` template parameter.\n"); - log("\n"); - log(" cxxrtl_width\n"); - log(" only valid on ports of black boxes. must be a constant expression, which\n"); - log(" is directly inserted into generated code.\n"); - log("\n"); - log(" cxxrtl_comb, cxxrtl_sync\n"); - log(" only valid on outputs of black boxes. if specified, indicates that every\n"); - log(" bit of the output port is driven, correspondingly, by combinatorial or\n"); - log(" synchronous logic. this knowledge is used for scheduling optimizations.\n"); - log(" if neither is specified, the output will be pessimistically treated as\n"); - log(" driven by both combinatorial and synchronous logic.\n"); - log("\n"); - log("The following options are supported by this backend:\n"); - log("\n"); - log(" -print-wire-types, -print-debug-wire-types\n"); - log(" enable additional debug logging, for pass developers.\n"); - log("\n"); - log(" -header\n"); - log(" generate separate interface (.h) and implementation (.cc) files.\n"); - log(" if specified, the backend must be called with a filename, and filename\n"); - log(" of the interface is derived from filename of the implementation.\n"); - log(" otherwise, interface and implementation are generated together.\n"); - log("\n"); - log(" -namespace \n"); - log(" place the generated code into namespace . if not specified,\n"); - log(" \"cxxrtl_design\" is used.\n"); - log("\n"); - log(" -nohierarchy\n"); - log(" use design hierarchy as-is. in most designs, a top module should be\n"); - log(" present as it is exposed through the C API and has unbuffered outputs\n"); - log(" for improved performance; it will be determined automatically if absent.\n"); - log("\n"); - log(" -noflatten\n"); - log(" don't flatten the design. fully flattened designs can evaluate within\n"); - log(" one delta cycle if they have no combinatorial feedback.\n"); - log(" note that the debug interface and waveform dumps use full hierarchical\n"); - log(" names for all wires even in flattened designs.\n"); - log("\n"); - log(" -noproc\n"); - log(" don't convert processes to netlists. in most designs, converting\n"); - log(" processes significantly improves evaluation performance at the cost of\n"); - log(" slight increase in compilation time.\n"); - log("\n"); - log(" -O \n"); - log(" set the optimization level. the default is -O%d. higher optimization\n", DEFAULT_OPT_LEVEL); - log(" levels dramatically decrease compile and run time, and highest level\n"); - log(" possible for a design should be used.\n"); - log("\n"); - log(" -O0\n"); - log(" no optimization.\n"); - log("\n"); - log(" -O1\n"); - log(" unbuffer internal wires if possible.\n"); - log("\n"); - log(" -O2\n"); - log(" like -O1, and localize internal wires if possible.\n"); - log("\n"); - log(" -O3\n"); - log(" like -O2, and inline internal wires if possible.\n"); - log("\n"); - log(" -O4\n"); - log(" like -O3, and unbuffer public wires not marked (*keep*) if possible.\n"); - log("\n"); - log(" -O5\n"); - log(" like -O4, and localize public wires not marked (*keep*) if possible.\n"); - log("\n"); - log(" -O6\n"); - log(" like -O5, and inline public wires not marked (*keep*) if possible.\n"); - log("\n"); - log(" -g \n"); - log(" set the debug level. the default is -g%d. higher debug levels provide\n", DEFAULT_DEBUG_LEVEL); - log(" more visibility and generate more code, but do not pessimize evaluation.\n"); - log("\n"); - log(" -g0\n"); - log(" no debug information. the C API is disabled.\n"); - log("\n"); - log(" -g1\n"); - log(" include bare minimum of debug information necessary to access all design\n"); - log(" state. the C API is enabled.\n"); - log("\n"); - log(" -g2\n"); - log(" like -g1, but include debug information for all public wires that are\n"); - log(" directly accessible through the C++ interface.\n"); - log("\n"); - log(" -g3\n"); - log(" like -g2, and include debug information for public wires that are tied\n"); - log(" to a constant or another public wire.\n"); - log("\n"); - log(" -g4\n"); - log(" like -g3, and compute debug information on demand for all public wires\n"); - log(" that were optimized out.\n"); - log("\n"); - } - - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override - { - bool print_wire_types = false; - bool print_debug_wire_types = false; - bool nohierarchy = false; - bool noflatten = false; - bool noproc = false; - int opt_level = DEFAULT_OPT_LEVEL; - int debug_level = DEFAULT_DEBUG_LEVEL; - CxxrtlWorker worker; - - log_header(design, "Executing CXXRTL backend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-print-wire-types") { - print_wire_types = true; - continue; - } - if (args[argidx] == "-print-debug-wire-types") { - print_debug_wire_types = true; - continue; - } - if (args[argidx] == "-nohierarchy") { - nohierarchy = true; - continue; - } - if (args[argidx] == "-noflatten") { - noflatten = true; - continue; - } - if (args[argidx] == "-noproc") { - noproc = true; - continue; - } - if (args[argidx] == "-Og") { - log_warning("The `-Og` option has been removed. Use `-g3` instead for complete " - "design coverage regardless of optimization level.\n"); - continue; - } - if (args[argidx] == "-O" && argidx+1 < args.size() && args[argidx+1] == "g") { - argidx++; - log_warning("The `-Og` option has been removed. Use `-g3` instead for complete " - "design coverage regardless of optimization level.\n"); - continue; - } - if (args[argidx] == "-O" && argidx+1 < args.size()) { - opt_level = std::stoi(args[++argidx]); - continue; - } - if (args[argidx].substr(0, 2) == "-O" && args[argidx].size() == 3 && isdigit(args[argidx][2])) { - opt_level = std::stoi(args[argidx].substr(2)); - continue; - } - if (args[argidx] == "-g" && argidx+1 < args.size()) { - debug_level = std::stoi(args[++argidx]); - continue; - } - if (args[argidx].substr(0, 2) == "-g" && args[argidx].size() == 3 && isdigit(args[argidx][2])) { - debug_level = std::stoi(args[argidx].substr(2)); - continue; - } - if (args[argidx] == "-header") { - worker.split_intf = true; - continue; - } - if (args[argidx] == "-namespace" && argidx+1 < args.size()) { - worker.design_ns = args[++argidx]; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - worker.print_wire_types = print_wire_types; - worker.print_debug_wire_types = print_debug_wire_types; - worker.run_hierarchy = !nohierarchy; - worker.run_flatten = !noflatten; - worker.run_proc = !noproc; - switch (opt_level) { - // the highest level here must match DEFAULT_OPT_LEVEL - case 6: - worker.inline_public = true; - YS_FALLTHROUGH - case 5: - worker.localize_public = true; - YS_FALLTHROUGH - case 4: - worker.unbuffer_public = true; - YS_FALLTHROUGH - case 3: - worker.inline_internal = true; - YS_FALLTHROUGH - case 2: - worker.localize_internal = true; - YS_FALLTHROUGH - case 1: - worker.unbuffer_internal = true; - YS_FALLTHROUGH - case 0: - break; - default: - log_cmd_error("Invalid optimization level %d.\n", opt_level); - } - switch (debug_level) { - // the highest level here must match DEFAULT_DEBUG_LEVEL - case 4: - worker.debug_eval = true; - YS_FALLTHROUGH - case 3: - worker.debug_alias = true; - YS_FALLTHROUGH - case 2: - worker.debug_member = true; - YS_FALLTHROUGH - case 1: - worker.debug_info = true; - YS_FALLTHROUGH - case 0: - break; - default: - log_cmd_error("Invalid debug information level %d.\n", debug_level); - } - - std::ofstream intf_f; - if (worker.split_intf) { - if (filename == "") - log_cmd_error("Option -header must be used with a filename.\n"); - - worker.intf_filename = filename.substr(0, filename.rfind('.')) + ".h"; - intf_f.open(worker.intf_filename, std::ofstream::trunc); - if (intf_f.fail()) - log_cmd_error("Can't open file `%s' for writing: %s\n", - worker.intf_filename.c_str(), strerror(errno)); - - worker.intf_f = &intf_f; - } - worker.impl_f = f; - - worker.prepare_design(design); - worker.dump_design(design); - } -} CxxrtlBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/cxxrtl/cxxrtl_capi.cc b/yosys/backends/cxxrtl/cxxrtl_capi.cc deleted file mode 100644 index 227173ba87f..00000000000 --- a/yosys/backends/cxxrtl/cxxrtl_capi.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 whitequark - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted. - * - * 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 is a part of the CXXRTL C API. It should be used together with `cxxrtl_capi.h`. - -#include -#include - -struct _cxxrtl_handle { - std::unique_ptr module; - cxxrtl::debug_items objects; -}; - -// Private function for use by other units of the C API. -const cxxrtl::debug_items &cxxrtl_debug_items_from_handle(cxxrtl_handle handle) { - return handle->objects; -} - -cxxrtl_handle cxxrtl_create(cxxrtl_toplevel design) { - return cxxrtl_create_at(design, ""); -} - -cxxrtl_handle cxxrtl_create_at(cxxrtl_toplevel design, const char *root) { - std::string path = root; - if (!path.empty()) { - // module::debug_info() accepts either an empty path, or a path ending in space to simplify - // the logic in generated code. While this is sketchy at best to expose in the C++ API, this - // would be a lot worse in the C API, so don't expose it here. - assert(path.back() != ' '); - path += ' '; - } - - cxxrtl_handle handle = new _cxxrtl_handle; - handle->module = std::move(design->module); - handle->module->debug_info(handle->objects, path); - delete design; - return handle; -} - -void cxxrtl_destroy(cxxrtl_handle handle) { - delete handle; -} - -void cxxrtl_reset(cxxrtl_handle handle) { - handle->module->reset(); -} - -int cxxrtl_eval(cxxrtl_handle handle) { - return handle->module->eval(); -} - -int cxxrtl_commit(cxxrtl_handle handle) { - return handle->module->commit(); -} - -size_t cxxrtl_step(cxxrtl_handle handle) { - return handle->module->step(); -} - -struct cxxrtl_object *cxxrtl_get_parts(cxxrtl_handle handle, const char *name, size_t *parts) { - auto it = handle->objects.table.find(name); - if (it == handle->objects.table.end()) - return nullptr; - *parts = it->second.size(); - return static_cast(&it->second[0]); -} - -void cxxrtl_enum(cxxrtl_handle handle, void *data, - void (*callback)(void *data, const char *name, - cxxrtl_object *object, size_t parts)) { - for (auto &it : handle->objects.table) - callback(data, it.first.c_str(), static_cast(&it.second[0]), it.second.size()); -} - -void cxxrtl_outline_eval(cxxrtl_outline outline) { - outline->eval(); -} diff --git a/yosys/backends/cxxrtl/cxxrtl_capi.h b/yosys/backends/cxxrtl/cxxrtl_capi.h deleted file mode 100644 index 2df2b7287f4..00000000000 --- a/yosys/backends/cxxrtl/cxxrtl_capi.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 whitequark - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted. - * - * 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 CXXRTL_CAPI_H -#define CXXRTL_CAPI_H - -// This file is a part of the CXXRTL C API. It should be used together with `cxxrtl_capi.cc`. -// -// The CXXRTL C API makes it possible to drive CXXRTL designs using C or any other language that -// supports the C ABI, for example, Python. It does not provide a way to implement black boxes. - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Opaque reference to a design toplevel. -// -// A design toplevel can only be used to create a design handle. -typedef struct _cxxrtl_toplevel *cxxrtl_toplevel; - -// The constructor for a design toplevel is provided as a part of generated code for that design. -// Its prototype matches: -// -// cxxrtl_toplevel _create(); - -// Opaque reference to a design handle. -// -// A design handle is required by all operations in the C API. -typedef struct _cxxrtl_handle *cxxrtl_handle; - -// Create a design handle from a design toplevel. -// -// The `design` is consumed by this operation and cannot be used afterwards. -cxxrtl_handle cxxrtl_create(cxxrtl_toplevel design); - -// Create a design handle at a given hierarchy position from a design toplevel. -// -// This operation is similar to `cxxrtl_create`, except the full hierarchical name of every object -// is prepended with `root`. -cxxrtl_handle cxxrtl_create_at(cxxrtl_toplevel design, const char *root); - -// Release all resources used by a design and its handle. -void cxxrtl_destroy(cxxrtl_handle handle); - -// Reinitialize the design, replacing the internal state with the reset values while preserving -// black boxes. -// -// This operation is essentially equivalent to a power-on reset. Values, wires, and memories are -// returned to their reset state while preserving the state of black boxes and keeping all of -// the interior pointers obtained with e.g. `cxxrtl_get` valid. -void cxxrtl_reset(cxxrtl_handle handle); - -// Evaluate the design, propagating changes on inputs to the `next` value of internal state and -// output wires. -// -// Returns 1 if the design is known to immediately converge, 0 otherwise. -int cxxrtl_eval(cxxrtl_handle handle); - -// Commit the design, replacing the `curr` value of internal state and output wires with the `next` -// value. -// -// Return 1 if any of the `curr` values were updated, 0 otherwise. -int cxxrtl_commit(cxxrtl_handle handle); - -// Simulate the design to a fixed point. -// -// Returns the number of delta cycles. -size_t cxxrtl_step(cxxrtl_handle handle); - -// Type of a simulated object. -// -// The type of a simulated object indicates the way it is stored and the operations that are legal -// to perform on it (i.e. won't crash the simulation). It says very little about object semantics, -// which is specified through flags. -enum cxxrtl_type { - // Values correspond to singly buffered netlist nodes, i.e. nodes driven exclusively by - // combinatorial cells, or toplevel input nodes. - // - // Values can be inspected via the `curr` pointer. If the `next` pointer is NULL, the value is - // driven by a constant and can never be modified. Otherwise, the value can be modified through - // the `next` pointer (which is equal to `curr` if not NULL). Note that changes to the bits - // driven by combinatorial cells will be ignored. - // - // Values always have depth 1. - CXXRTL_VALUE = 0, - - // Wires correspond to doubly buffered netlist nodes, i.e. nodes driven, at least in part, by - // storage cells, or by combinatorial cells that are a part of a feedback path. They are also - // present in non-optimized builds. - // - // Wires can be inspected via the `curr` pointer and modified via the `next` pointer (which are - // distinct for wires). Note that changes to the bits driven by combinatorial cells will be - // ignored. - // - // Wires always have depth 1. - CXXRTL_WIRE = 1, - - // Memories correspond to memory cells. - // - // Memories can be inspected and modified via the `curr` pointer. Due to a limitation of this - // API, memories cannot yet be modified in a guaranteed race-free way, and the `next` pointer is - // always NULL. - CXXRTL_MEMORY = 2, - - // Aliases correspond to netlist nodes driven by another node such that their value is always - // exactly equal. - // - // Aliases can be inspected via the `curr` pointer. They cannot be modified, and the `next` - // pointer is always NULL. - CXXRTL_ALIAS = 3, - - // Outlines correspond to netlist nodes that were optimized in a way that makes them inaccessible - // outside of a module's `eval()` function. At the highest debug information level, every inlined - // node has a corresponding outline object. - // - // Outlines can be inspected via the `curr` pointer and can never be modified; the `next` pointer - // is always NULL. Unlike all other objects, the bits of an outline object are meaningful only - // after a call to `cxxrtl_outline_eval` and until any subsequent modification to the netlist. - // Observing this requirement is the responsibility of the caller; it is not enforced. - // - // Outlines always correspond to combinatorial netlist nodes that are not ports. - CXXRTL_OUTLINE = 4, - - // More object types may be added in the future, but the existing ones will never change. -}; - -// Flags of a simulated object. -// -// The flags of a simulated object indicate its role in the netlist: -// * The flags `CXXRTL_INPUT` and `CXXRTL_OUTPUT` designate module ports. -// * The flags `CXXRTL_DRIVEN_SYNC`, `CXXRTL_DRIVEN_COMB`, and `CXXRTL_UNDRIVEN` specify -// the semantics of node state. An object with several of these flags set has different bits -// follow different semantics. -enum cxxrtl_flag { - // Node is a module input port. - // - // This flag can be set on objects of type `CXXRTL_VALUE` and `CXXRTL_WIRE`. It may be combined - // with `CXXRTL_OUTPUT`, as well as other flags. - CXXRTL_INPUT = 1 << 0, - - // Node is a module output port. - // - // This flag can be set on objects of type `CXXRTL_WIRE`. It may be combined with `CXXRTL_INPUT`, - // as well as other flags. - CXXRTL_OUTPUT = 1 << 1, - - // Node is a module inout port. - // - // This flag can be set on objects of type `CXXRTL_WIRE`. It may be combined with other flags. - CXXRTL_INOUT = (CXXRTL_INPUT|CXXRTL_OUTPUT), - - // Node has bits that are driven by a storage cell. - // - // This flag can be set on objects of type `CXXRTL_WIRE`. It may be combined with - // `CXXRTL_DRIVEN_COMB` and `CXXRTL_UNDRIVEN`, as well as other flags. - // - // This flag is set on wires that have bits connected directly to the output of a flip-flop or - // a latch, and hold its state. Many `CXXRTL_WIRE` objects may not have the `CXXRTL_DRIVEN_SYNC` - // flag set; for example, output ports and feedback wires generally won't. Writing to the `next` - // pointer of these wires updates stored state, and for designs without combinatorial loops, - // capturing the value from every of these wires through the `curr` pointer creates a complete - // snapshot of the design state. - CXXRTL_DRIVEN_SYNC = 1 << 2, - - // Node has bits that are driven by a combinatorial cell or another node. - // - // This flag can be set on objects of type `CXXRTL_VALUE`, `CXXRTL_WIRE`, and `CXXRTL_OUTLINE`. - // It may be combined with `CXXRTL_DRIVEN_SYNC` and `CXXRTL_UNDRIVEN`, as well as other flags. - // - // This flag is set on objects that have bits connected to the output of a combinatorial cell, - // or directly to another node. For designs without combinatorial loops, writing to such bits - // through the `next` pointer (if it is not NULL) has no effect. - CXXRTL_DRIVEN_COMB = 1 << 3, - - // Node has bits that are not driven. - // - // This flag can be set on objects of type `CXXRTL_VALUE` and `CXXRTL_WIRE`. It may be combined - // with `CXXRTL_DRIVEN_SYNC` and `CXXRTL_DRIVEN_COMB`, as well as other flags. - // - // This flag is set on objects that have bits not driven by an output of any cell or by another - // node, such as inputs and dangling wires. - CXXRTL_UNDRIVEN = 1 << 4, - - // More object flags may be added in the future, but the existing ones will never change. -}; - -// Description of a simulated object. -// -// The `curr` and `next` arrays can be accessed directly to inspect and, if applicable, modify -// the bits stored in the object. -struct cxxrtl_object { - // Type of the object. - // - // All objects have the same memory layout determined by `width` and `depth`, but the type - // determines all other properties of the object. - uint32_t type; // actually `enum cxxrtl_type` - - // Flags of the object. - uint32_t flags; // actually bit mask of `enum cxxrtl_flags` - - // Width of the object in bits. - size_t width; - - // Index of the least significant bit. - size_t lsb_at; - - // Depth of the object. Only meaningful for memories; for other objects, always 1. - size_t depth; - - // Index of the first word. Only meaningful for memories; for other objects, always 0; - size_t zero_at; - - // Bits stored in the object, as 32-bit chunks, least significant bits first. - // - // The width is rounded up to a multiple of 32; the padding bits are always set to 0 by - // the simulation code, and must be always written as 0 when modified by user code. - // In memories, every element is stored contiguously. Therefore, the total number of chunks - // in any object is `((width + 31) / 32) * depth`. - // - // To allow the simulation to be partitioned into multiple independent units communicating - // through wires, the bits are double buffered. To avoid race conditions, user code should - // always read from `curr` and write to `next`. The `curr` pointer is always valid; for objects - // that cannot be modified, or cannot be modified in a race-free way, `next` is NULL. - uint32_t *curr; - uint32_t *next; - - // Opaque reference to an outline. Only meaningful for outline objects. - // - // See the documentation of `cxxrtl_outline` for details. When creating a `cxxrtl_object`, set - // this field to NULL. - struct _cxxrtl_outline *outline; - - // More description fields may be added in the future, but the existing ones will never change. -}; - -// Retrieve description of a simulated object. -// -// The `name` is the full hierarchical name of the object in the Yosys notation, where public names -// have a `\` prefix and hierarchy levels are separated by single spaces. For example, if -// the top-level module instantiates a module `foo`, which in turn contains a wire `bar`, the full -// hierarchical name is `\foo \bar`. -// -// The storage of a single abstract object may be split (usually with the `splitnets` pass) into -// many physical parts, all of which correspond to the same hierarchical name. To handle such cases, -// this function returns an array and writes its length to `parts`. The array is sorted by `lsb_at`. -// -// Returns the object parts if it was found, NULL otherwise. The returned parts are valid until -// the design is destroyed. -struct cxxrtl_object *cxxrtl_get_parts(cxxrtl_handle handle, const char *name, size_t *parts); - -// Retrieve description of a single part simulated object. -// -// This function is a shortcut for the most common use of `cxxrtl_get_parts`. It asserts that, -// if the object exists, it consists of a single part. If assertions are disabled, it returns NULL -// for multi-part objects. -static inline struct cxxrtl_object *cxxrtl_get(cxxrtl_handle handle, const char *name) { - size_t parts = 0; - struct cxxrtl_object *object = cxxrtl_get_parts(handle, name, &parts); - assert(object == NULL || parts == 1); - if (object == NULL || parts == 1) - return object; - return NULL; -} - -// Enumerate simulated objects. -// -// For every object in the simulation, `callback` is called with the provided `data`, the full -// hierarchical name of the object (see `cxxrtl_get` for details), and the object parts. -// The provided `name` and `object` values are valid until the design is destroyed. -void cxxrtl_enum(cxxrtl_handle handle, void *data, - void (*callback)(void *data, const char *name, - struct cxxrtl_object *object, size_t parts)); - -// Opaque reference to an outline. -// -// An outline is a group of outline objects that are evaluated simultaneously. The identity of -// an outline can be compared to determine whether any two objects belong to the same outline. -typedef struct _cxxrtl_outline *cxxrtl_outline; - -// Evaluate an outline. -// -// After evaluating an outline, the bits of every outline object contained in it are consistent -// with the current state of the netlist. In general, any further modification to the netlist -// causes every outline object to become stale, after which the corresponding outline must be -// re-evaluated, otherwise the bits read from that object are meaningless. -void cxxrtl_outline_eval(cxxrtl_outline outline); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/yosys/backends/cxxrtl/cxxrtl_vcd.h b/yosys/backends/cxxrtl/cxxrtl_vcd.h deleted file mode 100644 index b76922bbd8a..00000000000 --- a/yosys/backends/cxxrtl/cxxrtl_vcd.h +++ /dev/null @@ -1,275 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 whitequark - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted. - * - * 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 CXXRTL_VCD_H -#define CXXRTL_VCD_H - -#include - -namespace cxxrtl { - -class vcd_writer { - struct variable { - size_t ident; - size_t width; - chunk_t *curr; - size_t cache_offset; - debug_outline *outline; - bool *outline_warm; - }; - - std::vector current_scope; - std::map outlines; - std::vector variables; - std::vector cache; - std::map aliases; - bool streaming = false; - - void emit_timescale(unsigned number, const std::string &unit) { - assert(!streaming); - assert(number == 1 || number == 10 || number == 100); - assert(unit == "s" || unit == "ms" || unit == "us" || - unit == "ns" || unit == "ps" || unit == "fs"); - buffer += "$timescale " + std::to_string(number) + " " + unit + " $end\n"; - } - - void emit_scope(const std::vector &scope) { - assert(!streaming); - while (current_scope.size() > scope.size() || - (current_scope.size() > 0 && - current_scope[current_scope.size() - 1] != scope[current_scope.size() - 1])) { - buffer += "$upscope $end\n"; - current_scope.pop_back(); - } - while (current_scope.size() < scope.size()) { - buffer += "$scope module " + scope[current_scope.size()] + " $end\n"; - current_scope.push_back(scope[current_scope.size()]); - } - } - - void emit_ident(size_t ident) { - do { - buffer += '!' + ident % 94; // "base94" - ident /= 94; - } while (ident != 0); - } - - void emit_name(const std::string &name) { - for (char c : name) { - if (c == ':') { - // Due to a bug, GTKWave cannot parse a colon in the variable name, causing the VCD file - // to be unreadable. It cannot be escaped either, so replace it with the sideways colon. - buffer += ".."; - } else { - buffer += c; - } - } - } - - void emit_var(const variable &var, const std::string &type, const std::string &name, - size_t lsb_at, bool multipart) { - assert(!streaming); - buffer += "$var " + type + " " + std::to_string(var.width) + " "; - emit_ident(var.ident); - buffer += " "; - emit_name(name); - if (multipart || name.back() == ']' || lsb_at != 0) { - if (var.width == 1) - buffer += " [" + std::to_string(lsb_at) + "]"; - else - buffer += " [" + std::to_string(lsb_at + var.width - 1) + ":" + std::to_string(lsb_at) + "]"; - } - buffer += " $end\n"; - } - - void emit_enddefinitions() { - assert(!streaming); - buffer += "$enddefinitions $end\n"; - streaming = true; - } - - void emit_time(uint64_t timestamp) { - assert(streaming); - buffer += "#" + std::to_string(timestamp) + "\n"; - } - - void emit_scalar(const variable &var) { - assert(streaming); - assert(var.width == 1); - buffer += (*var.curr ? '1' : '0'); - emit_ident(var.ident); - buffer += '\n'; - } - - void emit_vector(const variable &var) { - assert(streaming); - buffer += 'b'; - for (size_t bit = var.width - 1; bit != (size_t)-1; bit--) { - bool bit_curr = var.curr[bit / (8 * sizeof(chunk_t))] & (1 << (bit % (8 * sizeof(chunk_t)))); - buffer += (bit_curr ? '1' : '0'); - } - buffer += ' '; - emit_ident(var.ident); - buffer += '\n'; - } - - void reset_outlines() { - for (auto &outline_it : outlines) - outline_it.second = /*warm=*/(outline_it.first == nullptr); - } - - variable ®ister_variable(size_t width, chunk_t *curr, bool constant = false, debug_outline *outline = nullptr) { - if (aliases.count(curr)) { - return variables[aliases[curr]]; - } else { - auto outline_it = outlines.emplace(outline, /*warm=*/(outline == nullptr)).first; - const size_t chunks = (width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8); - aliases[curr] = variables.size(); - if (constant) { - variables.emplace_back(variable { variables.size(), width, curr, (size_t)-1, outline_it->first, &outline_it->second }); - } else { - variables.emplace_back(variable { variables.size(), width, curr, cache.size(), outline_it->first, &outline_it->second }); - cache.insert(cache.end(), &curr[0], &curr[chunks]); - } - return variables.back(); - } - } - - bool test_variable(const variable &var) { - if (var.cache_offset == (size_t)-1) - return false; // constant - if (!*var.outline_warm) { - var.outline->eval(); - *var.outline_warm = true; - } - const size_t chunks = (var.width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8); - if (std::equal(&var.curr[0], &var.curr[chunks], &cache[var.cache_offset])) { - return false; - } else { - std::copy(&var.curr[0], &var.curr[chunks], &cache[var.cache_offset]); - return true; - } - } - - static std::vector split_hierarchy(const std::string &hier_name) { - std::vector hierarchy; - size_t prev = 0; - while (true) { - size_t curr = hier_name.find_first_of(' ', prev); - if (curr == std::string::npos) { - hierarchy.push_back(hier_name.substr(prev)); - break; - } else { - hierarchy.push_back(hier_name.substr(prev, curr - prev)); - prev = curr + 1; - } - } - return hierarchy; - } - -public: - std::string buffer; - - void timescale(unsigned number, const std::string &unit) { - emit_timescale(number, unit); - } - - void add(const std::string &hier_name, const debug_item &item, bool multipart = false) { - std::vector scope = split_hierarchy(hier_name); - std::string name = scope.back(); - scope.pop_back(); - - emit_scope(scope); - switch (item.type) { - // Not the best naming but oh well... - case debug_item::VALUE: - emit_var(register_variable(item.width, item.curr, /*constant=*/item.next == nullptr), - "wire", name, item.lsb_at, multipart); - break; - case debug_item::WIRE: - emit_var(register_variable(item.width, item.curr), - "reg", name, item.lsb_at, multipart); - break; - case debug_item::MEMORY: { - const size_t stride = (item.width + (sizeof(chunk_t) * 8 - 1)) / (sizeof(chunk_t) * 8); - for (size_t index = 0; index < item.depth; index++) { - chunk_t *nth_curr = &item.curr[stride * index]; - std::string nth_name = name + '[' + std::to_string(index) + ']'; - emit_var(register_variable(item.width, nth_curr), - "reg", nth_name, item.lsb_at, multipart); - } - break; - } - case debug_item::ALIAS: - // Like VALUE, but, even though `item.next == nullptr` always holds, the underlying value - // can actually change, and must be tracked. In most cases the VCD identifier will be - // unified with the aliased reg, but we should handle the case where only the alias is - // added to the VCD writer, too. - emit_var(register_variable(item.width, item.curr), - "wire", name, item.lsb_at, multipart); - break; - case debug_item::OUTLINE: - emit_var(register_variable(item.width, item.curr, /*constant=*/false, item.outline), - "wire", name, item.lsb_at, multipart); - break; - } - } - - template - void add(const debug_items &items, const Filter &filter) { - // `debug_items` is a map, so the items are already sorted in an order optimal for emitting - // VCD scope sections. - for (auto &it : items.table) - for (auto &part : it.second) - if (filter(it.first, part)) - add(it.first, part, it.second.size() > 1); - } - - void add(const debug_items &items) { - this->add(items, [](const std::string &, const debug_item &) { - return true; - }); - } - - void add_without_memories(const debug_items &items) { - this->add(items, [](const std::string &, const debug_item &item) { - return item.type != debug_item::MEMORY; - }); - } - - void sample(uint64_t timestamp) { - bool first_sample = !streaming; - if (first_sample) { - emit_scope({}); - emit_enddefinitions(); - } - reset_outlines(); - emit_time(timestamp); - for (auto var : variables) - if (test_variable(var) || first_sample) { - if (var.width == 1) - emit_scalar(var); - else - emit_vector(var); - } - } -}; - -} - -#endif diff --git a/yosys/backends/cxxrtl/cxxrtl_vcd_capi.cc b/yosys/backends/cxxrtl/cxxrtl_vcd_capi.cc deleted file mode 100644 index 52a9198b869..00000000000 --- a/yosys/backends/cxxrtl/cxxrtl_vcd_capi.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 whitequark - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted. - * - * 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 is a part of the CXXRTL C API. It should be used together with `cxxrtl_vcd_capi.h`. - -#include -#include - -extern const cxxrtl::debug_items &cxxrtl_debug_items_from_handle(cxxrtl_handle handle); - -struct _cxxrtl_vcd { - cxxrtl::vcd_writer writer; - bool flush = false; -}; - -cxxrtl_vcd cxxrtl_vcd_create() { - return new _cxxrtl_vcd; -} - -void cxxrtl_vcd_destroy(cxxrtl_vcd vcd) { - delete vcd; -} - -void cxxrtl_vcd_timescale(cxxrtl_vcd vcd, int number, const char *unit) { - vcd->writer.timescale(number, unit); -} - -void cxxrtl_vcd_add(cxxrtl_vcd vcd, const char *name, cxxrtl_object *object) { - // Note the copy. We don't know whether `object` came from a design (in which case it is - // an instance of `debug_item`), or from user code (in which case it is an instance of - // `cxxrtl_object`), so casting the pointer wouldn't be safe. - vcd->writer.add(name, cxxrtl::debug_item(*object)); -} - -void cxxrtl_vcd_add_from(cxxrtl_vcd vcd, cxxrtl_handle handle) { - vcd->writer.add(cxxrtl_debug_items_from_handle(handle)); -} - -void cxxrtl_vcd_add_from_if(cxxrtl_vcd vcd, cxxrtl_handle handle, void *data, - int (*filter)(void *data, const char *name, - const cxxrtl_object *object)) { - vcd->writer.add(cxxrtl_debug_items_from_handle(handle), - [=](const std::string &name, const cxxrtl::debug_item &item) { - return filter(data, name.c_str(), static_cast(&item)); - }); -} - -void cxxrtl_vcd_add_from_without_memories(cxxrtl_vcd vcd, cxxrtl_handle handle) { - vcd->writer.add_without_memories(cxxrtl_debug_items_from_handle(handle)); -} - -void cxxrtl_vcd_sample(cxxrtl_vcd vcd, uint64_t time) { - if (vcd->flush) { - vcd->writer.buffer.clear(); - vcd->flush = false; - } - vcd->writer.sample(time); -} - -void cxxrtl_vcd_read(cxxrtl_vcd vcd, const char **data, size_t *size) { - if (vcd->flush) { - vcd->writer.buffer.clear(); - vcd->flush = false; - } - *data = vcd->writer.buffer.c_str(); - *size = vcd->writer.buffer.size(); - vcd->flush = true; -} diff --git a/yosys/backends/cxxrtl/cxxrtl_vcd_capi.h b/yosys/backends/cxxrtl/cxxrtl_vcd_capi.h deleted file mode 100644 index d55afe2230e..00000000000 --- a/yosys/backends/cxxrtl/cxxrtl_vcd_capi.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 whitequark - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted. - * - * 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 CXXRTL_VCD_CAPI_H -#define CXXRTL_VCD_CAPI_H - -// This file is a part of the CXXRTL C API. It should be used together with `cxxrtl_vcd_capi.cc`. -// -// The CXXRTL C API for VCD writing makes it possible to insert virtual probes into designs and -// dump waveforms to Value Change Dump files. - -#include -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Opaque reference to a VCD writer. -typedef struct _cxxrtl_vcd *cxxrtl_vcd; - -// Create a VCD writer. -cxxrtl_vcd cxxrtl_vcd_create(); - -// Release all resources used by a VCD writer. -void cxxrtl_vcd_destroy(cxxrtl_vcd vcd); - -// Set VCD timescale. -// -// The `number` must be 1, 10, or 100, and the `unit` must be one of `"s"`, `"ms"`, `"us"`, `"ns"`, -// `"ps"`, or `"fs"`. -// -// Timescale can only be set before the first call to `cxxrtl_vcd_sample`. -void cxxrtl_vcd_timescale(cxxrtl_vcd vcd, int number, const char *unit); - -// Schedule a specific CXXRTL object to be sampled. -// -// The `name` is a full hierarchical name as described for `cxxrtl_get`; it does not need to match -// the original name of `object`, if any. The `object` must outlive the VCD writer, but there are -// no other requirements; if desired, it can be provided by user code, rather than come from -// a design. -// -// Objects can only be scheduled before the first call to `cxxrtl_vcd_sample`. -void cxxrtl_vcd_add(cxxrtl_vcd vcd, const char *name, struct cxxrtl_object *object); - -// Schedule all CXXRTL objects in a simulation. -// -// The design `handle` must outlive the VCD writer. -// -// Objects can only be scheduled before the first call to `cxxrtl_vcd_sample`. -void cxxrtl_vcd_add_from(cxxrtl_vcd vcd, cxxrtl_handle handle); - -// Schedule CXXRTL objects in a simulation that match a given predicate. -// -// For every object in the simulation, `filter` is called with the provided `data`, the full -// hierarchical name of the object (see `cxxrtl_get` for details), and the object description. -// The object will be sampled if the predicate returns a non-zero value. -// -// Objects can only be scheduled before the first call to `cxxrtl_vcd_sample`. -void cxxrtl_vcd_add_from_if(cxxrtl_vcd vcd, cxxrtl_handle handle, void *data, - int (*filter)(void *data, const char *name, - const struct cxxrtl_object *object)); - -// Schedule all CXXRTL objects in a simulation except for memories. -// -// The design `handle` must outlive the VCD writer. -// -// Objects can only be scheduled before the first call to `cxxrtl_vcd_sample`. -void cxxrtl_vcd_add_from_without_memories(cxxrtl_vcd vcd, cxxrtl_handle handle); - -// Sample all scheduled objects. -// -// First, `time` is written to the internal buffer. Second, the values of every signal changed since -// the previous call to `cxxrtl_vcd_sample` (all values if this is the first call) are written to -// the internal buffer. The contents of the buffer can be retrieved with `cxxrtl_vcd_read`. -void cxxrtl_vcd_sample(cxxrtl_vcd vcd, uint64_t time); - -// Retrieve buffered VCD data. -// -// The pointer to the start of the next chunk of VCD data is assigned to `*data`, and the length -// of that chunk is assigned to `*size`. The pointer to the data is valid until the next call to -// `cxxrtl_vcd_sample` or `cxxrtl_vcd_read`. Once all of the buffered data has been retrieved, -// this function will always return zero sized chunks. -void cxxrtl_vcd_read(cxxrtl_vcd vcd, const char **data, size_t *size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/yosys/backends/edif/Makefile.inc b/yosys/backends/edif/Makefile.inc deleted file mode 100644 index 93de0e24f72..00000000000 --- 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 7722d0c3394..00000000000 --- a/yosys/backends/edif/edif.cc +++ /dev/null @@ -1,590 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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() 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\n"); - log(" \"G\" for \"GND\" and \"P\" for \"VCC\".)\n"); - log("\n"); - log(" -attrprop\n"); - log(" create EDIF properties for cell attributes\n"); - log("\n"); - log(" -keep\n"); - log(" create extra KEEP nets by allowing a cell to drive multiple nets.\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) 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, keepmode = 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] == "-keep") { - keepmode = 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 module : design->modules()) - if (module->get_bool_attribute(ID::top)) - top_module_name = module->name.str(); - - for (auto module : design->modules()) - { - 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", log_id(module->name)); - if (module->memories.size() != 0) - log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", log_id(module->name)); - - for (auto cell : module->cells()) - { - if (design->module(cell->type) == nullptr || design->module(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"; - } - int width = port_it.second; - int start = 0; - bool upto = false; - auto m = design->module(cell_it.first); - if (m) { - auto w = m->wire(port_it.first); - if (w) { - width = GetSize(w); - start = w->start_offset; - upto = w->upto; - } - } - if (width == 1) - *f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it.first), dir); - else { - int b[2]; - b[upto ? 0 : 1] = start; - b[upto ? 1 : 0] = start+width-1; - *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEFR(port_it.first, port_rename, b[0], b[1]), width, 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 module : design->modules()) { - module_deps[module] = std::set(); - for (auto cell : module->cells()) - if (design->module(cell->type) != nullptr) - module_deps[module].insert(design->module(cell->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", log_id(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", log_id(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"); - - 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 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 cell : module->cells()) { - for (auto &conn : cell->connections()) - if (cell->output(conn.first)) - sigmap.add(conn.second); - } - - for (auto wire : module->wires()) - for (auto b1 : SigSpec(wire)) - { - auto b2 = sigmap(b1); - - if (b1 == b2 || !b2.wire) - continue; - - log_assert(b1.wire != nullptr); - - Wire *w1 = b1.wire; - Wire *w2 = b2.wire; - - { - int c1 = w1->get_bool_attribute(ID::keep); - int c2 = w2->get_bool_attribute(ID::keep); - - if (c1 > c2) goto promote; - if (c1 < c2) goto nopromote; - } - - { - int c1 = w1->name.isPublic(); - int c2 = w2->name.isPublic(); - - if (c1 > c2) goto promote; - if (c1 < c2) goto nopromote; - } - - { - auto count_nontrivial_attr = [](Wire *w) { - int count = w->attributes.size(); - count -= w->attributes.count(ID::src); - count -= w->attributes.count(ID::unused_bits); - return count; - }; - - int c1 = count_nontrivial_attr(w1); - int c2 = count_nontrivial_attr(w2); - - if (c1 > c2) goto promote; - if (c1 < c2) goto nopromote; - } - - { - int c1 = w1->port_id ? INT_MAX - w1->port_id : 0; - int c2 = w2->port_id ? INT_MAX - w2->port_id : 0; - - if (c1 > c2) goto promote; - if (c1 < c2) goto nopromote; - } - - nopromote: - if (0) - promote: - sigmap.add(b1); - } - - for (auto wire : module->wires()) { - 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)", EDIF_DEF(wire->name), dir); - if (attr_properties) - for (auto &p : wire->attributes) - add_prop(p.first, p.second); - *f << ")\n"; - RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire)); - net_join_db[sig].insert(make_pair(stringf("(portRef %s)", EDIF_REF(wire->name)), wire->port_input)); - } 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)", EDIF_DEFR(wire->name, port_rename, b[0], b[1]), wire->width, dir); - if (attr_properties) - for (auto &p : wire->attributes) - add_prop(p.first, p.second); - - *f << ")\n"; - for (int i = 0; i < wire->width; i++) { - RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i)); - net_join_db[sig].insert(make_pair(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1), wire->port_input)); - } - } - } - - *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 : module->cells()) { - *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)" : ""); - 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 { - int member_idx = GetSize(sig)-i-1; - auto m = design->module(cell->type); - int width = sig.size(); - if (m) { - auto w = m->wire(p.first); - if (w) { - member_idx = GetSize(w)-i-1; - width = GetSize(w); - } - } - if (width == 1) - net_join_db[sig[i]].insert(make_pair(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)), cell->output(p.first))); - else { - net_join_db[sig[i]].insert(make_pair(stringf("(portRef (member %s %d) (instanceRef %s))", - EDIF_REF(p.first), member_idx, EDIF_REF(cell->name)), cell->output(p.first))); - } - } - } - } - - 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.first.c_str()); - sig = RTLIL::State::S0; - } else if (sig == RTLIL::State::Sz) { - continue; - } else { - for (auto &ref : it.second) - log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.first.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.first.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(" )"); - if (attr_properties && sig.wire != NULL) - for (auto &p : sig.wire->attributes) - add_prop(p.first, p.second); - *f << stringf("\n )\n"); - } - - for (auto wire : module->wires()) - { - if (!wire->get_bool_attribute(ID::keep)) - continue; - - for(int i = 0; i < wire->width; i++) - { - SigBit raw_sig = RTLIL::SigSpec(wire, i); - SigBit mapped_sig = sigmap(raw_sig); - - if (raw_sig == mapped_sig || net_join_db.count(mapped_sig) == 0) - continue; - - std::string netname = log_signal(raw_sig); - for (size_t i = 0; i < netname.size(); i++) - if (netname[i] == ' ' || netname[i] == '\\') - netname.erase(netname.begin() + i--); - - if (keepmode) - { - *f << stringf(" (net %s (joined\n", EDIF_DEF(netname)); - - auto &refs = net_join_db.at(mapped_sig); - for (auto &ref : refs) - if (ref.second) - *f << stringf(" %s\n", ref.first.c_str()); - *f << stringf(" )"); - - if (attr_properties && raw_sig.wire != NULL) - for (auto &p : raw_sig.wire->attributes) - add_prop(p.first, p.second); - - *f << stringf("\n )\n"); - } - else - { - log_warning("Ignoring conflicting 'keep' property on net %s. Use -keep to generate the extra net nevertheless.\n", EDIF_DEF(netname)); - } - } - } - - *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 826876a8634..00000000000 --- 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 a2ac93abe3c..00000000000 --- 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 fdf100d3406..00000000000 --- 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 eb30ab4b948..00000000000 --- a/yosys/backends/firrtl/firrtl.cc +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 "kernel/mem.h" -#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 - -std::string getFileinfo(const RTLIL::AttrObject *design_entity) -{ - std::string src(design_entity->get_src_attribute()); - std::string fileinfo_str = src.empty() ? "" : "@[" + src + "]"; - return fileinfo_str; -} - -// 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(); -} - -std::string dump_const_string(const RTLIL::Const &data) -{ - std::string res_str; - - std::string str = data.decode_string(); - for (size_t i = 0; i < str.size(); i++) - { - if (str[i] == '\n') - res_str += "\\n"; - else if (str[i] == '\t') - res_str += "\\t"; - else if (str[i] < 32) - res_str += stringf("\\%03o", str[i]); - else if (str[i] == '"') - res_str += "\\\""; - else if (str[i] == '\\') - res_str += "\\\\"; - else - res_str += str[i]; - } - - return res_str; -} - -std::string dump_const(const RTLIL::Const &data) -{ - std::string res_str; - - // // For debugging purposes to find out how Yosys encodes flags. - // res_str += stringf("flags_%x --> ", data.flags); - - // Real-valued parameter. - if (data.flags & RTLIL::CONST_FLAG_REAL) - { - // Yosys stores real values as strings, so we call the string dumping code. - res_str += dump_const_string(data); - } - // String parameter. - else if (data.flags & RTLIL::CONST_FLAG_STRING) - { - res_str += "\""; - res_str += dump_const_string(data); - res_str += "\""; - } - // Numeric (non-real) parameter. - else - { - int width = data.bits.size(); - - // If a standard 32-bit int, then emit standard int value like "56" or - // "-56". Firrtl supports negative-valued int literals. - // - // SignedInt - // : ( '+' | '-' ) PosInt - // ; - if (width <= 32) - { - int32_t int_val = 0; - - for (int i = 0; i < width; i++) - { - switch (data.bits[i]) - { - case State::S0: break; - case State::S1: int_val |= (1 << i); break; - default: - log_error("Unexpected int value\n"); - break; - } - } - - res_str += stringf("%d", int_val); - } - else - { - // If value is larger than 32 bits, then emit a binary representation of - // the number as integers are not large enough to contain the result. - // There is a caveat to this approach though: - // - // Note that parameter may be defined as having a fixed width as follows: - // - // parameter signed [26:0] test_signed; - // parameter [26:0] test_unsigned; - // parameter signed [40:0] test_signed_large; - // - // However, if you assign a value on the RHS without specifying the - // precision, then yosys considers the value you used as an int and - // assigns it a width of 32 bits regardless of the type of the parameter. - // - // defparam .test_signed = 49; (width = 32, though should be 27 based on definition) - // defparam .test_unsigned = 40'd35; (width = 40, though should be 27 based on definition) - // defparam .test_signed_large = 40'd12; (width = 40) - // - // We therefore may lose the precision of the original verilog literal if - // it was written without its bitwidth specifier. - - // Emit binary prefix for string. - res_str += "\"b"; - - // Emit bits. - for (int i = width - 1; i >= 0; i--) - { - log_assert(i < width); - switch (data.bits[i]) - { - case State::S0: res_str += "0"; break; - case State::S1: res_str += "1"; break; - case State::Sx: res_str += "x"; break; - case State::Sz: res_str += "z"; break; - case State::Sa: res_str += "-"; break; - case State::Sm: res_str += "m"; break; - } - } - - res_str += "\""; - } - } - - return res_str; -} - -std::string extmodule_name(RTLIL::Cell *cell, RTLIL::Module *mod_instance) -{ - // Since we are creating a custom extmodule for every cell that instantiates - // this blackbox, we need to create a custom name for it. We just use the - // name of the blackbox itself followed by the name of the cell. - const std::string cell_name = std::string(make_id(cell->name)); - const std::string blackbox_name = std::string(make_id(mod_instance->name)); - const std::string extmodule_name = blackbox_name + "_" + cell_name; - return extmodule_name; -} - -/** - * Emits a parameterized extmodule. Instance parameters are obtained from - * ''cell'' as it represents the instantiation of the blackbox defined by - * ''mod_instance'' and therefore contains all its instance parameters. - */ -void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream &f) -{ - const std::string indent = " "; - - const std::string blackbox_name = std::string(make_id(mod_instance->name)); - const std::string exported_name = extmodule_name(cell, mod_instance); - - // We use the cell's fileinfo for this extmodule as its parameters come from - // the cell and not from the module itself (the module contains default - // parameters, not the instance-specific ones we're using to emit the - // extmodule). - const std::string extmoduleFileinfo = getFileinfo(cell); - - // Emit extmodule header. - f << stringf(" extmodule %s: %s\n", exported_name.c_str(), extmoduleFileinfo.c_str()); - - // Emit extmodule ports. - for (auto wire : mod_instance->wires()) - { - const auto wireName = make_id(wire->name); - const std::string wireFileinfo = getFileinfo(wire); - - if (wire->port_input && wire->port_output) - { - log_error("Module port %s.%s is inout!\n", log_id(mod_instance), log_id(wire)); - } - - const std::string portDecl = stringf("%s%s %s: UInt<%d> %s\n", - indent.c_str(), - wire->port_input ? "input" : "output", - wireName, - wire->width, - wireFileinfo.c_str() - ); - - f << portDecl; - } - - // Emit extmodule "defname" field. This is the name of the verilog blackbox - // that is used when verilog is emitted, so we use the name of mod_instance - // here. - f << stringf("%sdefname = %s\n", indent.c_str(), blackbox_name.c_str()); - - // Emit extmodule generic parameters. - for (const auto &p : cell->parameters) - { - const RTLIL::IdString p_id = p.first; - const RTLIL::Const p_value = p.second; - - std::string param_name(p_id.c_str()); - const std::string param_value = dump_const(p_value); - - // Remove backslashes from parameters as these come from the internal RTLIL - // naming scheme, but should not exist in the emitted firrtl blackboxes. - // When firrtl is converted to verilog and given to downstream synthesis - // tools, these tools expect to find blackbox names and parameters as they - // were originally defined, i.e. without the extra RTLIL naming conventions. - param_name.erase( - std::remove(param_name.begin(), param_name.end(), '\\'), - param_name.end() - ); - - f << stringf("%sparameter %s = %s\n", indent.c_str(), param_name.c_str(), param_value.c_str()); - } - - f << "\n"; -} - -/** - * Emits extmodules for every instantiated blackbox in the design. - * - * RTLIL stores instance parameters at the cell's instantiation location. - * However, firrtl does not support module parameterization (everything is - * already elaborated). Firrtl instead supports external modules (extmodule), - * i.e. blackboxes that are defined by verilog and which have no body in - * firrtl itself other than the declaration of the blackboxes ports and - * parameters. - * - * Furthermore, firrtl does not support parameterization (even of extmodules) - * at a module's instantiation location and users must instead declare - * different extmodules with different instance parameters in the extmodule - * definition itself. - * - * This function goes through the design to identify all RTLIL blackboxes - * and emit parameterized extmodules with a unique name for each of them. The - * name that's given to the extmodule is - * - * _ - * - * Beware that it is therefore necessary for users to replace "parameterized" - * instances in the RTLIL sense with these custom extmodules for the firrtl to - * be valid. - */ -void emit_elaborated_extmodules(RTLIL::Design *design, std::ostream &f) -{ - for (auto module : design->modules()) - { - for (auto cell : module->cells()) - { - // Is this cell a module instance? - bool cellIsModuleInstance = cell->type[0] != '$'; - - if (cellIsModuleInstance) - { - // Find the module corresponding to this instance. - auto modInstance = design->module(cell->type); - // Ensure that we actually have a module instance - if (modInstance == nullptr) { - log_error("Unknown cell type %s\n", cell->type.c_str()); - return; - } - - bool modIsBlackbox = modInstance->get_blackbox_attribute(); - - if (modIsBlackbox) - { - emit_extmodule(cell, modInstance, f); - } - } - } - } -} - -struct FirrtlWorker -{ - Module *module; - std::ostream &f; - - dict> reverse_wire_map; - string unconn_id; - RTLIL::Design *design; - std::string indent; - - 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.begins_with("$paramod")) - { - log_assert(cell->has_attribute(ID::hdlname)); - instanceOf = cell->get_string_attribute(ID::hdlname); - } - 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; - } - - // If the instance is that of a blackbox, use the modified extmodule name - // that contains per-instance parameterizations. These instances were - // emitted earlier in the firrtl backend. - const std::string instanceName = instModule->get_blackbox_attribute() ? - extmodule_name(cell, instModule) : - instanceOf; - - std::string cellFileinfo = getFileinfo(cell); - wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceName.c_str(), cellFileinfo.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)); - YS_FALLTHROUGH - 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)); - YS_FALLTHROUGH - 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.compare(0, bitsString.length(), bitsString) == 0) { - 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 %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.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_width) - { - string result = b_expr; - if (b_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), moduleFileinfo.c_str()); - vector port_decls, wire_decls, mem_exprs, cell_exprs, wire_exprs; - - std::vector memories = Mem::get_all_memories(module); - for (auto &mem : memories) - mem.narrow(); - - for (auto wire : module->wires()) - { - const auto wireName = make_id(wire->name); - std::string wireFileinfo = getFileinfo(wire); - - // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it. - if (wire->attributes.count(ID::init)) { - log_warning("Initial value (%s) for (%s.%s) not supported\n", - wire->attributes.at(ID::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 %s: UInt<%d> %s\n", indent.c_str(), wire->port_input ? "input" : "output", - wireName, wire->width, wireFileinfo.c_str())); - } - else - { - wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), wireName, wire->width, wireFileinfo.c_str())); - } - } - - for (auto cell : module->cells()) - { - Const ndef(0, 0); - - // Is this cell is a module instance? - if (module->design->module(cell->type)) - { - process_instance(cell, wire_exprs); - continue; - } - - // Not a module instance. Set up cell properties - bool extract_y_bits = false; // Assume no extraction of final bits will be required. - int a_width = cell->parameters.at(ID::A_WIDTH, ndef).as_int(); // The width of "A" - int b_width = cell->parameters.at(ID::B_WIDTH, ndef).as_int(); // The width of "A" - const int y_width = cell->parameters.at(ID::Y_WIDTH, ndef).as_int(); // The width of the result - const bool a_signed = cell->parameters.at(ID::A_SIGNED, ndef).as_bool(); - const bool b_signed = cell->parameters.at(ID::B_SIGNED, ndef).as_bool(); - bool firrtl_is_signed = a_signed; // The result is signed (subsequent code may change this). - int firrtl_width = 0; - string primop; - bool always_uint = false; - string y_id = make_id(cell->name); - std::string cellFileinfo = getFileinfo(cell); - - if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor))) - { - string a_expr = make_expr(cell->getPort(ID::A)); - wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str())); - - if (a_signed) { - a_expr = "asSInt(" + a_expr + ")"; - } - - // Don't use the results of logical operations (a single bit) to control padding - if (!(cell->type.in(ID($eq), ID($eqx), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($reduce_bool), ID($logic_not)) && y_width == 1) ) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); - } - - // Assume the FIRRTL width is a single bit. - firrtl_width = 1; - if (cell->type.in(ID($not), ID($_NOT_))) primop = "not"; - else if (cell->type == ID($neg)) { - primop = "neg"; - firrtl_is_signed = true; // Result of "neg" is signed (an SInt). - firrtl_width = a_width; - } else if (cell->type == ID($logic_not)) { - primop = "eq"; - a_expr = stringf("%s, UInt(0)", a_expr.c_str()); - } - else if (cell->type == ID($reduce_and)) primop = "andr"; - else if (cell->type == ID($reduce_or)) primop = "orr"; - else if (cell->type == ID($reduce_xor)) primop = "xorr"; - else if (cell->type == ID($reduce_xnor)) { - primop = "not"; - a_expr = stringf("xorr(%s)", a_expr.c_str()); - } - else if (cell->type == ID($reduce_bool)) { - primop = "neq"; - // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. - 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 ((firrtl_is_signed && !always_uint)) - expr = stringf("asUInt(%s)", expr.c_str()); - - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); - register_reverse_wire_map(y_id, cell->getPort(ID::Y)); - - continue; - } - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_), ID($eq), ID($eqx), - ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl), - ID($logic_and), ID($logic_or), ID($pow))) - { - string a_expr = make_expr(cell->getPort(ID::A)); - string b_expr = make_expr(cell->getPort(ID::B)); - std::string cellFileinfo = getFileinfo(cell); - wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str())); - - if (a_signed) { - a_expr = "asSInt(" + a_expr + ")"; - // Expand the "A" operand to the result width - if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); - a_width = y_width; - } - } - // Shift amount is always unsigned, and needn't be padded to result width, - // otherwise, we need to cast the b_expr appropriately - if (b_signed && !cell->type.in(ID($shr), ID($sshr), ID($shl), ID($sshl), ID($pow))) { - b_expr = "asSInt(" + b_expr + ")"; - // Expand the "B" operand to the result width - if (b_width < y_width) { - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); - b_width = y_width; - } - } - - // For the arithmetic ops, expand operand widths to result widths befor performing the operation. - // This corresponds (according to iverilog) to what verilog compilers implement. - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_))) - { - if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); - a_width = y_width; - } - if (b_width < y_width) { - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); - b_width = y_width; - } - } - // Assume the FIRRTL width is the width of "A" - firrtl_width = a_width; - auto a_sig = cell->getPort(ID::A); - - if (cell->type == ID($add)) { - primop = "add"; - firrtl_is_signed = a_signed | b_signed; - firrtl_width = max(a_width, b_width); - } else if (cell->type == ID($sub)) { - primop = "sub"; - firrtl_is_signed = true; - int a_widthInc = (!a_signed && b_signed) ? 2 : (a_signed && !b_signed) ? 1 : 0; - int b_widthInc = (a_signed && !b_signed) ? 2 : (!a_signed && b_signed) ? 1 : 0; - firrtl_width = max(a_width + a_widthInc, b_width + b_widthInc); - } else if (cell->type == ID($mul)) { - primop = "mul"; - firrtl_is_signed = a_signed | b_signed; - firrtl_width = a_width + b_width; - } else if (cell->type == ID($div)) { - primop = "div"; - firrtl_is_signed = a_signed | b_signed; - firrtl_width = a_width; - } else if (cell->type == ID($mod)) { - // "rem" = truncating modulo - primop = "rem"; - firrtl_width = min(a_width, b_width); - } else if (cell->type.in(ID($and), ID($_AND_))) { - primop = "and"; - always_uint = true; - firrtl_width = max(a_width, b_width); - } - else if (cell->type.in(ID($or), ID($_OR_))) { - primop = "or"; - always_uint = true; - firrtl_width = max(a_width, b_width); - } - else if (cell->type.in(ID($xor), ID($_XOR_))) { - primop = "xor"; - always_uint = true; - firrtl_width = max(a_width, b_width); - } - else if (cell->type == ID($xnor)) { - primop = "xnor"; - always_uint = true; - firrtl_width = max(a_width, b_width); - } - else if ((cell->type == ID($eq)) || (cell->type == ID($eqx))) { - primop = "eq"; - always_uint = true; - firrtl_width = 1; - } - else if ((cell->type == ID($ne)) || (cell->type == ID($nex))) { - primop = "neq"; - always_uint = true; - firrtl_width = 1; - } - else if (cell->type == ID($gt)) { - primop = "gt"; - always_uint = true; - firrtl_width = 1; - } - else if (cell->type == ID($ge)) { - primop = "geq"; - always_uint = true; - firrtl_width = 1; - } - else if (cell->type == ID($lt)) { - primop = "lt"; - always_uint = true; - firrtl_width = 1; - } - else if (cell->type == ID($le)) { - primop = "leq"; - always_uint = true; - firrtl_width = 1; - } - else if ((cell->type == ID($shl)) || (cell->type == ID($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(ID::B); - if (b_sig.is_fully_const()) { - primop = "shl"; - int shift_amount = b_sig.as_int(); - b_expr = std::to_string(shift_amount); - firrtl_width = a_width + shift_amount; - } else { - primop = "dshl"; - // Convert from FIRRTL left shift semantics. - b_expr = gen_dshl(b_expr, b_width); - firrtl_width = a_width + (1 << b_width) - 1; - } - } - else if ((cell->type == ID($shr)) || (cell->type == ID($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(ID::B); - if (b_sig.is_fully_const()) { - primop = "shr"; - int shift_amount = b_sig.as_int(); - b_expr = std::to_string(shift_amount); - firrtl_width = max(1, a_width - shift_amount); - } else { - primop = "dshr"; - firrtl_width = a_width; - } - // We'll need to do some special fixups if the source (and thus result) is signed. - if (firrtl_is_signed) { - // If this is a "logical" shift right, pretend the source is unsigned. - if (cell->type == ID($shr)) { - a_expr = "asUInt(" + a_expr + ")"; - } - } - } - else if ((cell->type == ID($logic_and))) { - primop = "and"; - a_expr = "neq(" + a_expr + ", UInt(0))"; - b_expr = "neq(" + b_expr + ", UInt(0))"; - always_uint = true; - firrtl_width = 1; - } - else if ((cell->type == ID($logic_or))) { - primop = "or"; - a_expr = "neq(" + a_expr + ", UInt(0))"; - b_expr = "neq(" + b_expr + ", UInt(0))"; - always_uint = true; - firrtl_width = 1; - } - else if ((cell->type == ID($pow))) { - if (a_sig.is_fully_const() && a_sig.as_int() == 2) { - // We'll convert this to a shift. To simplify things, change the a_expr to "1" - // so we can use b_expr directly as a shift amount. - // Only support 2 ** N (i.e., shift left) - // 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. - a_expr = firrtl_is_signed ? "SInt(1)" : "UInt(1)"; - extract_y_bits = true; - // Is the shift amount constant? - auto b_sig = cell->getPort(ID::B); - if (b_sig.is_fully_const()) { - primop = "shl"; - int shiftAmount = b_sig.as_int(); - if (shiftAmount < 0) { - log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, log_id(module), log_id(cell)); - } - b_expr = std::to_string(shiftAmount); - firrtl_width = a_width + shiftAmount; - } else { - primop = "dshl"; - // Convert from FIRRTL left shift semantics. - b_expr = gen_dshl(b_expr, b_width); - firrtl_width = a_width + (1 << b_width) - 1; - } - } else { - log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell)); - } - } - - auto it = cell->parameters.find(ID::B_SIGNED); - if (it == cell->parameters.end() || !it->second.as_bool()) { - b_expr = "asUInt(" + b_expr + ")"; - } - - string expr; - // Deal with $xnor == ~^ (not xor) - if (primop == "xnor") { - expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str()); - } else { - expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); - } - - // Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result. - // If the operation is signed, the FIRRTL width will be 1 one bit larger. - if (extract_y_bits) { - expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); - } else if (firrtl_is_signed && (firrtl_width + 1) < y_width) { - expr = stringf("pad(%s, %d)", expr.c_str(), y_width); - } - - if ((firrtl_is_signed && !always_uint)) - expr = stringf("asUInt(%s)", expr.c_str()); - - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); - register_reverse_wire_map(y_id, cell->getPort(ID::Y)); - - continue; - } - - if (cell->type.in(ID($mux), ID($_MUX_))) - { - auto it = cell->parameters.find(ID::WIDTH); - int width = it == cell->parameters.end()? 1 : it->second.as_int(); - string a_expr = make_expr(cell->getPort(ID::A)); - string b_expr = make_expr(cell->getPort(ID::B)); - string s_expr = make_expr(cell->getPort(ID::S)); - wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), width, cellFileinfo.c_str())); - - 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 <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); - register_reverse_wire_map(y_id, cell->getPort(ID::Y)); - - continue; - } - - if (cell->is_mem_cell()) - { - // Will be handled below, as part of a Mem. - continue; - } - - if (cell->type.in(ID($dff))) - { - bool clkpol = cell->parameters.at(ID::CLK_POLARITY).as_bool(); - if (clkpol == false) - log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell)); - - int width = cell->parameters.at(ID::WIDTH).as_int(); - string expr = make_expr(cell->getPort(ID::D)); - string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")"; - - wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent.c_str(), y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str())); - - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); - register_reverse_wire_map(y_id, cell->getPort(ID::Q)); - - continue; - } - - if (cell->type == ID($shiftx)) { - // assign y = a[b +: y_width]; - // We'll extract the correct bits as part of the primop. - - string a_expr = make_expr(cell->getPort(ID::A)); - // Get the initial bit selector - string b_expr = make_expr(cell->getPort(ID::B)); - wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); - - if (cell->getParam(ID::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(ID::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 <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, cell->getPort(ID::Y)); - continue; - } - if (cell->type == ID($shift)) { - // assign y = a >> b; - // where b may be negative - - string a_expr = make_expr(cell->getPort(ID::A)); - string b_expr = make_expr(cell->getPort(ID::B)); - auto b_string = b_expr.c_str(); - string expr; - wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); - - if (cell->getParam(ID::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_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 <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, cell->getPort(ID::Y)); - continue; - } - if (cell->type == ID($pos)) { - // assign y = a; -// printCell(cell); - string a_expr = make_expr(cell->getPort(ID::A)); - // Verilog appears to treat the result as signed, so if the result is wider than "A", - // we need to pad. - if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); - } - wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); - cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), a_expr.c_str())); - register_reverse_wire_map(y_id, cell->getPort(ID::Y)); - continue; - } - log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); - } - - for (auto &mem : memories) { - string mem_id = make_id(mem.memid); - - Const init_data = mem.get_init_data(); - if (!init_data.is_fully_undef()) - log_error("Memory with initialization data: %s.%s\n", log_id(module), log_id(mem.memid)); - - if (mem.start_offset != 0) - log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(mem.memid)); - - for (int i = 0; i < GetSize(mem.rd_ports); i++) - { - auto &port = mem.rd_ports[i]; - string port_name(stringf("%s.r%d", mem_id.c_str(), i)); - - if (port.clk_enable) - log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid)); - - std::ostringstream rpe; - - string addr_expr = make_expr(port.addr); - string ena_expr = make_expr(State::S1); - string clk_expr = make_expr(State::S0); - - rpe << stringf("%s%s.addr <= %s\n", indent.c_str(), port_name.c_str(), addr_expr.c_str()); - rpe << stringf("%s%s.en <= %s\n", indent.c_str(), port_name.c_str(), ena_expr.c_str()); - rpe << stringf("%s%s.clk <= asClock(%s)\n", indent.c_str(), port_name.c_str(), clk_expr.c_str()); - cell_exprs.push_back(rpe.str()); - register_reverse_wire_map(stringf("%s.data", port_name.c_str()), port.data); - } - - for (int i = 0; i < GetSize(mem.wr_ports); i++) - { - auto &port = mem.wr_ports[i]; - string port_name(stringf("%s.w%d", mem_id.c_str(), i)); - - if (!port.clk_enable) - log_error("Unclocked write port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid)); - if (!port.clk_polarity) - log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid)); - for (int i = 1; i < GetSize(port.en); i++) - if (port.en[0] != port.en[i]) - log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid)); - - std::ostringstream wpe; - - string data_expr = make_expr(port.data); - string addr_expr = make_expr(port.addr); - string ena_expr = make_expr(port.en[0]); - string clk_expr = make_expr(port.clk); - string mask_expr = make_expr(State::S1); - wpe << stringf("%s%s.data <= %s\n", indent.c_str(), port_name.c_str(), data_expr.c_str()); - wpe << stringf("%s%s.addr <= %s\n", indent.c_str(), port_name.c_str(), addr_expr.c_str()); - wpe << stringf("%s%s.en <= %s\n", indent.c_str(), port_name.c_str(), ena_expr.c_str()); - wpe << stringf("%s%s.clk <= asClock(%s)\n", indent.c_str(), port_name.c_str(), clk_expr.c_str()); - wpe << stringf("%s%s.mask <= %s\n", indent.c_str(), port_name.c_str(), mask_expr.c_str()); - - cell_exprs.push_back(wpe.str()); - } - - std::ostringstream me; - - me << stringf(" mem %s:\n", mem_id.c_str()); - me << stringf(" data-type => UInt<%d>\n", mem.width); - me << stringf(" depth => %d\n", mem.size); - for (int i = 0; i < GetSize(mem.rd_ports); i++) - me << stringf(" reader => r%d\n", i); - for (int i = 0; i < GetSize(mem.wr_ports); i++) - me << stringf(" writer => w%d\n", i); - me << stringf(" read-latency => %d\n", 0); - me << stringf(" write-latency => %d\n", 1); - me << stringf(" read-under-write => undefined\n"); - - mem_exprs.push_back(me.str()); - } - - 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("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); - cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str())); - register_reverse_wire_map(y_id, conn.first); - } - - for (auto wire : module->wires()) - { - string expr; - std::string wireFileinfo = getFileinfo(wire); - - 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("%swire %s: UInt<1> %s\n", indent.c_str(), unconn_id.c_str(), wireFileinfo.c_str())); - // `invalid` is a firrtl construction for simulation so we will not - // tag it with a @[fileinfo] tag as it doesn't directly correspond to - // a specific line of verilog code. - wire_decls.push_back(stringf("%s%s is invalid\n", indent.c_str(), unconn_id.c_str())); - } - wire_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), make_id(wire->name), expr.c_str(), wireFileinfo.c_str())); - } else { - if (make_unconn_id) { - unconn_id.clear(); - } - // `invalid` is a firrtl construction for simulation so we will not - // tag it with a @[fileinfo] tag as it doesn't directly correspond to - // a specific line of verilog code. - wire_decls.push_back(stringf("%s%s is invalid\n", indent.c_str(), make_id(wire->name))); - } - } - - for (auto str : port_decls) - f << str; - - f << stringf("\n"); - - for (auto str : wire_decls) - f << str; - - f << stringf("\n"); - - for (auto str : mem_exprs) - f << str; - - f << stringf("\n"); - - for (auto str : cell_exprs) - f << str; - - f << stringf("\n"); - - for (auto str : wire_exprs) - f << str; - - f << stringf("\n"); - } - - void run() - { - emit_module(); - } -}; - -struct FirrtlBackend : public Backend { - FirrtlBackend() : Backend("firrtl", "write design to a FIRRTL file") { } - void help() 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(" bmuxmap\n"); - log(" demuxmap\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) 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, "pmuxtree"); - Pass::call(design, "bmuxmap"); - Pass::call(design, "demuxmap"); - Pass::call(design, "bwmuxmap"); - - 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(ID::top)) { - top = module; - } - for (auto wire : module->wires()) - if (wire->port_id) - make_id(wire->name); - } - - if (top == nullptr) - top = last; - - if (!top) - log_cmd_error("There is no top module in this design!\n"); - - std::string circuitFileinfo = getFileinfo(top); - *f << stringf("circuit %s: %s\n", make_id(top->name), circuitFileinfo.c_str()); - - emit_elaborated_extmodules(design, *f); - - // Emit non-blackbox modules. - for (auto module : design->modules()) - { - if (!module->get_blackbox_attribute()) - { - 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 fe7e3a32912..00000000000 --- 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 c6d62a84726..00000000000 --- 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/intersynth/Makefile.inc b/yosys/backends/intersynth/Makefile.inc deleted file mode 100644 index 85df1b393a2..00000000000 --- 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 59173c4a2d4..00000000000 --- a/yosys/backends/intersynth/intersynth.cc +++ /dev/null @@ -1,217 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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() 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://bygone.clairexen.net/intersynth/\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) 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.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : "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 : design->modules()) - { - 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", log_id(module->name)); - continue; - } - - log("Generating netlist %s.\n", log_id(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", log_id(module->name)); - netlists_code += stringf("netlist %s\n", log_id(module->name)); - - // Module Ports: "std::set celltypes_code" prevents duplicate top level ports - for (auto wire : module->wires()) { - if (wire->port_input || wire->port_output) { - celltypes_code.insert(stringf("celltype !%s b%d %sPORT\n" "%s %s %d %s PORT\n", - log_id(wire->name), wire->width, wire->port_input ? "*" : "", - wire->port_input ? "input" : "output", log_id(wire->name), wire->width, log_id(wire->name))); - netlists_code += stringf("node %s %s PORT %s\n", log_id(wire->name), log_id(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 : module->cells()) - { - std::string celltype_code, node_code; - - if (!ct.cell_known(cell->type)) - log_error("Found unknown cell type %s in module!\n", log_id(cell->type)); - - celltype_code = stringf("celltype %s", log_id(cell->type)); - node_code = stringf("node %s %s", log_id(cell->name), log_id(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) ? "*" : "", log_id(port.first)); - node_code += stringf(" %s %s", log_id(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()), log_id(param.first)); - if (param.second.bits.size() != 32) { - node_code += stringf(" %s '", log_id(param.first)); - for (int i = param.second.bits.size()-1; i >= 0; i--) - node_code += param.second.bits[i] == State::S1 ? "1" : "0"; - } else - node_code += stringf(" %s 0x%x", log_id(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/jny/Makefile.inc b/yosys/backends/jny/Makefile.inc deleted file mode 100644 index 5e417128ed9..00000000000 --- a/yosys/backends/jny/Makefile.inc +++ /dev/null @@ -1,2 +0,0 @@ - -OBJS += backends/jny/jny.o diff --git a/yosys/backends/jny/jny.cc b/yosys/backends/jny/jny.cc deleted file mode 100644 index 0be11a52cca..00000000000 --- a/yosys/backends/jny/jny.cc +++ /dev/null @@ -1,578 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Aki "lethalbit" Van Ness - * - * 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 -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - - -struct JnyWriter -{ - private: - std::ostream &f; - bool _use_selection; - - // XXX(aki): TODO: this needs to be updated to us - // dict and then coalesce_cells needs to be updated - // but for now for the PoC this looks to be sufficient - std::unordered_map> _cells{}; - - bool _include_connections; - bool _include_attributes; - bool _include_properties; - - string escape_string(string str) { - std::string newstr; - - auto itr = str.begin(); - - for(; itr != str.end(); ++itr) { - switch (*itr) { - case '\\': { - newstr += "\\\\"; - break; - } case '\n': { - newstr += "\\n"; - break; - } case '\f': { - newstr += "\\f"; - break; - } case '\t': { - newstr += "\\t"; - break; - } case '\r': { - newstr += "\\r"; - break; - } case '\"': { - newstr += "\\\""; - break; - } case '\b': { - newstr += "\\b"; - break; - } default: { - newstr += *itr; - } - } - } - - return newstr; - } - - // XXX(aki): I know this is far from ideal but i'm out of spoons and cant focus so - // it'll have to do for now, - void coalesce_cells(Module* mod) - { - _cells.clear(); - for (auto cell : mod->cells()) { - const auto cell_type = escape_string(RTLIL::unescape_id(cell->type)); - - if (_cells.find(cell_type) == _cells.end()) - _cells.emplace(cell_type, std::vector()); - - _cells.at(cell_type).push_back(cell); - } - } - - // XXX(aki): this is a lazy way to do this i know,,, - std::string gen_indent(const uint16_t level) - { - std::stringstream s; - for (uint16_t i = 0; i <= level; ++i) - { - s << " "; - } - return s.str(); - } - - public: - JnyWriter(std::ostream &f, bool use_selection, bool connections, bool attributes, bool properties) noexcept: - f(f), _use_selection(use_selection), - _include_connections(connections), _include_attributes(attributes), _include_properties(properties) - { } - - void write_metadata(Design *design, uint16_t indent_level = 0, std::string invk = "") - { - log_assert(design != nullptr); - - design->sort(); - - f << "{\n"; - f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json\",\n"; - f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_version_str).c_str()); - f << " \"version\": \"0.0.1\",\n"; - f << " \"invocation\": \"" << escape_string(invk) << "\",\n"; - f << " \"features\": ["; - - size_t fnum{0}; - if (_include_connections) { - ++fnum; - f << "\"connections\""; - } - - if (_include_attributes) { - if (fnum > 0) - f << ", "; - ++fnum; - f << "\"attributes\""; - } - - if (_include_properties) { - if (fnum > 0) - f << ", "; - ++fnum; - f << "\"properties\""; - } - - f << "],\n"; - - f << " \"modules\": [\n"; - - bool first{true}; - for (auto mod : _use_selection ? design->selected_modules() : design->modules()) { - if (!first) - f << ",\n"; - write_module(mod, indent_level + 2); - first = false; - } - - f << "\n"; - f << " ]\n"; - f << "}\n"; - } - - void write_sigspec(const RTLIL::SigSpec& sig, uint16_t indent_level = 0) { - const auto _indent = gen_indent(indent_level); - - f << _indent << " {\n"; - f << _indent << " \"width\": \"" << sig.size() << "\",\n"; - f << _indent << " \"type\": \""; - - if (sig.is_wire()) { - f << "wire"; - } else if (sig.is_chunk()) { - f << "chunk"; - } else if (sig.is_bit()) { - f << "bit"; - } else { - f << "unknown"; - } - f << "\",\n"; - - f << _indent << " \"const\": "; - if (sig.has_const()) { - f << "true"; - } else { - f << "false"; - } - - f << "\n"; - - f << _indent << " }"; - } - - void write_mod_conn(const std::pair& conn, uint16_t indent_level = 0) { - const auto _indent = gen_indent(indent_level); - f << _indent << " {\n"; - f << _indent << " \"signals\": [\n"; - - write_sigspec(conn.first, indent_level + 2); - f << ",\n"; - write_sigspec(conn.second, indent_level + 2); - f << "\n"; - - f << _indent << " ]\n"; - f << _indent << " }"; - } - - void write_cell_conn(const std::pair& sig, uint16_t indent_level = 0) { - const auto _indent = gen_indent(indent_level); - f << _indent << " {\n"; - f << _indent << " \"name\": \"" << escape_string(RTLIL::unescape_id(sig.first)) << "\",\n"; - f << _indent << " \"signals\": [\n"; - - write_sigspec(sig.second, indent_level + 2); - f << "\n"; - - f << _indent << " ]\n"; - f << _indent << " }"; - } - - void write_module(Module* mod, uint16_t indent_level = 0) { - log_assert(mod != nullptr); - - coalesce_cells(mod); - - const auto _indent = gen_indent(indent_level); - - f << _indent << "{\n"; - f << stringf(" %s\"name\": \"%s\",\n", _indent.c_str(), escape_string(RTLIL::unescape_id(mod->name)).c_str()); - f << _indent << " \"cell_sorts\": [\n"; - - bool first_sort{true}; - for (auto& sort : _cells) { - if (!first_sort) - f << ",\n"; - write_cell_sort(sort, indent_level + 2); - first_sort = false; - } - f << "\n"; - - f << _indent << " ]"; - if (_include_connections) { - f << ",\n" << _indent << " \"connections\": [\n"; - - bool first_conn{true}; - for (const auto& conn : mod->connections()) { - if (!first_conn) - f << ",\n"; - - write_mod_conn(conn, indent_level + 2); - - first_conn = false; - } - - f << _indent << " ]"; - } - if (_include_attributes) { - f << ",\n" << _indent << " \"attributes\": {\n"; - - write_prams(mod->attributes, indent_level + 2); - - f << "\n"; - f << _indent << " }"; - } - f << "\n" << _indent << "}"; - } - - void write_cell_ports(RTLIL::Cell* port_cell, uint64_t indent_level = 0) { - const auto _indent = gen_indent(indent_level); - - bool first_port{true}; - for (auto con : port_cell->connections()) { - if (!first_port) - f << ",\n"; - - f << _indent << " {\n"; - f << stringf(" %s\"name\": \"%s\",\n", _indent.c_str(), escape_string(RTLIL::unescape_id(con.first)).c_str()); - f << _indent << " \"direction\": \""; - if (port_cell->input(con.first)) - f << "i"; - if (port_cell->input(con.first)) - f << "o"; - f << "\",\n"; - if (con.second.size() == 1) - f << _indent << " \"range\": [0, 0]\n"; - else - f << stringf(" %s\"range\": [%d, %d]\n", _indent.c_str(), con.second.size(), 0); - f << _indent << " }"; - - first_port = false; - } - f << "\n"; - } - - - void write_cell_sort(std::pair>& sort, uint16_t indent_level = 0) { - const auto port_cell = sort.second.front(); - const auto _indent = gen_indent(indent_level); - - f << _indent << "{\n"; - f << stringf(" %s\"type\": \"%s\",\n", _indent.c_str(), sort.first.c_str()); - f << _indent << " \"ports\": [\n"; - - write_cell_ports(port_cell, indent_level + 2); - - f << _indent << " ],\n" << _indent << " \"cells\": [\n"; - - bool first_cell{true}; - for (auto& cell : sort.second) { - if (!first_cell) - f << ",\n"; - - write_cell(cell, indent_level + 2); - - first_cell = false; - } - - f << "\n"; - f << _indent << " ]\n"; - f << _indent << "}"; - } - - void write_param_val(const Const& v) { - if ((v.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) == RTLIL::ConstFlags::CONST_FLAG_STRING) { - const auto str = v.decode_string(); - - // XXX(aki): TODO, uh, yeah - - f << "\"" << escape_string(str) << "\""; - } else if ((v.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) == RTLIL::ConstFlags::CONST_FLAG_SIGNED) { - f << stringf("\"%dsd %d\"", v.size(), v.as_int(true)); - } else if ((v.flags & RTLIL::ConstFlags::CONST_FLAG_REAL) == RTLIL::ConstFlags::CONST_FLAG_REAL) { - - } else { - f << "\"" << escape_string(v.as_string()) << "\""; - } - } - - void write_prams(dict& params, uint16_t indent_level = 0) { - const auto _indent = gen_indent(indent_level); - - bool first_param{true}; - for (auto& param : params) { - if (!first_param) - f << stringf(",\n"); - const auto param_val = param.second; - if (!param_val.empty()) { - f << stringf(" %s\"%s\": ", _indent.c_str(), escape_string(RTLIL::unescape_id(param.first)).c_str()); - write_param_val(param_val); - } else { - f << stringf(" %s\"%s\": true", _indent.c_str(), escape_string(RTLIL::unescape_id(param.first)).c_str()); - } - - first_param = false; - } - } - - void write_cell(Cell* cell, uint16_t indent_level = 0) { - const auto _indent = gen_indent(indent_level); - log_assert(cell != nullptr); - - f << _indent << " {\n"; - f << stringf(" %s\"name\": \"%s\"", _indent.c_str(), escape_string(RTLIL::unescape_id(cell->name)).c_str()); - - if (_include_connections) { - f << ",\n" << _indent << " \"connections\": [\n"; - - bool first_conn{true}; - for (const auto& conn : cell->connections()) { - if (!first_conn) - f << ",\n"; - - write_cell_conn(conn, indent_level + 2); - - first_conn = false; - } - - f << "\n"; - f << _indent << " ]"; - } - - if (_include_attributes) { - f << ",\n" << _indent << " \"attributes\": {\n"; - - write_prams(cell->attributes, indent_level + 2); - - f << "\n"; - f << _indent << " }"; - } - - if (_include_properties) { - f << ",\n" << _indent << " \"parameters\": {\n"; - - write_prams(cell->parameters, indent_level + 2); - - f << "\n"; - f << _indent << " }"; - } - - f << "\n" << _indent << " }"; - } -}; - -struct JnyBackend : public Backend { - JnyBackend() : Backend("jny", "generate design metadata") { } - void help() override { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" jny [options] [selection]\n"); - log("\n"); - log("Write JSON netlist metadata for the current design\n"); - log("\n"); - log(" -no-connections\n"); - log(" Don't include connection information in the netlist output.\n"); - log("\n"); - log(" -no-attributes\n"); - log(" Don't include attributed information in the netlist output.\n"); - log("\n"); - log(" -no-properties\n"); - log(" Don't include property information in the netlist output.\n"); - log("\n"); - log("The JSON schema for JNY output files is located in the \"jny.schema.json\" file\n"); - log("which is located at \"https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json\"\n"); - log("\n"); - } - - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { - - bool connections{true}; - bool attributes{true}; - bool properties{true}; - - size_t argidx{1}; - for (; argidx < args.size(); argidx++) { - if (args[argidx] == "-no-connections") { - connections = false; - continue; - } - - if (args[argidx] == "-no-attributes") { - attributes = false; - continue; - } - - if (args[argidx] == "-no-properties") { - properties = false; - continue; - } - - break; - } - - // Compose invocation line - std::ostringstream invk; - if (!args.empty()) { - std::copy(args.begin(), args.end(), - std::ostream_iterator(invk, " ") - ); - } - invk << filename; - - extra_args(f, filename, args, argidx); - - log_header(design, "Executing jny backend.\n"); - - JnyWriter jny_writer(*f, false, connections, attributes, properties); - jny_writer.write_metadata(design, 0, invk.str()); - } - -} JnyBackend; - - -struct JnyPass : public Pass { - JnyPass() : Pass("jny", "write design and metadata") { } - - void help() override { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" jny [options] [selection]\n"); - log("\n"); - log("Write JSON netlist metadata for the current design\n"); - log("\n"); - log(" -o \n"); - log(" write to the specified file.\n"); - log("\n"); - log(" -no-connections\n"); - log(" Don't include connection information in the netlist output.\n"); - log("\n"); - log(" -no-attributes\n"); - log(" Don't include attributed information in the netlist output.\n"); - log("\n"); - log(" -no-properties\n"); - log(" Don't include property information in the netlist output.\n"); - log("\n"); - log("See 'help write_jny' for a description of the JSON format used.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) override { - std::string filename{}; - - bool connections{true}; - bool attributes{true}; - bool properties{true}; - - size_t argidx{1}; - for (; argidx < args.size(); argidx++) { - if (args[argidx] == "-o" && argidx+1 < args.size()) { - filename = args[++argidx]; - continue; - } - - if (args[argidx] == "-no-connections") { - connections = false; - continue; - } - - if (args[argidx] == "-no-attributes") { - attributes = false; - continue; - } - - if (args[argidx] == "-no-properties") { - properties = false; - continue; - } - - break; - } - - // Compose invocation line - std::ostringstream invk; - if (!args.empty()) { - std::copy(args.begin(), args.end(), - std::ostream_iterator(invk, " ") - ); - } - - extra_args(args, argidx, design); - - std::ostream *f; - std::stringstream buf; - bool empty = filename.empty(); - - if (!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; - invk << filename; - } else { - f = &buf; - } - - - JnyWriter jny_writer(*f, false, connections, attributes, properties); - jny_writer.write_metadata(design, 0, invk.str()); - - if (!empty) { - delete f; - } else { - log("%s", buf.str().c_str()); - } - } - -} JnyPass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/json/Makefile.inc b/yosys/backends/json/Makefile.inc deleted file mode 100644 index a463daf9147..00000000000 --- 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 fd2c922fd5d..00000000000 --- a/yosys/backends/json/json.cc +++ /dev/null @@ -1,695 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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; - bool compat_int_mode; - - Design *design; - Module *module; - - SigMap sigmap; - int sigidcounter; - dict sigids; - pool aig_models; - - JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode) : - f(f), use_selection(use_selection), aig_mode(aig_mode), - compat_int_mode(compat_int_mode) { } - - string get_string(string str) - { - string newstr = "\""; - for (char c : str) { - if (c == '\\') - newstr += "\\\\"; - else if (c == '"') - newstr += "\\\""; - else if (c == '\b') - newstr += "\\b"; - else if (c == '\f') - newstr += "\\f"; - else if (c == '\n') - newstr += "\\n"; - else if (c == '\r') - newstr += "\\r"; - else if (c == '\t') - newstr += "\\t"; - else if (c < 0x20) - newstr += stringf("\\u%04X", c); - else - 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_parameter_value(const Const &value) - { - if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) { - string str = value.decode_string(); - int state = 0; - for (char c : str) { - if (state == 0) { - if (c == '0' || c == '1' || c == 'x' || c == 'z') - state = 0; - else if (c == ' ') - state = 1; - else - state = 2; - } else if (state == 1 && c != ' ') - state = 2; - } - if (state < 2) - str += " "; - f << get_string(str); - } else if (compat_int_mode && GetSize(value) <= 32 && value.is_fully_def()) { - if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) - f << stringf("%d", value.as_int()); - else - f << stringf("%u", value.as_int()); - } else { - f << get_string(value.as_string()); - } - } - - 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()); - write_parameter_value(param.second); - 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; - - if (module->has_processes()) { - log_error("Module %s contains processes, which are not supported by JSON backend (run `proc` first).\n", log_id(module)); - } - - f << stringf(" %s: {\n", get_name(module->name).c_str()); - - f << stringf(" \"attributes\": {"); - write_parameters(module->attributes, /*for_module=*/true); - f << stringf("\n },\n"); - - if (module->parameter_default_values.size()) { - f << stringf(" \"parameter_default_values\": {"); - write_parameters(module->parameter_default_values, /*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"); - if (w->is_signed) - f << stringf(" \"signed\": %d,\n", w->is_signed); - 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"); - - if (!module->memories.empty()) { - f << stringf(" \"memories\": {"); - first = true; - for (auto &it : module->memories) { - if (use_selection && !module->selected(it.second)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(it.second->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", it.second->name[0] == '$' ? "1" : "0"); - f << stringf(" \"attributes\": {"); - write_parameters(it.second->attributes); - f << stringf("\n },\n"); - f << stringf(" \"width\": %d,\n", it.second->width); - f << stringf(" \"start_offset\": %d,\n", it.second->start_offset); - f << stringf(" \"size\": %d\n", it.second->size); - 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"); - if (w->is_signed) - f << stringf(" \"signed\": %d,\n", w->is_signed); - 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() 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(" -compat-int\n"); - log(" emit 32-bit or smaller fully-defined parameter values directly\n"); - log(" as JSON numbers (for compatibility with old parsers)\n"); - log("\n"); - log("\n"); - log("The general syntax of the JSON output created by this command is as follows:\n"); - log("\n"); - log(" {\n"); - log(" \"creator\": \"Yosys \",\n"); - log(" \"modules\": {\n"); - log(" : {\n"); - log(" \"attributes\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"parameter_default_values\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"ports\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"cells\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"memories\": {\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(" \"offset\": \n"); - log(" \"upto\": <1 if the port bit indexing is MSB-first>\n"); - log(" \"signed\": <1 if the port is signed>\n"); - log(" }\n"); - log("\n"); - log("The \"offset\" and \"upto\" fields are skipped if their value would be 0.\n"); - log("They don't affect connection semantics, and are only used to preserve original\n"); - log("HDL bit indexing."); - log("And is:\n"); - log("\n"); - log(" {\n"); - log(" \"hide_name\": <1 | 0>,\n"); - log(" \"type\": ,\n"); - log(" \"model\": ,\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(" \"attributes\": {\n"); - log(" : ,\n"); - log(" ...\n"); - log(" },\n"); - log(" \"width\": \n"); - log(" \"start_offset\": \n"); - log(" \"size\": \n"); - log(" }\n"); - log("\n"); - log("And is:\n"); - log("\n"); - log(" {\n"); - log(" \"hide_name\": <1 | 0>,\n"); - log(" \"bits\": \n"); - log(" \"offset\": \n"); - log(" \"upto\": <1 if the port bit indexing is MSB-first>\n"); - log(" \"signed\": <1 if the port is signed>\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\", \"1\", \"x\", or\n"); - log("\"z\" instead of a number.\n"); - log("\n"); - log("Bit vectors (including integers) are written as string holding the binary\n"); - log("representation of the value. Strings are written as strings, with an appended\n"); - log("blank in cases of strings of the form /[01xz]* */.\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(" \"creator\": \"Yosys 0.9+2406 (git sha1 fb1168d8, clang 9.0.1 -fPIC -Os)\",\n"); - log(" \"modules\": {\n"); - log(" \"test\": {\n"); - log(" \"attributes\": {\n"); - log(" \"cells_not_processed\": \"00000000000000000000000000000001\",\n"); - log(" \"src\": \"test.v:1.1-4.10\"\n"); - log(" },\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(" \"P\": \"00000000000000000000000000101010\",\n"); - log(" \"Q\": \"00000000000000000000010100111001\"\n"); - log(" },\n"); - log(" \"attributes\": {\n"); - log(" \"keep\": \"00000000000000000000000000000001\",\n"); - log(" \"module_not_derived\": \"00000000000000000000000000000001\",\n"); - log(" \"src\": \"test.v:3.1-3.55\"\n"); - log(" },\n"); - log(" \"connections\": {\n"); - log(" \"A\": [ 3, 2 ],\n"); - log(" \"B\": [ 2, 3 ],\n"); - log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ]\n"); - log(" }\n"); - log(" }\n"); - log(" },\n"); - log(" \"netnames\": {\n"); - log(" \"x\": {\n"); - log(" \"hide_name\": 0,\n"); - log(" \"bits\": [ 2 ],\n"); - log(" \"attributes\": {\n"); - log(" \"src\": \"test.v:1.19-1.20\"\n"); - log(" }\n"); - log(" },\n"); - log(" \"y\": {\n"); - log(" \"hide_name\": 0,\n"); - log(" \"bits\": [ 3 ],\n"); - log(" \"attributes\": {\n"); - log(" \"src\": \"test.v:1.22-1.23\"\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) override - { - bool aig_mode = false; - bool compat_int_mode = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-aig") { - aig_mode = true; - continue; - } - if (args[argidx] == "-compat-int") { - compat_int_mode = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - log_header(design, "Executing JSON backend.\n"); - - JsonWriter json_writer(*f, false, aig_mode, compat_int_mode); - json_writer.write_design(design); - } -} JsonBackend; - -struct JsonPass : public Pass { - JsonPass() : Pass("json", "write design in JSON format") { } - void help() 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(" -compat-int\n"); - log(" emit 32-bit or smaller fully-defined parameter values directly\n"); - log(" as JSON numbers (for compatibility with old parsers)\n"); - log("\n"); - log("See 'help write_json' for a description of the JSON format used.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - std::string filename; - bool aig_mode = false; - bool compat_int_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] == "-compat-int") { - compat_int_mode = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - std::ostream *f; - std::stringstream buf; - bool empty = filename.empty(); - - if (!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, compat_int_mode); - json_writer.write_design(design); - - if (!empty) { - delete f; - } else { - log("%s", buf.str().c_str()); - } - } -} JsonPass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/rtlil/Makefile.inc b/yosys/backends/rtlil/Makefile.inc deleted file mode 100644 index f691282ca16..00000000000 --- a/yosys/backends/rtlil/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/rtlil/rtlil_backend.o - diff --git a/yosys/backends/rtlil/rtlil_backend.cc b/yosys/backends/rtlil/rtlil_backend.cc deleted file mode 100644 index 574eb3aaad1..00000000000 --- a/yosys/backends/rtlil/rtlil_backend.cc +++ /dev/null @@ -1,558 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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. - * - */ - -#include "rtlil_backend.h" -#include "kernel/yosys.h" -#include - -USING_YOSYS_NAMESPACE -using namespace RTLIL_BACKEND; -YOSYS_NAMESPACE_BEGIN - -void RTLIL_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 State::S0: break; - case State::S1: val |= 1 << i; break; - default: val = -1; break; - } - } - if (val >= 0) { - f << stringf("%d", val); - return; - } - } - f << stringf("%d'", width); - if (data.is_fully_undef_x_only()) { - f << "x"; - } else { - for (int i = offset+width-1; i >= offset; i--) { - log_assert(i < (int)data.bits.size()); - switch (data.bits[i]) { - case State::S0: f << stringf("0"); break; - case State::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", (unsigned char)str[i]); - else if (str[i] == '"') - f << stringf("\\\""); - else if (str[i] == '\\') - f << stringf("\\\\"); - else - f << str[i]; - } - f << stringf("\""); - } -} - -void RTLIL_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 RTLIL_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 RTLIL_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); - if (wire->is_signed) - f << stringf("signed "); - f << stringf("%s\n", wire->name.c_str()); -} - -void RTLIL_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 RTLIL_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 RTLIL_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 RTLIL_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 RTLIL_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) { - f << stringf("%s update ", indent.c_str()); - dump_sigspec(f, it.first); - f << stringf(" "); - dump_sigspec(f, it.second); - f << stringf("\n"); - } - - for (auto &it: sy->mem_write_actions) { - for (auto it2 = it.attributes.begin(); it2 != it.attributes.end(); ++it2) { - f << stringf("%s attribute %s ", indent.c_str(), it2->first.c_str()); - dump_const(f, it2->second); - f << stringf("\n"); - } - f << stringf("%s memwr %s ", indent.c_str(), it.memid.c_str()); - dump_sigspec(f, it.address); - f << stringf(" "); - dump_sigspec(f, it.data); - f << stringf(" "); - dump_sigspec(f, it.enable); - f << stringf(" "); - dump_const(f, it.priority_mask); - f << stringf("\n"); - } -} - -void RTLIL_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 RTLIL_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 RTLIL_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 (const auto &p : module->avail_parameters) { - const auto &it = module->parameter_default_values.find(p); - if (it == module->parameter_default_values.end()) { - f << stringf("%s" " parameter %s\n", indent.c_str(), p.c_str()); - } else { - f << stringf("%s" " parameter %s ", indent.c_str(), p.c_str()); - dump_const(f, it->second); - f << stringf("\n"); - } - } - } - } - - 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 || design->selected_whole_module(module->name); - if (!show_conn) { - 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 RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n) -{ - int init_autoidx = autoidx; - - if (!flag_m) { - int count_selected_mods = 0; - for (auto module : design->modules()) { - if (design->selected_whole_module(module->name)) - flag_m = true; - if (design->selected(module)) - 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 module : design->modules()) { - if (!only_selected || design->selected(module)) { - if (only_selected) - f << stringf("\n"); - dump_module(f, "", module, design, only_selected, flag_m, flag_n); - } - } - - log_assert(init_autoidx == autoidx); -} - -YOSYS_NAMESPACE_END -PRIVATE_NAMESPACE_BEGIN - -struct RTLILBackend : public Backend { - RTLILBackend() : Backend("rtlil", "write design to RTLIL file") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" write_rtlil [filename]\n"); - log("\n"); - log("Write the current design to an RTLIL file. (RTLIL 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) override - { - bool selected = false; - - log_header(design, "Executing RTLIL 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); - RTLIL_BACKEND::dump_design(*f, design, selected, true, false); - } -} RTLILBackend; - -struct IlangBackend : public Backend { - IlangBackend() : Backend("ilang", "(deprecated) alias of write_rtlil") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log("See `help write_rtlil`.\n"); - log("\n"); - } - void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override - { - RTLILBackend.execute(f, filename, args, design); - } -} IlangBackend; - -struct DumpPass : public Pass { - DumpPass() : Pass("dump", "print parts of the design in RTLIL format") { } - void help() 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("RTLIL 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) 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; - bool empty = filename.empty(); - - if (!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; - } - - RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n); - - if (!empty) { - delete f; - } else { - log("%s", buf.str().c_str()); - } - } -} DumpPass; - -PRIVATE_NAMESPACE_END diff --git a/yosys/backends/rtlil/rtlil_backend.h b/yosys/backends/rtlil/rtlil_backend.h deleted file mode 100644 index 35829729c56..00000000000 --- a/yosys/backends/rtlil/rtlil_backend.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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. - * - */ - -#ifndef RTLIL_BACKEND_H -#define RTLIL_BACKEND_H - -#include "kernel/yosys.h" -#include - -YOSYS_NAMESPACE_BEGIN - -namespace RTLIL_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/simplec/.gitignore b/yosys/backends/simplec/.gitignore deleted file mode 100644 index f08796168f6..00000000000 --- 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 fee1376c569..00000000000 --- 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 e283dcf7c17..00000000000 --- a/yosys/backends/simplec/simplec.cc +++ /dev/null @@ -1,812 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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(ID($_BUF_), ID($_NOT_))) - { - SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A)); - SigBit y = sigmaps.at(work->module)(cell->getPort(ID::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 == ID($_BUF_)) expr = a_expr; - if (cell->type == ID($_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(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) - { - SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A)); - SigBit b = sigmaps.at(work->module)(cell->getPort(ID::B)); - SigBit y = sigmaps.at(work->module)(cell->getPort(ID::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 == ID($_AND_)) expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_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(ID($_AOI3_), ID($_OAI3_))) - { - SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A)); - SigBit b = sigmaps.at(work->module)(cell->getPort(ID::B)); - SigBit c = sigmaps.at(work->module)(cell->getPort(ID::C)); - SigBit y = sigmaps.at(work->module)(cell->getPort(ID::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 == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); - if (cell->type == ID($_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(ID($_AOI4_), ID($_OAI4_))) - { - SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A)); - SigBit b = sigmaps.at(work->module)(cell->getPort(ID::B)); - SigBit c = sigmaps.at(work->module)(cell->getPort(ID::C)); - SigBit d = sigmaps.at(work->module)(cell->getPort(ID::D)); - SigBit y = sigmaps.at(work->module)(cell->getPort(ID::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 == ID($_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 == ID($_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.in(ID($_MUX_), ID($_NMUX_))) - { - SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A)); - SigBit b = sigmaps.at(work->module)(cell->getPort(ID::B)); - SigBit s = sigmaps.at(work->module)(cell->getPort(ID::S)); - SigBit y = sigmaps.at(work->module)(cell->getPort(ID::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 ? %s(bool)%s : %s(bool)%s", s_expr.c_str(), - cell->type == ID($_NMUX_) ? "!" : "", b_expr.c_str(), - cell->type == ID($_NMUX_) ? "!" : "", 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(ID::init)) - { - SigSpec sig = sigmaps.at(module)(w); - Const val = w->attributes.at(ID::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() 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) 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 ede75727378..00000000000 --- 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 7fac4826563..00000000000 --- 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 92329a6f94c..00000000000 --- 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 313ea0a1aac..00000000000 --- 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 3afe990e769..00000000000 --- a/yosys/backends/smt2/Makefile.inc +++ /dev/null @@ -1,46 +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 += $(PROGRAM_PREFIX)yosys-smtbmc.exe $(PROGRAM_PREFIX)yosys-smtbmc-script.py -TARGETS += $(PROGRAM_PREFIX)yosys-witness.exe $(PROGRAM_PREFIX)yosys-witness-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) - -$(PROGRAM_PREFIX)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/$(PROGRAM_PREFIX)yosys/python3"]]|;' \ - -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ - -$(PROGRAM_PREFIX)yosys-witness-script.py: backends/smt2/witness.py - $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' \ - -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ - -$(PROGRAM_PREFIX)yosys-smtbmc.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-smtbmc-script.py - $(P) $(CXX) -DGUI=0 -O -s -o $@ $< - -$(PROGRAM_PREFIX)yosys-witness.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-witness-script.py - $(P) $(CXX) -DGUI=0 -O -s -o $@ $< -# Other targets -else -TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc $(PROGRAM_PREFIX)yosys-witness - -$(PROGRAM_PREFIX)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/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new - $(Q) chmod +x $@.new - $(Q) mv $@.new $@ - -$(PROGRAM_PREFIX)yosys-witness: backends/smt2/witness.py - $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new - $(Q) chmod +x $@.new - $(Q) mv $@.new $@ -endif - -$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py)) -$(eval $(call add_share_file,share/python3,backends/smt2/ywio.py)) -endif -endif diff --git a/yosys/backends/smt2/example.v b/yosys/backends/smt2/example.v deleted file mode 100644 index b195266eb7e..00000000000 --- 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 6fccb344f38..00000000000 --- 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 index 48da3f4be57..7b48be29902 100644 --- a/yosys/backends/smt2/smt2.cc +++ b/yosys/backends/smt2/smt2.cc @@ -626,9 +626,13 @@ struct Smt2Worker } bool init_only = cell->type.in(ID($anyconst), ID($anyinit), ID($allconst)); - for (auto chunk : cell->getPort(QY).chunks()) + bool clk2fflogic = cell->type == ID($anyinit) && cell->get_bool_attribute(ID(clk2fflogic)); + int smtoffset = 0; + for (auto chunk : cell->getPort(clk2fflogic ? ID::D : QY).chunks()) { if (chunk.is_wire()) - decls.push_back(witness_signal(init_only ? "init" : "seq", chunk.width, chunk.offset, "", idcounter, chunk.wire)); + decls.push_back(witness_signal(init_only ? "init" : "seq", chunk.width, chunk.offset, "", idcounter, chunk.wire, smtoffset)); + smtoffset += chunk.width; + } makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(QY)), log_signal(cell->getPort(QY))); if (cell->type == ID($anyseq)) diff --git a/yosys/backends/smt2/smtbmc.py b/yosys/backends/smt2/smtbmc.py deleted file mode 100644 index cb21eb3aa4b..00000000000 --- a/yosys/backends/smt2/smtbmc.py +++ /dev/null @@ -1,1947 +0,0 @@ -#!/usr/bin/env python3 -# -# yosys -- Yosys Open SYnthesis Suite -# -# Copyright (C) 2012 Claire Xenia 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, bisect -##yosys-sys-path## -from smtio import SmtIo, SmtOpts, MkVcd -from ywio import ReadWitness, WriteWitness, WitnessValues -from collections import defaultdict - -got_topt = False -skip_steps = 0 -step_size = 1 -num_steps = 20 -append_steps = 0 -vcdfile = None -inywfile = None -outywfile = 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 -binarymode = False -keep_going = False -check_witness = False -detect_loops = False -so = SmtOpts() - - -def usage(): - print(os.path.basename(sys.argv[0]) + """ [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. - - --yw - read a Yosys witness. - - --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-yw - write trace as a Yosys witness trace - - --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 replaced 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) - - --binary - dump anyconst values as raw bit strings - - --keep-going - continue BMC after the first failed assertion and report - further failed assertions. To output multiple traces - covering all found failed assertions, the character '%' is - replaced in all dump filenames with an increasing number. - - --check-witness - check that the used witness file contains sufficient - constraints to force an assertion failure. - - --detect-loops - check if states are unique in temporal induction counter examples - (this feature is experimental and incomplete) - -""" + 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", "yw=", "btorwit=", "presat", - "dump-vcd=", "dump-yw=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=", - "smtc-init", "smtc-top=", "noinit", "binary", "keep-going", "check-witness", "detect-loops"]) -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 == "--yw": - inywfile = a - elif o == "--btorwit": - btorwitfile = a - elif o == "--dump-vcd": - vcdfile = a - elif o == "--dump-yw": - outywfile = 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 o == "--binary": - binarymode = True - elif o == "--keep-going": - keep_going = True - elif o == "--check-witness": - check_witness = True - elif o == "--detect-loops": - detect_loops = True - 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, individual=False): - if final: - if ("final-%d" % state) not in db: - return ([], [], []) if getvalues or individual else "true" - else: - if state not in db: - return ([], [], []) if getvalues or individual 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 or individual: - expr_list.append((loc, expr, actual_expr)) - else: - expr_list.append(actual_expr) - - if getvalues or individual: - loc_list, expr_list, actual_expr_list = zip(*expr_list) - if individual: - return loc_list, expr_list, actual_expr_list - else: - value_list = smt.get_list(actual_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: - 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: - if not check_witness: - 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: - 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: - if not check_witness: - skip_steps = max(skip_steps, step) - # some solvers optimize the properties so that they fail one cycle early, - # thus we check the properties in the cycle the aiger witness ends, and - # if that doesn't work, we check the cycle after that as well. - num_steps = max(num_steps, step+2) - step += 1 - -if inywfile is not None: - if not got_topt: - skip_steps = 0 - num_steps = 0 - - with open(inywfile, "r") as f: - inyw = ReadWitness(f) - - inits, seqs, clocks, mems = smt.hierwitness(topmod, allregs=True, blackbox=True) - - smt_wires = defaultdict(list) - smt_mems = defaultdict(list) - - for wire in inits + seqs: - smt_wires[wire["path"]].append(wire) - - for mem in mems: - smt_mems[mem["path"]].append(mem) - - addr_re = re.compile(r'\\\[[0-9]+\]$') - bits_re = re.compile(r'[01?]*$') - - for t, step in inyw.steps(): - present_signals, missing = step.present_signals(inyw.sigmap) - for sig in present_signals: - bits = step[sig] - if not bits_re.match(bits): - raise ValueError("unsupported bit value in Yosys witness file") - - sig_end = sig.offset + len(bits) - if sig.path in smt_wires: - for wire in smt_wires[sig.path]: - width, offset = wire["width"], wire["offset"] - - smt_bool = smt.net_width(topmod, wire["smtpath"]) == 1 - - offset = max(offset, 0) - - end = width + offset - common_offset = max(sig.offset, offset) - common_end = min(sig_end, end) - if common_end <= common_offset: - continue - - smt_expr = smt.witness_net_expr(topmod, f"s{t}", wire) - - if not smt_bool: - slice_high = common_end - offset - 1 - slice_low = common_offset - offset - smt_expr = "((_ extract %d %d) %s)" % (slice_high, slice_low, smt_expr) - - bit_slice = bits[len(bits) - (common_end - sig.offset):len(bits) - (common_offset - sig.offset)] - - if bit_slice.count("?") == len(bit_slice): - continue - - if smt_bool: - assert width == 1 - smt_constr = "(= %s %s)" % (smt_expr, "true" if bit_slice == "1" else "false") - else: - if "?" in bit_slice: - mask = bit_slice.replace("0", "1").replace("?", "0") - bit_slice = bit_slice.replace("?", "0") - smt_expr = "(bvand %s #b%s)" % (smt_expr, mask) - - smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice) - - constr_assumes[t].append((inywfile, smt_constr)) - - if sig.memory_path: - if sig.memory_path in smt_mems: - for mem in smt_mems[sig.memory_path]: - width, size, bv = mem["width"], mem["size"], mem["statebv"] - - smt_expr = smt.net_expr(topmod, f"s{t}", mem["smtpath"]) - - if bv: - word_low = sig.memory_addr * width - word_high = word_low + width - 1 - smt_expr = "((_ extract %d %d) %s)" % (word_high, word_low, smt_expr) - else: - addr_width = (size - 1).bit_length() - addr_bits = f"{sig.memory_addr:0{addr_width}b}" - smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits) - - if len(bits) < width: - slice_high = sig.offset + len(bits) - 1 - smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr) - - bit_slice = bits - - if "?" in bit_slice: - mask = bit_slice.replace("0", "1").replace("?", "0") - bit_slice = bit_slice.replace("?", "0") - smt_expr = "(bvand %s #b%s)" % (smt_expr, mask) - - smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice) - constr_assumes[t].append((inywfile, smt_constr)) - - if not got_topt: - if not check_witness: - skip_steps = max(skip_steps, t) - num_steps = max(num_steps, t+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 collect_mem_trace_data(steps_start, steps_stop, vcd=None): - 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 ii in reversed(range(len(tdata))): - for k in range(width): - if tdata[ii][k] == "x": - tdata[ii][k] = buf[k] - else: - buf[k] = tdata[ii][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) - - int_addr = int(addr, 2) - - netpath = mempath[:] - if vcd: - netpath[-1] += "<%0*x>" % ((len(addr)+3) // 4, int_addr) - 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, int_addr, "".join(tdata[i-steps_start]))) - - return mem_trace_data - -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 = collect_mem_trace_data(steps_start, steps_stop, vcd) - - 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, addr, value in mem_trace_data[i]: - vcd.set_net([topmod] + path, value) - - vcd.set_time(steps_stop) - -def detect_state_loop(steps_start, steps_stop): - print_msg(f"Checking for loops in found induction counter example") - print_msg(f"This feature is experimental and incomplete") - - path_list = sorted(smt.hiernets(topmod, regs_only=True)) - - mem_trace_data = collect_mem_trace_data(steps_start, steps_stop) - - # Map state to index of step when it occurred - states = dict() - - for i in range(steps_start, steps_stop): - value_list = smt.get_net_bin_list(topmod, path_list, "s%d" % i) - mem_state = sorted( - [(tuple(path), addr, data) - for path, addr, data in mem_trace_data.get(i, [])]) - state = tuple(value_list), tuple(mem_state) - if state in states: - return (i, states[state]) - else: - states[state] = i - - return None - -def char_ok_in_verilog(c,i): - if ('A' <= c <= 'Z'): return True - if ('a' <= c <= 'z'): return True - if ('0' <= c <= '9' and i>0): return True - if (c == '_'): return True - if (c == '$'): return True - return False - -def escape_identifier(identifier): - if type(identifier) is list: - return map(escape_identifier, identifier) - if "." in identifier: - return ".".join(escape_identifier(identifier.split("."))) - if (all(char_ok_in_verilog(identifier[i],i) for i in range(0, len(identifier)))): - return identifier - return "\\"+identifier+" " - - - -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] %s = clock;" % (width-1, escape_identifier("PI_"+name)), file=f) - else: - print(" reg [%d:0] %s;" % (width-1, escape_identifier("PI_"+name)), file=f) - - print(" %s UUT (" % escape_identifier(vlogtb_topmod), file=f) - print(",\n".join(" .%s(%s)" % (escape_identifier(name), escape_identifier("PI_"+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(escape_identifier(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(escape_identifier(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(escape_identifier(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(" %s <= %d'b%s;" % (escape_identifier("PI_"+".".join(name)), len(val), val), file=f) - else: - print(" %s = %d'b%s;" % (escape_identifier("PI_"+".".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(escape_identifier(info[0] + [info[3]])), len(value), value), file=f); - else: - print(" UUT.%s = %d'b%s;" % (".".join(escape_identifier(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_yw_trace(steps_start, steps_stop, index, allregs=False): - filename = outywfile.replace("%", index) - print_msg("Writing trace to Yosys witness file: %s" % (filename)) - - mem_trace_data = collect_mem_trace_data(steps_start, steps_stop) - - with open(filename, "w") as f: - inits, seqs, clocks, mems = smt.hierwitness(topmod, allregs) - - yw = WriteWitness(f, "smtbmc") - - for clock in clocks: - yw.add_clock(clock["path"], clock["offset"], clock["type"]) - - for seq in seqs: - seq["sig"] = yw.add_sig(seq["path"], seq["offset"], seq["width"]) - - for init in inits: - init["sig"] = yw.add_sig(init["path"], init["offset"], init["width"], True) - - inits = seqs + inits - - mem_dict = {tuple(mem["smtpath"]): mem for mem in mems} - mem_init_values = [] - - for path, addr, value in mem_trace_data.get(0, ()): - json_mem = mem_dict.get(tuple(path)) - if not json_mem: - continue - - bit_addr = addr * json_mem["width"] - uninit_chunks = [(chunk["width"] + chunk["offset"], chunk["offset"]) for chunk in json_mem["uninitialized"]] - first_chunk_nr = bisect.bisect_left(uninit_chunks, (bit_addr + 1,)) - - for uninit_end, uninit_offset in uninit_chunks[first_chunk_nr:]: - assert uninit_end > bit_addr - if uninit_offset > bit_addr + json_mem["width"]: - break - - word_path = (*json_mem["path"], f"\\[{addr}]") - - overlap_start = max(uninit_offset - bit_addr, 0) - overlap_end = min(uninit_end - bit_addr, json_mem["width"]) - overlap_bits = value[len(value)-overlap_end:len(value)-overlap_start] - - sig = yw.add_sig(word_path, overlap_start, overlap_end - overlap_start, True) - mem_init_values.append((sig, overlap_bits.replace("x", "?"))) - - for k in range(steps_start, steps_stop): - step_values = WitnessValues() - - if k == steps_start: - for sig, value in mem_init_values: - step_values[sig] = value - sigs = inits + seqs - else: - sigs = seqs - - for sig in sigs: - value = smt.bv2bin(smt.get(smt.witness_net_expr(topmod, f"s{k}", sig))) - step_values[sig["sig"]] = value - yw.step(step_values) - - yw.end_trace() - - -def write_trace(steps_start, steps_stop, index, allregs=False): - 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) - - if outywfile is not None: - write_yw_trace(steps_start, steps_stop, index, allregs) - - -def print_failed_asserts_worker(mod, state, path, extrainfo, infomap, infokey=()): - 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(): - cell_infokey = (mod, cellname, infokey) - if print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname, extrainfo, infomap, cell_infokey): - found_failed_assert = True - - for assertfun, assertinfo in smt.modinfo[mod].asserts.items(): - if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]: - assert_key = (assertfun, infokey) - print_msg("Assert failed in %s: %s%s%s" % (path, assertinfo, extrainfo, infomap.get(assert_key, ''))) - found_failed_assert = True - - return found_failed_assert - - -def print_failed_asserts(state, final=False, extrainfo="", infomap={}): - 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%s" % (loc, expr, extrainfo, infomap.get(loc, ''))) - found_failed_assert = True - - if not final: - if print_failed_asserts_worker(topmod, "s%d" % state, topmod, extrainfo, infomap): - 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: - if not binarymode: - 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 in %s (%s): %s" % (path, info[0], smt.bv2bin(smt.get("(|%s| %s)" % (fun, state))))) - else: - if not binarymode: - print_msg("Value for anyconst %s.%s (%s): %d" % (path, info[1], info[0], smt.bv2int(smt.get("(|%s| %s)" % (fun, state))))) - else: - print_msg("Value for anyconst %s.%s (%s): %s" % (path, info[1], info[0], smt.bv2bin(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 - - -def get_assert_map(mod, base, path, key_base=()): - assert mod in smt.modinfo - - assert_map = dict() - - for expr, desc in smt.modinfo[mod].asserts.items(): - assert_map[(expr, key_base)] = ("(|%s| %s)" % (expr, base), path, desc) - - for cell, submod in smt.modinfo[mod].cells.items(): - assert_map.update(get_assert_map(submod, "(|%s_h %s| %s)" % (mod, cell, base), path + "." + cell, (mod, cell, key_base))) - - return assert_map - - -def get_assert_keys(): - keys = set() - keys.update(get_assert_map(topmod, 'state', topmod).keys()) - for step_constr_asserts in constr_asserts.values(): - keys.update(loc for loc, expr in step_constr_asserts) - - return keys - - -def get_active_assert_map(step, active): - assert_map = dict() - for key, assert_data in get_assert_map(topmod, "s%s" % step, topmod).items(): - if key in active: - assert_map[key] = assert_data - - for loc, expr, actual_expr in zip(*get_constr_expr(constr_asserts, step, individual=True)): - if loc in active: - assert_map[loc] = (actual_expr, None, (expr, loc)) - - return assert_map - - -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 - - assert (len(smt.modinfo[topmod].maximize) + len(smt.modinfo[topmod].minimize) <= 1) - - 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)) - - if len(smt.modinfo[topmod].maximize) > 0: - for s in states: - if s in used_states_db: - smt.write("(maximize (|%s| %s))\n" % (smt.modinfo[topmod].maximize.copy().pop(), s)) - break - - if len(smt.modinfo[topmod].minimize) > 0: - for s in states: - if s in used_states_db: - smt.write("(minimize (|%s| %s))\n" % (smt.modinfo[topmod].minimize.copy().pop(), s)) - break - -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(expected=["sat", "unsat"]): - if asserts_cache_dirty: - smt_forall_assert() - return smt.check_sat(expected=expected) - -if tempind: - retstatus = "FAILED" - 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, '%', allregs=True) - if detect_loops: - loop = detect_state_loop(step, num_steps+1) - if loop: - print_msg(f"Loop detected, increasing induction depth will not help. Step {loop[0]} = step {loop[1]}") - - elif dumpall: - print_anyconsts(num_steps) - print_failed_asserts(num_steps) - write_trace(step, num_steps+1, "%d" % step, allregs=True) - - else: - print_msg("Temporal induction successful.") - retstatus = "PASSED" - 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 = "FAILED" - 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 = "FAILED" - 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 = "PASSED" - 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 - active_assert_keys = get_assert_keys() - failed_assert_infomap = dict() - traceidx = 0 - - step = 0 - retstatus = "PASSED" - 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 Assumptions are unsatisfiable!" % smt.timestamp()) - retstatus = "PREUNSAT" - break - - if not final_only: - recheck_current_step = True - while recheck_current_step: - recheck_current_step = False - 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() - - active_assert_maps = dict() - active_assert_exprs = list() - for i in range(step, last_check_step+1): - assert_expr_map = get_active_assert_map(i, active_assert_keys) - active_assert_maps[i] = assert_expr_map - active_assert_exprs.extend(assert_data[0] for assert_data in assert_expr_map.values()) - - if active_assert_exprs: - if len(active_assert_exprs) == 1: - active_assert_expr = active_assert_exprs[0] - else: - active_assert_expr = "(and %s)" % " ".join(active_assert_exprs) - - smt_assert("(not %s)" % active_assert_expr) - else: - active_assert_expr = "true" - smt_assert("false") - - - if smt_check_sat() == "sat": - if retstatus != "FAILED": - print("%s BMC failed!" % smt.timestamp()) - - if check_witness: - print_msg("Checking witness constraints...") - smt_pop() - smt_push() - smt_assert(active_assert_expr) - if smt_check_sat() != "sat": - retstatus = "PASSED" - check_witness = False - num_steps = -1 - break - - 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 append steps without violating assumptions!" % smt.timestamp()) - retstatus = "FAILED" - break - print_anyconsts(step) - - for i in range(step, last_check_step+1): - print_failed_asserts(i, infomap=failed_assert_infomap) - - if keep_going: - for i in range(step, last_check_step+1): - for key, (expr, path, desc) in active_assert_maps[i].items(): - if key in active_assert_keys and not smt.bv2int(smt.get(expr)): - failed_assert_infomap[key] = " [failed before]" - - active_assert_keys.remove(key) - - if active_assert_keys: - recheck_current_step = True - - write_trace(0, last_check_step+1+append_steps, "%d" % traceidx if keep_going else '%') - traceidx += 1 - retstatus = "FAILED" - - smt_pop() - if recheck_current_step: - print_msg("Checking remaining assertions..") - - if retstatus == "FAILED" and not (keep_going and active_assert_keys): - break - - if (constr_final_start is not None) or (last_check_step+1 != num_steps): - for i in range(step, last_check_step+1): - assert_expr_map = get_active_assert_map(i, active_assert_keys) - for assert_data in assert_expr_map.values(): - smt_assert(assert_data[0]) - - 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 = "FAILED" - break - - smt_pop() - if retstatus == "FAILED" or retstatus == "PREUNSAT": - 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)) - status = smt_check_sat() - if status != "sat": - print("%s No solution found! (%s)" % (smt.timestamp(), status)) - retstatus = "FAILED" - break - - elif dumpall: - print_anyconsts(0) - write_trace(0, last_check_step+1, "%d" % step) - - step += step_size - - if gentrace and retstatus == "PASSED": - print_anyconsts(0) - write_trace(0, num_steps, '%') - - if check_witness: - retstatus = "FAILED" - -smt.write("(exit)") -smt.wait() - -print_msg("Status: %s" % retstatus) -sys.exit(0 if retstatus == "PASSED" else 1) diff --git a/yosys/backends/smt2/smtio.py b/yosys/backends/smt2/smtio.py deleted file mode 100644 index a7374589690..00000000000 --- a/yosys/backends/smt2/smtio.py +++ /dev/null @@ -1,1240 +0,0 @@ -# -# yosys -- Yosys Open SYnthesis Suite -# -# Copyright (C) 2012 Claire Xenia 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, json -import subprocess -if os.name == "posix": - import resource -from copy import copy -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 = 8 * 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: - try: - resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1])) - except ValueError: - # couldn't get more stack, just run with what we have - pass - - -# 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.maximize = set() - self.minimize = set() - self.anyconsts = dict() - self.anyseqs = dict() - self.allconsts = dict() - self.allseqs = dict() - self.asize = dict() - self.witness = [] - - -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.timeout = 0 - self.produce_models = True - self.recheck = False - self.smt2cache = [list()] - self.smt2_options = dict() - 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.timeout = opts.timeout - 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.timeout = 0 - 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.forall: - self.noincr = True - - if self.noincr: - self.popen_vargs = ['yices-smt2'] + self.solver_opts - else: - self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts - if self.timeout != 0: - self.popen_vargs.append('-t') - self.popen_vargs.append('%d' % self.timeout); - - if self.solver == "z3": - self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts - if self.timeout != 0: - self.popen_vargs.append('-T:%d' % self.timeout); - - if self.solver in ["cvc4", "cvc5"]: - self.recheck = True - if self.noincr: - self.popen_vargs = [self.solver, '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts - else: - self.popen_vargs = [self.solver, '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts - if self.timeout != 0: - self.popen_vargs.append('--tlimit=%d000' % self.timeout); - - if self.solver == "mathsat": - self.popen_vargs = ['mathsat'] + self.solver_opts - if self.timeout != 0: - print('timeout option is not supported for mathsat.') - sys.exit(1) - - if self.solver in ["boolector", "bitwuzla"]: - if self.noincr: - self.popen_vargs = [self.solver, '--smt2'] + self.solver_opts - else: - self.popen_vargs = [self.solver, '--smt2', '-i'] + self.solver_opts - self.unroll = True - if self.timeout != 0: - print('timeout option is not supported for %s.' % self.solver) - sys.exit(1) - - 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.timeout != 0: - print('timeout option is not supported for abc.') - sys.exit(1) - - 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" - if self.solver == "yices" and self.forall: self.logic = "BV" - - self.setup_done = True - - for stmt in self.info_stmts: - self.write(stmt) - - if self.produce_models: - self.write("(set-option :produce-models true)") - - #See the SMT-LIB Standard, Section 4.1.7 - modestart_options = [":global-declarations", ":interactive-mode", ":produce-assertions", ":produce-assignments", ":produce-models", ":produce-proofs", ":produce-unsat-assumptions", ":produce-unsat-cores", ":random-seed"] - for key, val in self.smt2_options.items(): - if key in modestart_options: - self.write("(set-option {} {})".format(key, val)) - - self.write("(set-logic %s)" % self.logic) - - if self.forall and self.solver == "yices": - self.write("(set-option :yices-ef-max-iters 1000000000)") - - for key, val in self.smt2_options.items(): - if key not in modestart_options: - self.write("(set-option {} {})".format(key, val)) - - 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 = copy(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("utf-8") - 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 - try: - self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - except FileNotFoundError: - print("%s SMT Solver '%s' not found in path." % (self.timestamp(), self.popen_vargs[0]), flush=True) - sys.exit(1) - 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, "utf-8")) - 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 - - recheck = None - - if self.solver != "dummy": - if self.noincr: - # Don't close the solver yet, if we're just unrolling definitions - # required for a (get-...) statement - if self.p is not None and not stmt.startswith("(get-") and unroll: - self.p_close() - - 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.recheck and s and s[0].startswith("get-"): - recheck = self.unroll_idcnt - - 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 recheck is not None and recheck != self.unroll_idcnt: - self.check_sat(["sat"]) - - if stmt == "(push 1)": - self.unroll_stack.append(( - copy(self.unroll_sorts), - copy(self.unroll_objs), - copy(self.unroll_decls), - copy(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 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-solver-option": - self.smt2_options[fields[2]] = fields[3] - - 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": - if len(fields) > 4: - self.modinfo[self.curmod].asserts["%s_a %s" % (self.curmod, fields[2])] = f'{fields[4]} ({fields[3]})' - else: - self.modinfo[self.curmod].asserts["%s_a %s" % (self.curmod, fields[2])] = fields[3] - - if fields[1] == "yosys-smt2-cover": - if len(fields) > 4: - self.modinfo[self.curmod].covers["%s_c %s" % (self.curmod, fields[2])] = f'{fields[4]} ({fields[3]})' - else: - self.modinfo[self.curmod].covers["%s_c %s" % (self.curmod, fields[2])] = fields[3] - - if fields[1] == "yosys-smt2-maximize": - self.modinfo[self.curmod].maximize.add(fields[2]) - - if fields[1] == "yosys-smt2-minimize": - self.modinfo[self.curmod].minimize.add(fields[2]) - - 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]) - - if fields[1] == "yosys-smt2-witness": - data = json.loads(stmt.split(None, 2)[2]) - if data.get("type") in ["cell", "mem", "posedge", "negedge", "input", "reg", "init", "seq", "blackbox"]: - self.modinfo[self.curmod].witness.append(data) - - 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 hierwitness(self, top, allregs=False, blackbox=True): - init_witnesses = [] - seq_witnesses = [] - clk_witnesses = [] - mem_witnesses = [] - - def absolute(path, cursor, witness): - return { - **witness, - "path": path + tuple(witness["path"]), - "smtpath": cursor + [witness["smtname"]], - } - - for witness in self.modinfo[top].witness: - if witness["type"] == "input": - seq_witnesses.append(absolute((), [], witness)) - if witness["type"] in ("posedge", "negedge"): - clk_witnesses.append(absolute((), [], witness)) - - init_types = ["init"] - if allregs: - init_types.append("reg") - - seq_types = ["seq"] - if blackbox: - seq_types.append("blackbox") - - def worker(mod, path, cursor): - cell_paths = {} - for witness in self.modinfo[mod].witness: - if witness["type"] in init_types: - init_witnesses.append(absolute(path, cursor, witness)) - if witness["type"] in seq_types: - seq_witnesses.append(absolute(path, cursor, witness)) - if witness["type"] == "mem": - if allregs and not witness["rom"]: - width, size = witness["width"], witness["size"] - witness = {**witness, "uninitialized": [{"width": width * size, "offset": 0}]} - if not witness["uninitialized"]: - continue - - mem_witnesses.append(absolute(path, cursor, witness)) - if witness["type"] == "cell": - cell_paths[witness["smtname"]] = tuple(witness["path"]) - - for cellname, celltype in sorted(self.modinfo[mod].cells.items()): - worker(celltype, path + cell_paths.get(cellname, ("?" + cellname,)), cursor + [cellname]) - - worker(top, (), []) - return init_witnesses, seq_witnesses, clk_witnesses, mem_witnesses - - 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, expected=["sat", "unsat", "unknown", "timeout", "interrupted"]): - 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) - - if self.forall: - result = self.read() - while result not in ["sat", "unsat", "unknown", "timeout", "interrupted", ""]: - print("%s %s: %s" % (self.timestamp(), self.solver, result)) - result = self.read() - else: - 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 expected: - 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, cursor=0): - while stmt[cursor] in [" ", "\t", "\r", "\n"]: - cursor += 1 - - if stmt[cursor] == '(': - expr = [] - cursor += 1 - while stmt[cursor] != ')': - el, cursor = worker(stmt, cursor) - expr.append(el) - return expr, cursor+1 - - if stmt[cursor] == '|': - expr = "|" - cursor += 1 - while stmt[cursor] != '|': - expr += stmt[cursor] - cursor += 1 - expr += "|" - return expr, cursor+1 - - expr = "" - 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 isinstance(path[0], int): - return "(|%s#%d| %s)" % (mod, path[0], 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 witness_net_expr(self, mod, base, witness): - net = self.net_expr(mod, base, witness["smtpath"]) - is_bool = self.net_width(mod, witness["smtpath"]) == 1 - if is_bool: - assert witness["width"] == 1 - assert witness["smtoffset"] == 0 - return net - return "((_ extract %d %d) %s)" % (witness["smtoffset"] + witness["width"] - 1, witness["smtoffset"], net) - - 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 - if isinstance(net_path[-1], int): - return None - 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", "timeout=", "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.timeout = 0 - 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 == "--timeout": - self.timeout = int(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, bitwuzla, cvc4, mathsat, dummy - default: yices - - -S - pass as command line argument to the solver - - --timeout - set the solver timeout to the specified value (in seconds). - - --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) - - def vcdescape(n): - if n.startswith("$") or ":" in n: - return "\\" + n - return n - - scope = [] - for path in sorted(self.nets): - key, width = self.nets[path] - - uipath = list(path) - if "." in uipath[-1] and not uipath[-1].startswith("$"): - 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)] - print("$scope module %s $end" % vcdescape(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, vcdescape(uipath[-1])), file=self.f) - else: - print("$var wire %d %s %s $end" % (width, key, vcdescape(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 34adb7af3c1..00000000000 --- 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/smt2/witness.py b/yosys/backends/smt2/witness.py deleted file mode 100644 index 8d0cc8112d1..00000000000 --- a/yosys/backends/smt2/witness.py +++ /dev/null @@ -1,410 +0,0 @@ -#!/usr/bin/env python3 -# -# yosys -- Yosys Open SYnthesis Suite -# -# Copyright (C) 2022 Jannis Harder -# -# 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, itertools, re -##yosys-sys-path## -import json -import click - -from ywio import ReadWitness, WriteWitness, WitnessSig, WitnessSigMap, WitnessValues, coalesce_signals - -@click.group() -def cli(): - pass - - -@cli.command(help=""" -Display a Yosys witness trace in a human readable format. -""") -@click.argument("input", type=click.File("r")) -def display(input): - click.echo(f"Reading Yosys witness trace {input.name!r}...") - inyw = ReadWitness(input) - - def output(): - - yield click.style("*** RTLIL bit-order below may differ from source level declarations ***", fg="red") - if inyw.clocks: - yield click.style("=== Clock Signals ===", fg="blue") - for clock in inyw.clocks: - yield f" {clock['edge']} {WitnessSig(clock['path'], clock['offset']).pretty()}" - - for t, values in inyw.steps(): - if t: - yield click.style(f"=== Step {t} ===", fg="blue") - else: - yield click.style("=== Initial State ===", fg="blue") - - step_prefix = click.style(f"#{t}", fg="bright_black") - - signals, missing = values.present_signals(inyw.sigmap) - - assert not missing - - for sig in signals: - display_bits = values[sig].replace("?", click.style("?", fg="bright_black")) - yield f" {step_prefix} {sig.pretty()} = {display_bits}" - click.echo_via_pager([line + "\n" for line in output()]) - - -@cli.command(help=""" -Display statistics of a Yosys witness trace. -""") -@click.argument("input", type=click.File("r")) -def stats(input): - click.echo(f"Reading Yosys witness trace {input.name!r}...") - inyw = ReadWitness(input) - - total = 0 - - for t, values in inyw.steps(): - click.echo(f"{t:5}: {len(values.values):8} bits") - total += len(values.values) - - click.echo(f"total: {total:8} bits") - - -@cli.command(help=""" -Transform a Yosys witness trace. - -Currently no transformations are implemented, so it is only useful for testing. -""") -@click.argument("input", type=click.File("r")) -@click.argument("output", type=click.File("w")) -def yw2yw(input, output): - click.echo(f"Copying yosys witness trace from {input.name!r} to {output.name!r}...") - inyw = ReadWitness(input) - outyw = WriteWitness(output, "yosys-witness yw2yw") - - for clock in inyw.clocks: - outyw.add_clock(clock["path"], clock["offset"], clock["edge"]) - - for sig in inyw.signals: - outyw.add_sig(sig.path, sig.offset, sig.width, sig.init_only) - - for t, values in inyw.steps(): - outyw.step(values) - - outyw.end_trace() - - click.echo(f"Copied {outyw.t + 1} time steps.") - - -class AigerMap: - def __init__(self, mapfile): - data = json.load(mapfile) - - version = data.get("version") if isinstance(data, dict) else {} - if version != "Yosys Witness Aiger map": - raise click.ClickException(f"{mapfile.name}: unexpected file format version {version!r}") - - self.latch_count = data["latch_count"] - self.input_count = data["input_count"] - - self.clocks = data["clocks"] - - self.sigmap = WitnessSigMap() - self.init_inputs = set(init["input"] for init in data["inits"]) - - for bit in data["inputs"] + data["seqs"] + data["inits"]: - self.sigmap.add_bit((tuple(bit["path"]), bit["offset"]), bit["input"]) - - - -@cli.command(help=""" -Convert an AIGER witness trace into a Yosys witness trace. - -This requires a Yosys witness AIGER map file as generated by 'write_aiger -ywmap'. -""") -@click.argument("input", type=click.File("r")) -@click.argument("mapfile", type=click.File("r")) -@click.argument("output", type=click.File("w")) -def aiw2yw(input, mapfile, output): - input_name = input.name - click.echo(f"Converting AIGER witness trace {input_name!r} to Yosys witness trace {output.name!r}...") - click.echo(f"Using Yosys witness AIGER map file {mapfile.name!r}") - aiger_map = AigerMap(mapfile) - - header_lines = list(itertools.islice(input, 0, 2)) - - if len(header_lines) == 2 and header_lines[1][0] in ".bcjf": - status = header_lines[0].strip() - if status == "0": - raise click.ClickException(f"{input_name}: file contains no trace, the AIGER status is unsat") - elif status == "2": - raise click.ClickException(f"{input_name}: file contains no trace, the AIGER status is sat") - elif status != "1": - raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file") - else: - input = itertools.chain(header_lines, input) - - ffline = next(input, None) - if ffline is None: - raise click.ClickException(f"{input_name}: unexpected end of file") - ffline = ffline.strip() - if not re.match(r'[01x]*$', ffline): - raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file") - if not re.match(r'[0]*$', ffline): - raise click.ClickException(f"{input_name}: non-default initial state not supported") - - outyw = WriteWitness(output, 'yosys-witness aiw2yw') - - for clock in aiger_map.clocks: - outyw.add_clock(clock["path"], clock["offset"], clock["edge"]) - - for (path, offset), id in aiger_map.sigmap.bit_to_id.items(): - outyw.add_sig(path, offset, init_only=id in aiger_map.init_inputs) - - missing = set() - - while True: - inline = next(input, None) - if inline is None: - click.echo(f"Warning: {input_name}: file may be incomplete") - break - inline = inline.strip() - if inline in [".", "# DONE"]: - break - if inline.startswith("#"): - continue - - if not re.match(r'[01x]*$', ffline): - raise click.ClickException(f"{input_name}: unexpected data in AIGER witness file") - - if len(inline) != aiger_map.input_count: - raise click.ClickException( - f"{input_name}: {mapfile.name}: number of inputs does not match, " - f"{len(inline)} in witness, {aiger_map.input_count} in map file") - - values = WitnessValues() - for i, v in enumerate(inline): - if v == "x" or outyw.t > 0 and i in aiger_map.init_inputs: - continue - - try: - bit = aiger_map.sigmap.id_to_bit[i] - except IndexError: - bit = None - if bit is None: - missing.insert(i) - - values[bit] = v - - outyw.step(values) - - outyw.end_trace() - - if missing: - click.echo("The following AIGER inputs belong to unknown signals:") - click.echo(" " + " ".join(str(id) for id in sorted(missing))) - - click.echo(f"Converted {outyw.t} time steps.") - -@cli.command(help=""" -Convert a Yosys witness trace into an AIGER witness trace. - -This requires a Yosys witness AIGER map file as generated by 'write_aiger -ywmap'. -""") -@click.argument("input", type=click.File("r")) -@click.argument("mapfile", type=click.File("r")) -@click.argument("output", type=click.File("w")) -def yw2aiw(input, mapfile, output): - click.echo(f"Converting Yosys witness trace {input.name!r} to AIGER witness trace {output.name!r}...") - click.echo(f"Using Yosys witness AIGER map file {mapfile.name!r}") - aiger_map = AigerMap(mapfile) - inyw = ReadWitness(input) - - print("1", file=output) - print("b0", file=output) - # TODO the b0 status isn't really accurate, but we don't have any better info here - print("0" * aiger_map.latch_count, file=output) - - all_missing = set() - - for t, step in inyw.steps(): - bits, missing = step.pack_present(aiger_map.sigmap) - bits = bits[::-1].replace('?', 'x') - all_missing.update(missing) - bits += 'x' * (aiger_map.input_count - len(bits)) - print(bits, file=output) - - print(".", file=output) - - if all_missing: - click.echo("The following signals are missing in the AIGER map file and will be dropped:") - for sig in coalesce_signals(WitnessSig(*bit) for bit in all_missing): - click.echo(" " + sig.pretty()) - - - click.echo(f"Converted {len(inyw)} time steps.") - -class BtorMap: - def __init__(self, mapfile): - self.data = data = json.load(mapfile) - - version = data.get("version") if isinstance(data, dict) else {} - if version != "Yosys Witness BTOR map": - raise click.ClickException(f"{mapfile.name}: unexpected file format version {version!r}") - - self.sigmap = WitnessSigMap() - - for mode in ("states", "inputs"): - for btor_signal_def in data[mode]: - if btor_signal_def is None: - continue - if isinstance(btor_signal_def, dict): - btor_signal_def["path"] = tuple(btor_signal_def["path"]) - else: - for chunk in btor_signal_def: - chunk["path"] = tuple(chunk["path"]) - - -@cli.command(help=""" -Convert a BTOR witness trace into a Yosys witness trace. - -This requires a Yosys witness BTOR map file as generated by 'write_btor -ywmap'. -""") -@click.argument("input", type=click.File("r")) -@click.argument("mapfile", type=click.File("r")) -@click.argument("output", type=click.File("w")) -def wit2yw(input, mapfile, output): - input_name = input.name - click.echo(f"Converting BTOR witness trace {input_name!r} to Yosys witness trace {output.name!r}...") - click.echo(f"Using Yosys witness BTOR map file {mapfile.name!r}") - btor_map = BtorMap(mapfile) - - input = filter(None, (line.split(';', 1)[0].strip() for line in input)) - - sat = next(input, None) - if sat != "sat": - raise click.ClickException(f"{input_name}: not a BTOR witness file") - - props = next(input, None) - - t = -1 - - line = next(input, None) - - frames = [] - bits = {} - - while line and not line.startswith('.'): - current_t = int(line[1:].strip()) - if line[0] == '#': - mode = "states" - elif line[0] == '@': - mode = "inputs" - else: - raise click.ClickException(f"{input_name}: unexpected data in BTOR witness file") - - if current_t > t: - t = current_t - values = WitnessValues() - array_inits = set() - frames.append(values) - - line = next(input, None) - while line and line[0] not in "#@.": - if current_t > 0 and mode == "states": - line = next(input, None) - continue - tokens = line.split() - line = next(input, None) - - btor_sig = btor_map.data[mode][int(tokens[0])] - btor_sigs = [btor_sig] - - if btor_sig is None: - continue - - if isinstance(btor_sig, dict): - addr = tokens[1] - if not addr.startswith('['): - addr = '[*]' - value = tokens[1] - else: - value = tokens[2] - if not addr.endswith(']'): - raise click.ClickException(f"{input_name}: expected address in BTOR witness file") - path = btor_sig["path"] - width = btor_sig["width"] - size = btor_sig["size"] - if addr == '[*]': - btor_sigs = [ - [{ - "path": (*path, f"\\[{addr}]"), - "width": width, - "offset": 0, - }] - for addr in range(size) - if (path, addr) not in array_inits - ] - array_inits.update((path, addr) for addr in range(size)) - else: - addr = int(addr[1:-1], 2) - - if addr < 0 or addr >= size: - raise click.ClickException(f"{input_name}: out of bounds address in BTOR witness file") - - array_inits.add((path, addr)) - btor_sig = [{ - "path": (*path, f"\\[{addr}]"), - "width": width, - "offset": 0, - }] - btor_sigs = [btor_sig] - else: - value = tokens[1] - - for btor_sig in btor_sigs: - value_bits = iter(reversed(value)) - - for chunk in btor_sig: - offset = chunk["offset"] - path = chunk["path"] - for i in range(offset, offset + chunk["width"]): - key = (path, i) - bits[key] = mode == "inputs" - values[key] = next(value_bits) - - if next(value_bits, None) is not None: - raise click.ClickException(f"{input_name}: excess bits in BTOR witness file") - - - if line is None: - raise click.ClickException(f"{input_name}: unexpected end of BTOR witness file") - if line.strip() != '.': - raise click.ClickException(f"{input_name}: unexpected data in BTOR witness file") - if next(input, None) is not None: - raise click.ClickException(f"{input_name}: unexpected trailing data in BTOR witness file") - - outyw = WriteWitness(output, 'yosys-witness wit2yw') - - outyw.signals = coalesce_signals((), bits) - for clock in btor_map.data["clocks"]: - outyw.add_clock(clock["path"], clock["offset"], clock["edge"]) - - for values in frames: - outyw.step(values) - - outyw.end_trace() - click.echo(f"Converted {outyw.t} time steps.") - -if __name__ == "__main__": - cli() diff --git a/yosys/backends/smt2/ywio.py b/yosys/backends/smt2/ywio.py deleted file mode 100644 index 39cfac41e25..00000000000 --- a/yosys/backends/smt2/ywio.py +++ /dev/null @@ -1,393 +0,0 @@ -# -# yosys -- Yosys Open SYnthesis Suite -# -# Copyright (C) 2022 Jannis Harder -# -# 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 json, re - -from functools import total_ordering - - -class PrettyJson: - def __init__(self, f): - self.f = f - self.indent = 0 - self.state = ["value"] - - def line(self): - indent = len(self.state) - bool(self.state and self.state[-1] == "value") - print("\n", end=" " * (2 * indent), file=self.f) - - def raw(self, str): - print(end=str, file=self.f) - - def begin_object(self): - self.begin_value() - self.raw("{") - self.state.append("object_first") - - def begin_array(self): - self.begin_value() - self.raw("[") - self.state.append("array_first") - - def end_object(self): - state = self.state.pop() - if state == "object": - self.line() - else: - assert state == "object_first" - self.raw("}") - self.end_value() - - def end_array(self): - state = self.state.pop() - if state == "array": - self.line() - else: - assert state == "array_first" - self.raw("]") - self.end_value() - - def name(self, name): - if self.state[-1] == "object_first": - self.state[-1] = "object" - else: - self.raw(",") - self.line() - json.dump(str(name), self.f) - self.raw(": ") - self.state.append("value") - - def begin_value(self): - if self.state[-1] == "array_first": - self.line() - self.state[-1] = "array" - elif self.state[-1] == "array": - self.raw(",") - self.line() - else: - assert self.state.pop() == "value" - - def end_value(self): - if not self.state: - print(file=self.f, flush=True) - - def value(self, value): - self.begin_value() - json.dump(value, self.f) - self.end_value() - - def entry(self, name, value): - self.name(name) - self.value(value) - - def object(self, entries=None): - if isinstance(entries, dict): - entries = dict.items() - self.begin_object() - for name, value in entries: - self.entry(name, value) - self.end_object() - - def array(self, values=None): - self.begin_array() - for value in values: - self.value(value) - self.end_array() - - -addr_re = re.compile(r'\\\[[0-9]+\]$') -public_name_re = re.compile(r"\\([a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?|\[[0-9]+\])$") - -def pretty_name(id): - if public_name_re.match(id): - return id.lstrip("\\") - else: - return id - -def pretty_path(path): - out = "" - for name in path: - name = pretty_name(name) - if name.startswith("["): - out += name - continue - if out: - out += "." - if name.startswith("\\") or name.startswith("$"): - out += name + " " - else: - out += name - - return out - -@total_ordering -class WitnessSig: - def __init__(self, path, offset, width=1, init_only=False): - path = tuple(path) - self.path, self.width, self.offset, self.init_only = path, width, offset, init_only - - self.memory_path = None - self.memory_addr = None - - sort_path = path - sort_id = -1 - if path and addr_re.match(path[-1]): - self.memory_path = sort_path = path[:-1] - self.memory_addr = sort_id = int(path[-1][2:-1]) - - self.sort_key = (init_only, sort_path, sort_id, offset, width) - - def bits(self): - return ((self.path, i) for i in range(self.offset, self.offset + self.width)) - - def rev_bits(self): - return ((self.path, i) for i in reversed(range(self.offset, self.offset + self.width))) - - def pretty(self): - if self.width > 1: - last_offset = self.offset + self.width - 1 - return f"{pretty_path(self.path)}[{last_offset}:{self.offset}]" - else: - return f"{pretty_path(self.path)}[{self.offset}]" - - def __eq__(self): - return self.sort_key - - def __hash__(self): - return hash(self.sort_key) - - def __lt__(self, other): - return self.sort_key < other.sort_key - - -def coalesce_signals(signals, bits=None): - if bits is None: - bits = {} - for sig in signals: - for bit in sig.bits(): - if sig.init_only: - bits.setdefault(bit, False) - else: - bits[bit] = True - - active = None - - out = [] - - for bit, not_init in sorted(bits.items()): - if active: - if active[0] == bit[0] and active[2] == bit[1] and active[3] == not_init: - active[2] += 1 - else: - out.append(WitnessSig(active[0], active[1], active[2] - active[1], not active[3])) - active = None - - if active is None: - active = [bit[0], bit[1], bit[1] + 1, not_init] - - if active: - out.append(WitnessSig(active[0], active[1], active[2] - active[1], not active[3])) - - return sorted(out) - - -class WitnessSigMap: - def __init__(self, signals=[]): - self.signals = [] - - self.id_to_bit = [] - self.bit_to_id = {} - self.bit_to_sig = {} - - for sig in signals: - self.add_signal(sig) - - def add_signal(self, sig): - self.signals.append(sig) - for bit in sig.bits(): - self.add_bit(bit) - self.bit_to_sig[bit] = sig - - def add_bit(self, bit, id=None): - if id is None: - id = len(self.id_to_bit) - self.id_to_bit.append(bit) - else: - if len(self.id_to_bit) <= id: - self.id_to_bit += [None] * (id - len(self.id_to_bit) + 1) - self.id_to_bit[id] = bit - self.bit_to_id[bit] = id - - -class WitnessValues: - def __init__(self): - self.values = {} - - def __setitem__(self, key, value): - if isinstance(key, tuple) and len(key) == 2: - if value != "?": - assert isinstance(value, str) - assert len(value) == 1 - self.values[key] = value - else: - assert isinstance(key, WitnessSig) - assert key.width == len(value) - if isinstance(value, str): - value = reversed(value) - for bit, bit_value in zip(key.bits(), value): - if bit_value != "?": - self.values[bit] = bit_value - - def __getitem__(self, key): - if isinstance(key, tuple) and len(key) == 2: - return self.values.get(key, "?") - else: - assert isinstance(key, WitnessSig) - return "".join([self.values.get(bit, "?") for bit in key.rev_bits()]) - - def pack_present(self, sigmap): - missing = [] - - max_id = max((sigmap.bit_to_id.get(bit, -1) for bit in self.values), default=-1) - - vector = ["?"] * (max_id + 1) - for bit, bit_value in self.values.items(): - id = sigmap.bit_to_id.get(bit, - 1) - if id < 0: - missing.append(bit) - else: - vector[max_id - sigmap.bit_to_id[bit]] = bit_value - - return "".join(vector), missing - - def pack(self, sigmap): - packed, missing = self.pack_present(sigmap) - if missing: - raise RuntimeError(f"Cannot pack bits {missing!r}") - return packed - - def unpack(self, sigmap, bits): - for i, bit_value in enumerate(reversed(bits)): - if bit_value != "?": - self.values[sigmap.id_to_bit[i]] = bit_value - - def present_signals(self, sigmap): - signals = set(sigmap.bit_to_sig.get(bit) for bit in self.values) - missing_signals = None in signals - if missing_signals: - signals.discard(None) - - return sorted(signals), missing_signals - - -class WriteWitness: - def __init__(self, f, generator): - self.out = PrettyJson(f) - self.t = 0 - self.header_written = False - self.clocks = [] - self.signals = [] - - self.out.begin_object() - self.out.entry("format", "Yosys Witness Trace") - self.out.entry("generator", generator) - - def add_clock(self, path, offset, edge): - assert not self.header_written - self.clocks.append({ - "path": path, - "edge": edge, - "offset": offset, - }) - - def add_sig(self, path, offset, width=1, init_only=False): - assert not self.header_written - sig = WitnessSig(path, offset, width, init_only) - self.signals.append(sig) - return sig - - def write_header(self): - assert not self.header_written - self.header_written = True - self.out.name("clocks") - self.out.array(self.clocks) - - self.signals = coalesce_signals(self.signals) - self.sigmap = WitnessSigMap(self.signals) - - self.out.name("signals") - self.out.array({ - "path": sig.path, - "width": sig.width, - "offset": sig.offset, - "init_only": sig.init_only, - } for sig in self.signals) - - self.out.name("steps") - self.out.begin_array() - - def step(self, values): - if not self.header_written: - self.write_header() - - self.out.value({"bits": values.pack(self.sigmap)}) - - self.t += 1 - - def end_trace(self): - if not self.header_written: - self.write_header() - self.out.end_array() - self.out.end_object() - - -class ReadWitness: - def __init__(self, f): - data = json.load(f) - if not isinstance(data, dict): - data = {} - - data_format = data.get("format", "Unknown Format") - - if data_format != "Yosys Witness Trace": - raise ValueError(f"unsupported format {data_format!r}") - - self.clocks = data["clocks"] - for clock in self.clocks: - clock["path"] = tuple(clock["path"]) - - self.signals = [ - WitnessSig(sig["path"], sig["offset"], sig["width"], sig["init_only"]) - for sig in data["signals"] - ] - - self.sigmap = WitnessSigMap(self.signals) - - self.bits = [step["bits"] for step in data["steps"]] - - def step(self, t): - values = WitnessValues() - values.unpack(self.sigmap, self.bits[t]) - return values - - def steps(self): - for i in range(len(self.bits)): - yield i, self.step(i) - - def __len__(self): - return len(self.bits) diff --git a/yosys/backends/smv/.gitignore b/yosys/backends/smv/.gitignore deleted file mode 100644 index d23d492d733..00000000000 --- a/yosys/backends/smv/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/test_cells.tmp/ diff --git a/yosys/backends/smv/Makefile.inc b/yosys/backends/smv/Makefile.inc deleted file mode 100644 index 66c192d80ed..00000000000 --- 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 49c2cc7a6c4..00000000000 --- a/yosys/backends/smv/smv.cc +++ /dev/null @@ -1,835 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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.compare(0, 2, "_\\") == 0) - 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(ID::init)) - assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at(ID::init)))); - } - - for (auto cell : module->cells()) - { - // FIXME: $slice, $concat, $mem - - if (cell->type.in(ID($assert))) - { - SigSpec sig_a = cell->getPort(ID::A); - SigSpec sig_en = cell->getPort(ID::EN); - - invarspecs.push_back(stringf("!bool(%s) | bool(%s);", rvalue(sig_en), rvalue(sig_a))); - - continue; - } - - if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) - { - SigSpec sig_a = cell->getPort(ID::A); - SigSpec sig_b = cell->getPort(ID::B); - - int width_y = GetSize(cell->getPort(ID::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(ID::A_SIGNED).as_bool(); - bool signed_b = cell->getParam(ID::B_SIGNED).as_bool(); - string op = cell->type.in(ID($shl), ID($sshl)) ? "<<" : ">>"; - string expr, expr_a; - - if (cell->type == ID($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(ID($shift), ID($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(ID($shift), ID($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(ID::Y)), expr.c_str())); - - continue; - } - - if (cell->type.in(ID($not), ID($pos), ID($neg))) - { - int width = GetSize(cell->getPort(ID::Y)); - string expr_a, op; - - if (cell->type == ID($not)) op = "!"; - if (cell->type == ID($pos)) op = ""; - if (cell->type == ID($neg)) op = "-"; - - if (cell->getParam(ID::A_SIGNED).as_bool()) - { - definitions.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort(ID::Y)), - op.c_str(), rvalue_s(cell->getPort(ID::A), width))); - } - else - { - definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort(ID::Y)), - op.c_str(), rvalue_u(cell->getPort(ID::A), width))); - } - - continue; - } - - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($and), ID($or), ID($xor), ID($xnor))) - { - int width = GetSize(cell->getPort(ID::Y)); - string expr_a, expr_b, op; - - if (cell->type == ID($add)) op = "+"; - if (cell->type == ID($sub)) op = "-"; - if (cell->type == ID($mul)) op = "*"; - if (cell->type == ID($and)) op = "&"; - if (cell->type == ID($or)) op = "|"; - if (cell->type == ID($xor)) op = "xor"; - if (cell->type == ID($xnor)) op = "xnor"; - - if (cell->getParam(ID::A_SIGNED).as_bool()) - { - definitions.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort(ID::Y)), - rvalue_s(cell->getPort(ID::A), width), op.c_str(), rvalue_s(cell->getPort(ID::B), width))); - } - else - { - definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort(ID::Y)), - rvalue_u(cell->getPort(ID::A), width), op.c_str(), rvalue_u(cell->getPort(ID::B), width))); - } - - continue; - } - - // SMV has a "mod" operator, but its semantics don't seem to be well-defined - to be safe, don't generate it at all - if (cell->type.in(ID($div)/*, ID($mod), ID($modfloor)*/)) - { - int width_y = GetSize(cell->getPort(ID::Y)); - int width = max(width_y, GetSize(cell->getPort(ID::A))); - width = max(width, GetSize(cell->getPort(ID::B))); - string expr_a, expr_b, op; - - if (cell->type == ID($div)) op = "/"; - //if (cell->type == ID($mod)) op = "mod"; - - if (cell->getParam(ID::A_SIGNED).as_bool()) - { - definitions.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort(ID::Y)), - rvalue_s(cell->getPort(ID::A), width), op.c_str(), rvalue_s(cell->getPort(ID::B), width), width_y)); - } - else - { - definitions.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort(ID::Y)), - rvalue_u(cell->getPort(ID::A), width), op.c_str(), rvalue_u(cell->getPort(ID::B), width), width_y)); - } - - continue; - } - - if (cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex), ID($lt), ID($le), ID($ge), ID($gt))) - { - int width = max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::B))); - string expr_a, expr_b, op; - - if (cell->type == ID($eq)) op = "="; - if (cell->type == ID($ne)) op = "!="; - if (cell->type == ID($eqx)) op = "="; - if (cell->type == ID($nex)) op = "!="; - if (cell->type == ID($lt)) op = "<"; - if (cell->type == ID($le)) op = "<="; - if (cell->type == ID($ge)) op = ">="; - if (cell->type == ID($gt)) op = ">"; - - if (cell->getParam(ID::A_SIGNED).as_bool()) - { - expr_a = stringf("resize(signed(%s), %d)", rvalue(cell->getPort(ID::A)), width); - expr_b = stringf("resize(signed(%s), %d)", rvalue(cell->getPort(ID::B)), width); - } - else - { - expr_a = stringf("resize(%s, %d)", rvalue(cell->getPort(ID::A)), width); - expr_b = stringf("resize(%s, %d)", rvalue(cell->getPort(ID::B)), width); - } - - definitions.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort(ID::Y)), - expr_a.c_str(), op.c_str(), expr_b.c_str(), GetSize(cell->getPort(ID::Y)))); - - continue; - } - - if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool))) - { - int width_a = GetSize(cell->getPort(ID::A)); - int width_y = GetSize(cell->getPort(ID::Y)); - const char *expr_a = rvalue(cell->getPort(ID::A)); - const char *expr_y = lvalue(cell->getPort(ID::Y)); - string expr; - - if (cell->type == ID($reduce_and)) expr = stringf("%s = !0ub%d_0", expr_a, width_a); - if (cell->type == ID($reduce_or)) expr = stringf("%s != 0ub%d_0", expr_a, width_a); - if (cell->type == ID($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(ID($reduce_xor), ID($reduce_xnor))) - { - int width_y = GetSize(cell->getPort(ID::Y)); - const char *expr_y = lvalue(cell->getPort(ID::Y)); - string expr; - - for (auto bit : cell->getPort(ID::A)) { - if (!expr.empty()) - expr += " xor "; - expr += rvalue(bit); - } - - if (cell->type == ID($reduce_xnor)) - expr = "!(" + expr + ")"; - - definitions.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y)); - continue; - } - - if (cell->type.in(ID($logic_and), ID($logic_or))) - { - int width_a = GetSize(cell->getPort(ID::A)); - int width_b = GetSize(cell->getPort(ID::B)); - int width_y = GetSize(cell->getPort(ID::Y)); - - string expr_a = stringf("(%s != 0ub%d_0)", rvalue(cell->getPort(ID::A)), width_a); - string expr_b = stringf("(%s != 0ub%d_0)", rvalue(cell->getPort(ID::B)), width_b); - const char *expr_y = lvalue(cell->getPort(ID::Y)); - - string expr; - if (cell->type == ID($logic_and)) expr = expr_a + " & " + expr_b; - if (cell->type == ID($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(ID($logic_not))) - { - int width_a = GetSize(cell->getPort(ID::A)); - int width_y = GetSize(cell->getPort(ID::Y)); - - string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort(ID::A)), width_a); - const char *expr_y = lvalue(cell->getPort(ID::Y)); - - definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y)); - continue; - } - - if (cell->type.in(ID($mux), ID($pmux))) - { - int width = GetSize(cell->getPort(ID::Y)); - SigSpec sig_a = cell->getPort(ID::A); - SigSpec sig_b = cell->getPort(ID::B); - SigSpec sig_s = cell->getPort(ID::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(ID::Y)), expr.c_str())); - continue; - } - - if (cell->type == ID($dff)) - { - vars.push_back(stringf("%s : unsigned word[%d]; -- %s", lvalue(cell->getPort(ID::Q)), GetSize(cell->getPort(ID::Q)), log_signal(cell->getPort(ID::Q)))); - assignments.push_back(stringf("next(%s) := %s;", lvalue(cell->getPort(ID::Q)), rvalue(cell->getPort(ID::D)))); - continue; - } - - if (cell->type.in(ID($_BUF_), ID($_NOT_))) - { - string op = cell->type == ID($_NOT_) ? "!" : ""; - definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort(ID::Y)), op.c_str(), rvalue(cell->getPort(ID::A)))); - continue; - } - - if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) - { - string op; - - if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_ANDNOT_))) op = "&"; - if (cell->type.in(ID($_OR_), ID($_NOR_), ID($_ORNOT_))) op = "|"; - if (cell->type.in(ID($_XOR_))) op = "xor"; - if (cell->type.in(ID($_XNOR_))) op = "xnor"; - - if (cell->type.in(ID($_ANDNOT_), ID($_ORNOT_))) - definitions.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::A)), op.c_str(), rvalue(cell->getPort(ID::B)))); - else - if (cell->type.in(ID($_NAND_), ID($_NOR_))) - definitions.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::A)), op.c_str(), rvalue(cell->getPort(ID::B)))); - else - definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::A)), op.c_str(), rvalue(cell->getPort(ID::B)))); - continue; - } - - if (cell->type == ID($_MUX_)) - { - definitions.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::S)), rvalue(cell->getPort(ID::B)), rvalue(cell->getPort(ID::A)))); - continue; - } - - if (cell->type == ID($_NMUX_)) - { - definitions.push_back(stringf("%s := !(bool(%s) ? %s : %s);", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::S)), rvalue(cell->getPort(ID::B)), rvalue(cell->getPort(ID::A)))); - continue; - } - - if (cell->type == ID($_AOI3_)) - { - definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::A)), rvalue(cell->getPort(ID::B)), rvalue(cell->getPort(ID::C)))); - continue; - } - - if (cell->type == ID($_OAI3_)) - { - definitions.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::A)), rvalue(cell->getPort(ID::B)), rvalue(cell->getPort(ID::C)))); - continue; - } - - if (cell->type == ID($_AOI4_)) - { - definitions.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::A)), rvalue(cell->getPort(ID::B)), rvalue(cell->getPort(ID::C)), rvalue(cell->getPort(ID::D)))); - continue; - } - - if (cell->type == ID($_OAI4_)) - { - definitions.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort(ID::Y)), - rvalue(cell->getPort(ID::A)), rvalue(cell->getPort(ID::B)), rvalue(cell->getPort(ID::C)), rvalue(cell->getPort(ID::D)))); - continue; - } - - if (cell->type[0] == '$') { - if (cell->type.in(ID($dffe), ID($sdff), ID($sdffe), ID($sdffce)) || cell->type.str().substr(0, 6) == "$_SDFF" || (cell->type.str().substr(0, 6) == "$_DFFE" && cell->type.str().size() == 10)) { - log_error("Unsupported cell type %s for cell %s.%s -- please run `dffunmap` before `write_smv`.\n", - log_id(cell->type), log_id(module), log_id(cell)); - } - if (cell->type.in(ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($dffsr), ID($dffsre)) || cell->type.str().substr(0, 5) == "$_DFF" || cell->type.str().substr(0, 7) == "$_ALDFF") { - log_error("Unsupported cell type %s for cell %s.%s -- please run `async2sync; dffunmap` or `clk2fflogic` before `write_smv`.\n", - log_id(cell->type), log_id(module), log_id(cell)); - } - if (cell->type.in(ID($sr), ID($dlatch), ID($adlatch), ID($dlatchsr)) || cell->type.str().substr(0, 8) == "$_DLATCH" || cell->type.str().substr(0, 5) == "$_SR_") { - log_error("Unsupported cell type %s for cell %s.%s -- please run `clk2fflogic` before `write_smv`.\n", - log_id(cell->type), log_id(module), log_id(cell)); - } - log_error("Unsupported cell type %s for cell %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() 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) override - { - std::ifstream template_f; - bool verbose = false; - - log_header(design, "Executing SMV backend.\n"); - - log_push(); - Pass::call(design, "bmuxmap"); - Pass::call(design, "demuxmap"); - Pass::call(design, "bwmuxmap"); - log_pop(); - - 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 145b9c33b92..00000000000 --- 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/$mod/$divfloor/$modfloor 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 /$divfloor /$modfloor' - -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 9c8530cb268..00000000000 --- 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 f260276eb93..00000000000 --- a/yosys/backends/spice/spice.cc +++ /dev/null @@ -1,270 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 &buf, 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 : module->cells()) - { - f << stringf("X%d", cell_counter++); - - std::vector port_sigs; - - if (design->module(cell->type) == nullptr) - { - 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->module(cell->type); - - std::vector ports; - for (auto wire : mod->wires()) { - 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 << (buf == "DC" ? stringf("V%d", conn_counter++) : stringf("X%d", cell_counter++)); - print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); - print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); - f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf.c_str())); - } -} - -struct SpiceBackend : public Backend { - SpiceBackend() : Backend("spice", "write design to SPICE netlist file") { } - void help() 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(" -buf DC|subckt_name\n"); - log(" set the name for jumper element (default: DC)\n"); - log(" (used to connect different nets)\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) 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", buf = "DC"; - - 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] == "-buf" && argidx+1 < args.size()) { - buf = 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 module : design->modules()) - if (module->get_bool_attribute(ID::top)) - top_module_name = module->name.str(); - - *f << stringf("* SPICE netlist generated by %s\n", yosys_version_str); - *f << stringf("\n"); - - for (auto module : design->modules()) - { - 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 : module->wires()) { - 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, buf, 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, buf, 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 8cd1dc619e3..00000000000 --- 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 2bf64e7b1c6..00000000000 --- a/yosys/backends/table/table.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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() 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) 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 c2dffef7a45..00000000000 --- 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 0a9c0590eb7..00000000000 --- a/yosys/backends/verilog/verilog_backend.cc +++ /dev/null @@ -1,2357 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 "kernel/ff.h" -#include "kernel/mem.h" -#include -#include -#include -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit, systemverilog, simple_lhs, noparallelcase; -int auto_name_counter, auto_name_offset, auto_name_digits, extmem_counter; -std::map auto_name_map; -std::set reg_wires; -std::string auto_prefix, extmem_prefix; - -RTLIL::Module *active_module; -dict active_initdata; -SigMap active_sigmap; -IdString initial_id; - -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 w : module->wires()) - reset_auto_counter_id(w->name, true); - - for (auto cell : module->cells()) { - reset_auto_counter_id(cell->name, true); - reset_auto_counter_id(cell->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) { - // See IEEE 1364-2005 Clause 5.1.14. - f << "{0{1'b0}}"; - 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] != State::S0 && data.bits[i] != State::S1) - goto dump_hex; - if (data.bits[i] == State::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 State::S0: bin_digits.push_back('0'); break; - case State::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('?'); 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; - } - if (bit_3 == '?' || bit_2 == '?' || bit_1 == '?' || bit_0 == '?') { - if (bit_3 != '?' || bit_2 != '?' || bit_1 != '?' || bit_0 != '?') - goto dump_bin; - hex_digits.push_back('?'); - 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 State::S0: f << stringf("0"); break; - case State::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: 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) { - // See IEEE 1364-2005 Clause 5.1.14. - f << "{0{1'b0}}"; - 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 regattr = false, bool as_comment = false) -{ - if (noattr) - return; - if (attr2comment) - as_comment = true; - for (auto it = attributes.begin(); it != attributes.end(); ++it) { - if (it->first == ID::init && regattr) continue; - f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str()); - f << stringf(" = "); - if (modattr && (it->second == State::S0 || it->second == Const(0))) - f << stringf(" 0 "); - else if (modattr && (it->second == State::S1 || 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, '\n', /*modattr=*/false, /*regattr=*/reg_wires.count(wire->name)); -#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(ID::init)) { - f << stringf(" = "); - dump_const(f, wire->attributes.at(ID::init)); - } - f << stringf(";\n"); - } else - 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, Mem &mem) -{ - std::string mem_id = id(mem.memid); - - dump_attributes(f, indent, mem.attributes); - f << stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent.c_str(), mem.width-1, mem_id.c_str(), mem.size+mem.start_offset-1, mem.start_offset); - - // for memory block make something like: - // reg [7:0] memid [3:0]; - // initial begin - // memid[0] = ... - // end - if (!mem.inits.empty()) - { - if (extmem) - { - std::string extmem_filename = stringf("%s-%d.mem", extmem_prefix.c_str(), extmem_counter++); - - std::string extmem_filename_esc; - for (auto c : extmem_filename) - { - if (c == '\n') - extmem_filename_esc += "\\n"; - else if (c == '\t') - extmem_filename_esc += "\\t"; - else if (c < 32) - extmem_filename_esc += stringf("\\%03o", c); - else if (c == '"') - extmem_filename_esc += "\\\""; - else if (c == '\\') - extmem_filename_esc += "\\\\"; - else - extmem_filename_esc += c; - } - f << stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent.c_str(), extmem_filename_esc.c_str(), mem_id.c_str()); - - std::ofstream extmem_f(extmem_filename, std::ofstream::trunc); - if (extmem_f.fail()) - log_error("Can't open file `%s' for writing: %s\n", extmem_filename.c_str(), strerror(errno)); - else - { - Const data = mem.get_init_data(); - for (int i=0; i expressions within that clock domain - dict> clk_to_lof_body; - dict clk_to_arst_cond; - dict> clk_to_arst_body; - clk_to_lof_body[""] = std::vector(); - std::string clk_domain_str; - // create a list of reg declarations - std::vector lof_reg_declarations; - - // read ports - for (auto &port : mem.rd_ports) - { - if (port.clk_enable) - { - { - std::ostringstream os; - dump_sigspec(os, port.clk); - clk_domain_str = stringf("%sedge %s", port.clk_polarity ? "pos" : "neg", os.str().c_str()); - if (port.arst != State::S0) { - std::ostringstream os2; - dump_sigspec(os2, port.arst); - clk_domain_str += stringf(", posedge %s", os2.str().c_str()); - clk_to_arst_cond[clk_domain_str] = os2.str(); - } - } - - // Decide how to represent the transparency; same idea as Mem::extract_rdff. - bool trans_use_addr = true; - for (auto bit : port.transparency_mask) - if (!bit) - trans_use_addr = false; - - if (GetSize(mem.wr_ports) == 0) - trans_use_addr = false; - - if (port.en != State::S1 || port.srst != State::S0 || port.arst != State::S0 || !port.init_value.is_fully_undef()) - trans_use_addr = false; - - if (!trans_use_addr) - { - // 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", port.data.size() - 1, temp_id.c_str()) ); - - bool has_indent = false; - - if (port.arst != State::S0) { - std::ostringstream os; - os << stringf("%s <= ", temp_id.c_str()); - dump_sigspec(os, port.arst_value); - os << ";\n"; - clk_to_arst_body[clk_domain_str].push_back(os.str()); - } - - if (port.srst != State::S0 && !port.ce_over_srst) { - std::ostringstream os; - os << stringf("if ("); - dump_sigspec(os, port.srst); - os << stringf(")\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); - std::ostringstream os2; - os2 << stringf("%s" "%s <= ", indent.c_str(), temp_id.c_str()); - dump_sigspec(os2, port.srst_value); - os2 << ";\n"; - clk_to_lof_body[clk_domain_str].push_back(os2.str()); - std::ostringstream os3; - if (port.en == State::S1) { - os3 << "else begin\n"; - } else { - os3 << "else if ("; - dump_sigspec(os3, port.en); - os3 << ") begin\n"; - } - clk_to_lof_body[clk_domain_str].push_back(os3.str()); - has_indent = true; - } else if (port.en != State::S1) { - std::ostringstream os; - os << stringf("if ("); - dump_sigspec(os, port.en); - os << stringf(") begin\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); - has_indent = true; - } - - for (int sub = 0; sub < (1 << port.wide_log2); sub++) - { - SigSpec addr = port.sub_addr(sub); - std::ostringstream os; - if (has_indent) - os << indent; - os << temp_id; - if (port.wide_log2) - os << stringf("[%d:%d]", (sub + 1) * mem.width - 1, sub * mem.width); - os << stringf(" <= %s[", mem_id.c_str()); - dump_sigspec(os, addr); - os << stringf("];\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); - } - - for (int i = 0; i < GetSize(mem.wr_ports); i++) { - auto &wport = mem.wr_ports[i]; - if (!port.transparency_mask[i] && !port.collision_x_mask[i]) - continue; - int min_wide_log2 = std::min(port.wide_log2, wport.wide_log2); - int max_wide_log2 = std::max(port.wide_log2, wport.wide_log2); - bool wide_write = wport.wide_log2 > port.wide_log2; - for (int sub = 0; sub < (1 << max_wide_log2); sub += (1 << min_wide_log2)) { - SigSpec raddr = port.addr; - SigSpec waddr = wport.addr; - if (wide_write) - waddr = wport.sub_addr(sub); - else - raddr = port.sub_addr(sub); - int pos = 0; - int ewidth = mem.width << min_wide_log2; - int wsub = wide_write ? sub : 0; - int rsub = wide_write ? 0 : sub; - while (pos < ewidth) { - int epos = pos; - while (epos < ewidth && wport.en[epos + wsub * mem.width] == wport.en[pos + wsub * mem.width]) - epos++; - - std::ostringstream os; - if (has_indent) - os << indent; - os << "if ("; - dump_sigspec(os, wport.en[pos + wsub * mem.width]); - if (raddr != waddr) { - os << " && "; - dump_sigspec(os, raddr); - os << " == "; - dump_sigspec(os, waddr); - } - os << ")\n"; - clk_to_lof_body[clk_domain_str].push_back(os.str()); - - std::ostringstream os2; - if (has_indent) - os2 << indent; - os2 << indent; - os2 << temp_id; - if (epos-pos != GetSize(port.data)) - os2 << stringf("[%d:%d]", rsub * mem.width + epos-1, rsub * mem.width + pos); - os2 << " <= "; - if (port.transparency_mask[i]) - dump_sigspec(os2, wport.data.extract(wsub * mem.width + pos, epos-pos)); - else - dump_sigspec(os2, Const(State::Sx, epos - pos)); - os2 << ";\n"; - clk_to_lof_body[clk_domain_str].push_back(os2.str()); - - pos = epos; - } - } - } - - if (port.srst != State::S0 && port.ce_over_srst) - { - std::ostringstream os; - if (has_indent) - os << indent; - os << stringf("if ("); - dump_sigspec(os, port.srst); - os << stringf(")\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); - std::ostringstream os2; - if (has_indent) - os2 << indent; - os2 << stringf("%s" "%s <= ", indent.c_str(), temp_id.c_str()); - dump_sigspec(os2, port.srst_value); - os2 << ";\n"; - clk_to_lof_body[clk_domain_str].push_back(os2.str()); - } - - if (has_indent) - clk_to_lof_body[clk_domain_str].push_back("end\n"); - - if (!port.init_value.is_fully_undef()) - { - std::ostringstream os; - dump_sigspec(os, port.init_value); - std::string line = stringf("initial %s = %s;\n", temp_id.c_str(), os.str().c_str()); - clk_to_lof_body[""].push_back(line); - } - - { - std::ostringstream os; - dump_sigspec(os, port.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", port.addr.size() - 1 - port.wide_log2, temp_id.c_str()) ); - { - std::ostringstream os; - dump_sigspec(os, port.addr.extract_end(port.wide_log2)); - 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); - } - for (int sub = 0; sub < (1 << port.wide_log2); sub++) - { - std::ostringstream os; - os << "assign "; - dump_sigspec(os, port.data.extract(sub * mem.width, mem.width)); - os << stringf(" = %s[", mem_id.c_str());; - if (port.wide_log2) { - Const addr_lo; - for (int i = 0; i < port.wide_log2; i++) - addr_lo.bits.push_back(State(sub >> i & 1)); - os << "{"; - os << temp_id; - os << ", "; - dump_const(os, addr_lo); - os << "}"; - } else { - os << temp_id; - } - os << "];\n"; - clk_to_lof_body[""].push_back(os.str()); - } - } - } else { - // for non-clocked read-ports make something like: - // assign r_data = array_reg[r_addr]; - for (int sub = 0; sub < (1 << port.wide_log2); sub++) - { - SigSpec addr = port.sub_addr(sub); - - std::ostringstream os, os2; - dump_sigspec(os, port.data.extract(sub * mem.width, mem.width)); - dump_sigspec(os2, 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); - } - } - } - - // Write ports. Those are messy because we try to preserve priority, as much as we can: - // - // 1. We split all ports into several disjoint processes. - // 2. If a port has priority over another port, the two ports need to share - // a process, so that priority can be reconstructed on the other end. - // 3. We want each process to be as small as possible, to avoid extra - // priorities inferred on the other end. - pool wr_ports_done; - for (int ridx = 0; ridx < GetSize(mem.wr_ports); ridx++) - { - if (wr_ports_done.count(ridx)) - continue; - - auto &root = mem.wr_ports[ridx]; - - // Start from a root. - pool wr_ports_now; - wr_ports_now.insert(ridx); - - // Transitively fill list of ports in this process by following priority edges. - while (true) - { - bool changed = false; - - for (int i = 0; i < GetSize(mem.wr_ports); i++) - for (int j = 0; j < i; j++) - if (mem.wr_ports[i].priority_mask[j]) - { - if (wr_ports_now.count(i) && !wr_ports_now.count(j)) { - wr_ports_now.insert(j); - changed = true; - } - if (!wr_ports_now.count(i) && wr_ports_now.count(j)) { - wr_ports_now.insert(i); - changed = true; - } - } - - if (!changed) - break; - } - - if (root.clk_enable) { - f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", root.clk_polarity ? "pos" : "neg"); - dump_sigspec(f, root.clk); - f << ") begin\n"; - } else { - f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_latch" : " @*"); - } - - for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++) - { - if (!wr_ports_now.count(pidx)) - continue; - wr_ports_done.insert(pidx); - - auto &port = mem.wr_ports[pidx]; - log_assert(port.clk_enable == root.clk_enable); - if (port.clk_enable) { - log_assert(port.clk == root.clk); - log_assert(port.clk_polarity == root.clk_polarity); - } - - // make something like: - // always @(posedge clk) - // if (wr_en_bit) memid[w_addr][??] <= w_data[??]; - // ... - for (int sub = 0; sub < (1 << port.wide_log2); sub++) - { - SigSpec addr = port.sub_addr(sub); - for (int i = 0; i < mem.width; i++) - { - int start_i = i, width = 1; - SigBit wen_bit = port.en[sub * mem.width + i]; - - while (i+1 < mem.width && active_sigmap(port.en[sub * mem.width + i+1]) == active_sigmap(wen_bit)) - i++, width++; - - if (wen_bit == State::S0) - continue; - - f << stringf("%s%s", indent.c_str(), indent.c_str()); - if (wen_bit != State::S1) - { - f << stringf("if ("); - dump_sigspec(f, wen_bit); - f << stringf(")\n"); - f << stringf("%s%s%s", indent.c_str(), indent.c_str(), indent.c_str()); - } - f << stringf("%s[", mem_id.c_str()); - dump_sigspec(f, addr); - if (width == GetSize(port.en)) - f << stringf("] <= "); - else - f << stringf("][%d:%d] <= ", i, start_i); - dump_sigspec(f, port.data.extract(sub * mem.width + start_i, width)); - f << stringf(";\n"); - } - } - } - - f << stringf("%s" "end\n", indent.c_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 @(%s) begin\n", indent.c_str(), systemverilog ? "_ff" : "", clk_domain.c_str()); - bool has_arst = clk_to_arst_cond.count(clk_domain) != 0; - if (has_arst) { - f << stringf("%s%s" "if (%s) begin\n", indent.c_str(), indent.c_str(), clk_to_arst_cond[clk_domain].c_str()); - for(auto &line : clk_to_arst_body[clk_domain]) - f << stringf("%s%s%s" "%s", indent.c_str(), indent.c_str(), indent.c_str(), line.c_str()); - f << stringf("%s%s" "end else begin\n", indent.c_str(), indent.c_str()); - for(auto &line : lof_lines) - f << stringf("%s%s%s" "%s", indent.c_str(), indent.c_str(), indent.c_str(), line.c_str()); - f << stringf("%s%s" "end\n", indent.c_str(), indent.c_str()); - } else { - 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()); - } - } -} - -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] == '$' && RTLIL::builtin_ff_cell_types().count(cell->type) && cell->hasPort(ID::Q) && !cell->type.in(ID($ff), ID($_FF_))) - { - RTLIL::SigSpec sig = cell->getPort(ID::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(ID::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(ID::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 == ID($_NOT_)) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::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(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = "); - if (cell->type.in(ID($_NAND_), ID($_NOR_), ID($_XNOR_))) - f << stringf("~("); - dump_cell_expr_port(f, cell, "A", false); - f << stringf(" "); - if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_ANDNOT_))) - f << stringf("&"); - if (cell->type.in(ID($_OR_), ID($_NOR_), ID($_ORNOT_))) - f << stringf("|"); - if (cell->type.in(ID($_XOR_), ID($_XNOR_))) - f << stringf("^"); - dump_attributes(f, "", cell->attributes, ' '); - f << stringf(" "); - if (cell->type.in(ID($_ANDNOT_), ID($_ORNOT_))) - f << stringf("~("); - dump_cell_expr_port(f, cell, "B", false); - if (cell->type.in(ID($_NAND_), ID($_NOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) - f << stringf(")"); - f << stringf(";\n"); - return true; - } - - if (cell->type == ID($_MUX_)) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::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 == ID($_NMUX_)) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::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(ID($_AOI3_), ID($_OAI3_))) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = ~(("); - dump_cell_expr_port(f, cell, "A", false); - f << stringf(cell->type == ID($_AOI3_) ? " & " : " | "); - dump_cell_expr_port(f, cell, "B", false); - f << stringf(cell->type == ID($_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(ID($_AOI4_), ID($_OAI4_))) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = ~(("); - dump_cell_expr_port(f, cell, "A", false); - f << stringf(cell->type == ID($_AOI4_) ? " & " : " | "); - dump_cell_expr_port(f, cell, "B", false); - f << stringf(cell->type == ID($_AOI4_) ? ") |" : ") &"); - dump_attributes(f, "", cell->attributes, ' '); - f << stringf(" ("); - dump_cell_expr_port(f, cell, "C", false); - f << stringf(cell->type == ID($_AOI4_) ? " & " : " | "); - dump_cell_expr_port(f, cell, "D", false); - f << stringf("));\n"); - 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(ID($not), "~") - HANDLE_UNIOP(ID($pos), "+") - HANDLE_UNIOP(ID($neg), "-") - - HANDLE_BINOP(ID($and), "&") - HANDLE_BINOP(ID($or), "|") - HANDLE_BINOP(ID($xor), "^") - HANDLE_BINOP(ID($xnor), "~^") - - HANDLE_UNIOP(ID($reduce_and), "&") - HANDLE_UNIOP(ID($reduce_or), "|") - HANDLE_UNIOP(ID($reduce_xor), "^") - HANDLE_UNIOP(ID($reduce_xnor), "~^") - HANDLE_UNIOP(ID($reduce_bool), "|") - - HANDLE_BINOP(ID($shl), "<<") - HANDLE_BINOP(ID($shr), ">>") - HANDLE_BINOP(ID($sshl), "<<<") - HANDLE_BINOP(ID($sshr), ">>>") - - HANDLE_BINOP(ID($lt), "<") - HANDLE_BINOP(ID($le), "<=") - HANDLE_BINOP(ID($eq), "==") - HANDLE_BINOP(ID($ne), "!=") - HANDLE_BINOP(ID($eqx), "===") - HANDLE_BINOP(ID($nex), "!==") - HANDLE_BINOP(ID($ge), ">=") - HANDLE_BINOP(ID($gt), ">") - - HANDLE_BINOP(ID($add), "+") - HANDLE_BINOP(ID($sub), "-") - HANDLE_BINOP(ID($mul), "*") - HANDLE_BINOP(ID($div), "/") - HANDLE_BINOP(ID($mod), "%") - HANDLE_BINOP(ID($pow), "**") - - HANDLE_UNIOP(ID($logic_not), "!") - HANDLE_BINOP(ID($logic_and), "&&") - HANDLE_BINOP(ID($logic_or), "||") - -#undef HANDLE_UNIOP -#undef HANDLE_BINOP - - if (cell->type == ID($divfloor)) - { - // wire [MAXLEN+1:0] _0_, _1_, _2_; - // assign _0_ = $signed(A); - // assign _1_ = $signed(B); - // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1)); - // assign Y = $signed(_2_) / $signed(_1_); - - if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) { - SigSpec sig_a = cell->getPort(ID::A); - SigSpec sig_b = cell->getPort(ID::B); - - std::string buf_a = next_auto_id(); - std::string buf_b = next_auto_id(); - std::string buf_num = next_auto_id(); - int size_a = GetSize(sig_a); - int size_b = GetSize(sig_b); - int size_y = GetSize(cell->getPort(ID::Y)); - int size_max = std::max(size_a, std::max(size_b, size_y)); - - // intentionally one wider than maximum width - f << stringf("%s" "wire [%d:0] %s, %s, %s;\n", indent.c_str(), size_max, buf_a.c_str(), buf_b.c_str(), buf_num.c_str()); - f << stringf("%s" "assign %s = ", indent.c_str(), buf_a.c_str()); - dump_cell_expr_port(f, cell, "A", true); - f << stringf(";\n"); - f << stringf("%s" "assign %s = ", indent.c_str(), buf_b.c_str()); - dump_cell_expr_port(f, cell, "B", true); - f << stringf(";\n"); - - f << stringf("%s" "assign %s = ", indent.c_str(), buf_num.c_str()); - f << stringf("("); - dump_sigspec(f, sig_a.extract(sig_a.size()-1)); - f << stringf(" == "); - dump_sigspec(f, sig_b.extract(sig_b.size()-1)); - f << stringf(") || "); - dump_sigspec(f, sig_a); - f << stringf(" == 0 ? %s : ", buf_a.c_str()); - f << stringf("$signed(%s - (", buf_a.c_str()); - dump_sigspec(f, sig_b.extract(sig_b.size()-1)); - f << stringf(" ? %s + 1 : %s - 1));\n", buf_b.c_str(), buf_b.c_str()); - - - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = $signed(%s) / ", buf_num.c_str()); - dump_attributes(f, "", cell->attributes, ' '); - f << stringf("$signed(%s);\n", buf_b.c_str()); - return true; - } else { - // same as truncating division - dump_cell_expr_binop(f, indent, cell, "/"); - return true; - } - } - - if (cell->type == ID($modfloor)) - { - // wire truncated = $signed(A) % $signed(B); - // assign Y = (A[-1] == B[-1]) || truncated == 0 ? $signed(truncated) : $signed(B) + $signed(truncated); - - if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) { - SigSpec sig_a = cell->getPort(ID::A); - SigSpec sig_b = cell->getPort(ID::B); - - std::string temp_id = next_auto_id(); - f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str()); - dump_cell_expr_port(f, cell, "A", true); - f << stringf(" %% "); - dump_attributes(f, "", cell->attributes, ' '); - dump_cell_expr_port(f, cell, "B", true); - f << stringf(";\n"); - - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = ("); - dump_sigspec(f, sig_a.extract(sig_a.size()-1)); - f << stringf(" == "); - dump_sigspec(f, sig_b.extract(sig_b.size()-1)); - f << stringf(") || %s == 0 ? $signed(%s) : ", temp_id.c_str(), temp_id.c_str()); - dump_cell_expr_port(f, cell, "B", true); - f << stringf(" + $signed(%s);\n", temp_id.c_str()); - return true; - } else { - // same as truncating modulo - dump_cell_expr_binop(f, indent, cell, "%"); - return true; - } - } - - if (cell->type == ID($shift)) - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = "); - if (cell->getParam(ID::B_SIGNED).as_bool()) - { - dump_cell_expr_port(f, cell, "B", true); - f << stringf(" < 0 ? "); - dump_cell_expr_port(f, cell, "A", true); - f << stringf(" << - "); - dump_sigspec(f, cell->getPort(ID::B)); - f << stringf(" : "); - dump_cell_expr_port(f, cell, "A", true); - f << stringf(" >> "); - dump_sigspec(f, cell->getPort(ID::B)); - } - else - { - dump_cell_expr_port(f, cell, "A", true); - f << stringf(" >> "); - dump_sigspec(f, cell->getPort(ID::B)); - } - f << stringf(";\n"); - return true; - } - - if (cell->type == ID($shiftx)) - { - std::string temp_id = next_auto_id(); - f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str()); - dump_sigspec(f, cell->getPort(ID::A)); - f << stringf(";\n"); - - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = %s[", temp_id.c_str()); - if (cell->getParam(ID::B_SIGNED).as_bool()) - f << stringf("$signed("); - dump_sigspec(f, cell->getPort(ID::B)); - if (cell->getParam(ID::B_SIGNED).as_bool()) - f << stringf(")"); - f << stringf(" +: %d", cell->getParam(ID::Y_WIDTH).as_int()); - f << stringf("];\n"); - return true; - } - - if (cell->type == ID($mux)) - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = "); - dump_sigspec(f, cell->getPort(ID::S)); - f << stringf(" ? "); - dump_attributes(f, "", cell->attributes, ' '); - dump_sigspec(f, cell->getPort(ID::B)); - f << stringf(" : "); - dump_sigspec(f, cell->getPort(ID::A)); - f << stringf(";\n"); - return true; - } - - if (cell->type == ID($pmux)) - { - int width = cell->parameters[ID::WIDTH].as_int(); - int s_width = cell->getPort(ID::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 (noparallelcase) - f << stringf("%s" " case (s)\n", indent.c_str()); - else { - if (!noattr) - f << stringf("%s" " (* parallel_case *)\n", indent.c_str()); - f << stringf("%s" " casez (s)", indent.c_str()); - 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' : noparallelcase ? '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); - } - - if (noparallelcase) { - f << stringf("%s" " %d'b", indent.c_str(), s_width); - for (int j = s_width-1; j >= 0; j--) - f << '0'; - f << stringf(":\n"); - } else - f << stringf("%s" " default:\n", indent.c_str()); - f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str()); - if (noparallelcase) { - f << stringf("%s" " default:\n", indent.c_str()); - f << stringf("%s" " %s = %d'bx;\n", indent.c_str(), func_name.c_str(), width); - } - - 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(ID::Y)); - f << stringf(" = %s(", func_name.c_str()); - dump_sigspec(f, cell->getPort(ID::A)); - f << stringf(", "); - dump_sigspec(f, cell->getPort(ID::B)); - f << stringf(", "); - dump_sigspec(f, cell->getPort(ID::S)); - f << stringf(");\n"); - return true; - } - - if (cell->type == ID($tribuf)) - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = "); - dump_sigspec(f, cell->getPort(ID::EN)); - f << stringf(" ? "); - dump_sigspec(f, cell->getPort(ID::A)); - f << stringf(" : %d'bz;\n", cell->parameters.at(ID::WIDTH).as_int()); - return true; - } - - if (cell->type == ID($slice)) - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = "); - dump_sigspec(f, cell->getPort(ID::A)); - f << stringf(" >> %d;\n", cell->parameters.at(ID::OFFSET).as_int()); - return true; - } - - if (cell->type == ID($concat)) - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = { "); - dump_sigspec(f, cell->getPort(ID::B)); - f << stringf(" , "); - dump_sigspec(f, cell->getPort(ID::A)); - f << stringf(" };\n"); - return true; - } - - if (cell->type == ID($lut)) - { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort(ID::Y)); - f << stringf(" = "); - dump_const(f, cell->parameters.at(ID::LUT)); - f << stringf(" >> "); - dump_attributes(f, "", cell->attributes, ' '); - dump_sigspec(f, cell->getPort(ID::A)); - f << stringf(";\n"); - return true; - } - - if (RTLIL::builtin_ff_cell_types().count(cell->type)) - { - FfData ff(nullptr, cell); - - // $ff / $_FF_ cell: not supported. - if (ff.has_gclk) - return false; - - std::string reg_name = cellname(cell); - bool out_is_reg_wire = is_reg_wire(ff.sig_q, reg_name); - - if (!out_is_reg_wire) { - if (ff.width == 1) - f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str()); - else - f << stringf("%s" "reg [%d:0] %s", indent.c_str(), ff.width-1, reg_name.c_str()); - dump_reg_init(f, ff.sig_q); - f << ";\n"; - } - - // If the FF has CLR/SET inputs, emit every bit slice separately. - int chunks = ff.has_sr ? ff.width : 1; - bool chunky = ff.has_sr && ff.width != 1; - - for (int i = 0; i < chunks; i++) - { - SigSpec sig_d, sig_ad; - Const val_arst, val_srst; - std::string reg_bit_name, sig_set_name, sig_clr_name, sig_arst_name, sig_aload_name; - if (chunky) { - reg_bit_name = stringf("%s[%d]", reg_name.c_str(), i); - if (ff.has_gclk || ff.has_clk) - sig_d = ff.sig_d[i]; - if (ff.has_aload) - sig_ad = ff.sig_ad[i]; - } else { - reg_bit_name = reg_name; - sig_d = ff.sig_d; - sig_ad = ff.sig_ad; - } - if (ff.has_arst) - val_arst = chunky ? ff.val_arst[i] : ff.val_arst; - if (ff.has_srst) - val_srst = chunky ? ff.val_srst[i] : ff.val_srst; - - // If there are constants in the sensitivity list, replace them with an intermediate wire - if (ff.has_clk) { - if (ff.has_sr) { - if (ff.sig_set[i].wire == NULL) - { - sig_set_name = next_auto_id(); - f << stringf("%s" "wire %s = ", indent.c_str(), sig_set_name.c_str()); - dump_const(f, ff.sig_set[i].data); - f << stringf(";\n"); - } - if (ff.sig_clr[i].wire == NULL) - { - sig_clr_name = next_auto_id(); - f << stringf("%s" "wire %s = ", indent.c_str(), sig_clr_name.c_str()); - dump_const(f, ff.sig_clr[i].data); - f << stringf(";\n"); - } - } else if (ff.has_arst) { - if (ff.sig_arst[0].wire == NULL) - { - sig_arst_name = next_auto_id(); - f << stringf("%s" "wire %s = ", indent.c_str(), sig_arst_name.c_str()); - dump_const(f, ff.sig_arst[0].data); - f << stringf(";\n"); - } - } else if (ff.has_aload) { - if (ff.sig_aload[0].wire == NULL) - { - sig_aload_name = next_auto_id(); - f << stringf("%s" "wire %s = ", indent.c_str(), sig_aload_name.c_str()); - dump_const(f, ff.sig_aload[0].data); - f << stringf(";\n"); - } - } - } - - dump_attributes(f, indent, cell->attributes); - if (ff.has_clk) - { - // FFs. - f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", ff.pol_clk ? "pos" : "neg"); - dump_sigspec(f, ff.sig_clk); - if (ff.has_sr) { - f << stringf(", %sedge ", ff.pol_set ? "pos" : "neg"); - if (ff.sig_set[i].wire == NULL) - f << stringf("%s", sig_set_name.c_str()); - else - dump_sigspec(f, ff.sig_set[i]); - - f << stringf(", %sedge ", ff.pol_clr ? "pos" : "neg"); - if (ff.sig_clr[i].wire == NULL) - f << stringf("%s", sig_clr_name.c_str()); - else - dump_sigspec(f, ff.sig_clr[i]); - } else if (ff.has_arst) { - f << stringf(", %sedge ", ff.pol_arst ? "pos" : "neg"); - if (ff.sig_arst[0].wire == NULL) - f << stringf("%s", sig_arst_name.c_str()); - else - dump_sigspec(f, ff.sig_arst); - } else if (ff.has_aload) { - f << stringf(", %sedge ", ff.pol_aload ? "pos" : "neg"); - if (ff.sig_aload[0].wire == NULL) - f << stringf("%s", sig_aload_name.c_str()); - else - dump_sigspec(f, ff.sig_aload); - } - f << stringf(")\n"); - - f << stringf("%s" " ", indent.c_str()); - if (ff.has_sr) { - f << stringf("if (%s", ff.pol_clr ? "" : "!"); - if (ff.sig_clr[i].wire == NULL) - f << stringf("%s", sig_clr_name.c_str()); - else - dump_sigspec(f, ff.sig_clr[i]); - f << stringf(") %s <= 1'b0;\n", reg_bit_name.c_str()); - f << stringf("%s" " else if (%s", indent.c_str(), ff.pol_set ? "" : "!"); - if (ff.sig_set[i].wire == NULL) - f << stringf("%s", sig_set_name.c_str()); - else - dump_sigspec(f, ff.sig_set[i]); - f << stringf(") %s <= 1'b1;\n", reg_bit_name.c_str()); - f << stringf("%s" " else ", indent.c_str()); - } else if (ff.has_arst) { - f << stringf("if (%s", ff.pol_arst ? "" : "!"); - if (ff.sig_arst[0].wire == NULL) - f << stringf("%s", sig_arst_name.c_str()); - else - dump_sigspec(f, ff.sig_arst); - f << stringf(") %s <= ", reg_bit_name.c_str()); - dump_sigspec(f, val_arst); - f << stringf(";\n"); - f << stringf("%s" " else ", indent.c_str()); - } else if (ff.has_aload) { - f << stringf("if (%s", ff.pol_aload ? "" : "!"); - if (ff.sig_aload[0].wire == NULL) - f << stringf("%s", sig_aload_name.c_str()); - else - dump_sigspec(f, ff.sig_aload); - f << stringf(") %s <= ", reg_bit_name.c_str()); - dump_sigspec(f, sig_ad); - f << stringf(";\n"); - f << stringf("%s" " else ", indent.c_str()); - } - - if (ff.has_srst && ff.has_ce && ff.ce_over_srst) { - f << stringf("if (%s", ff.pol_ce ? "" : "!"); - dump_sigspec(f, ff.sig_ce); - f << stringf(")\n"); - f << stringf("%s" " if (%s", indent.c_str(), ff.pol_srst ? "" : "!"); - dump_sigspec(f, ff.sig_srst); - f << stringf(") %s <= ", reg_bit_name.c_str()); - dump_sigspec(f, val_srst); - f << stringf(";\n"); - f << stringf("%s" " else ", indent.c_str()); - } else { - if (ff.has_srst) { - f << stringf("if (%s", ff.pol_srst ? "" : "!"); - dump_sigspec(f, ff.sig_srst); - f << stringf(") %s <= ", reg_bit_name.c_str()); - dump_sigspec(f, val_srst); - f << stringf(";\n"); - f << stringf("%s" " else ", indent.c_str()); - } - if (ff.has_ce) { - f << stringf("if (%s", ff.pol_ce ? "" : "!"); - dump_sigspec(f, ff.sig_ce); - f << stringf(") "); - } - } - - f << stringf("%s <= ", reg_bit_name.c_str()); - dump_sigspec(f, sig_d); - f << stringf(";\n"); - } - else - { - // Latches. - f << stringf("%s" "always%s\n", indent.c_str(), systemverilog ? "_latch" : " @*"); - - f << stringf("%s" " ", indent.c_str()); - if (ff.has_sr) { - f << stringf("if (%s", ff.pol_clr ? "" : "!"); - dump_sigspec(f, ff.sig_clr[i]); - f << stringf(") %s = 1'b0;\n", reg_bit_name.c_str()); - f << stringf("%s" " else if (%s", indent.c_str(), ff.pol_set ? "" : "!"); - dump_sigspec(f, ff.sig_set[i]); - f << stringf(") %s = 1'b1;\n", reg_bit_name.c_str()); - if (ff.has_aload) - f << stringf("%s" " else ", indent.c_str()); - } else if (ff.has_arst) { - f << stringf("if (%s", ff.pol_arst ? "" : "!"); - dump_sigspec(f, ff.sig_arst); - f << stringf(") %s = ", reg_bit_name.c_str()); - dump_sigspec(f, val_arst); - f << stringf(";\n"); - if (ff.has_aload) - f << stringf("%s" " else ", indent.c_str()); - } - if (ff.has_aload) { - f << stringf("if (%s", ff.pol_aload ? "" : "!"); - dump_sigspec(f, ff.sig_aload); - f << stringf(") %s = ", reg_bit_name.c_str()); - dump_sigspec(f, sig_ad); - f << stringf(";\n"); - } - } - } - - if (!out_is_reg_wire) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, ff.sig_q); - f << stringf(" = %s;\n", reg_name.c_str()); - } - - return true; - } - - if (cell->type.in(ID($assert), ID($assume), ID($cover))) - { - f << stringf("%s" "always%s if (", indent.c_str(), systemverilog ? "_comb" : " @*"); - dump_sigspec(f, cell->getPort(ID::EN)); - f << stringf(") %s(", cell->type.c_str()+1); - dump_sigspec(f, cell->getPort(ID::A)); - f << stringf(");\n"); - return true; - } - - if (cell->type.in(ID($specify2), ID($specify3))) - { - f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str()); - - SigSpec en = cell->getPort(ID::EN); - if (en != State::S1) { - f << stringf("if ("); - dump_sigspec(f, cell->getPort(ID::EN)); - f << stringf(") "); - } - - f << "("; - if (cell->type == ID($specify3) && cell->getParam(ID::EDGE_EN).as_bool()) - f << (cell->getParam(ID::EDGE_POL).as_bool() ? "posedge ": "negedge "); - - dump_sigspec(f, cell->getPort(ID::SRC)); - - f << " "; - if (cell->getParam(ID::SRC_DST_PEN).as_bool()) - f << (cell->getParam(ID::SRC_DST_POL).as_bool() ? "+": "-"); - f << (cell->getParam(ID::FULL).as_bool() ? "*> ": "=> "); - - if (cell->type == ID($specify3)) { - f << "("; - dump_sigspec(f, cell->getPort(ID::DST)); - f << " "; - if (cell->getParam(ID::DAT_DST_PEN).as_bool()) - f << (cell->getParam(ID::DAT_DST_POL).as_bool() ? "+": "-"); - f << ": "; - dump_sigspec(f, cell->getPort(ID::DAT)); - f << ")"; - } else { - dump_sigspec(f, cell->getPort(ID::DST)); - } - - bool bak_decimal = decimal; - decimal = 1; - - f << ") = ("; - dump_const(f, cell->getParam(ID::T_RISE_MIN)); - f << ":"; - dump_const(f, cell->getParam(ID::T_RISE_TYP)); - f << ":"; - dump_const(f, cell->getParam(ID::T_RISE_MAX)); - f << ", "; - dump_const(f, cell->getParam(ID::T_FALL_MIN)); - f << ":"; - dump_const(f, cell->getParam(ID::T_FALL_TYP)); - f << ":"; - dump_const(f, cell->getParam(ID::T_FALL_MAX)); - f << ");\n"; - - decimal = bak_decimal; - - f << stringf("%s" "endspecify\n", indent.c_str()); - return true; - } - - if (cell->type == ID($specrule)) - { - f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str()); - - IdString spec_type = cell->getParam(ID::TYPE).decode_string(); - f << stringf("%s(", spec_type.c_str()); - - if (cell->getParam(ID::SRC_PEN).as_bool()) - f << (cell->getParam(ID::SRC_POL).as_bool() ? "posedge ": "negedge "); - dump_sigspec(f, cell->getPort(ID::SRC)); - - if (cell->getPort(ID::SRC_EN) != State::S1) { - f << " &&& "; - dump_sigspec(f, cell->getPort(ID::SRC_EN)); - } - - f << ", "; - if (cell->getParam(ID::DST_PEN).as_bool()) - f << (cell->getParam(ID::DST_POL).as_bool() ? "posedge ": "negedge "); - dump_sigspec(f, cell->getPort(ID::DST)); - - if (cell->getPort(ID::DST_EN) != State::S1) { - f << " &&& "; - dump_sigspec(f, cell->getPort(ID::DST_EN)); - } - - bool bak_decimal = decimal; - decimal = 1; - - f << ", "; - dump_const(f, cell->getParam(ID::T_LIMIT_MIN)); - f << ": "; - dump_const(f, cell->getParam(ID::T_LIMIT_TYP)); - f << ": "; - dump_const(f, cell->getParam(ID::T_LIMIT_MAX)); - - if (spec_type.in(ID($setuphold), ID($recrem), ID($fullskew))) { - f << ", "; - dump_const(f, cell->getParam(ID::T_LIMIT2_MIN)); - f << ": "; - dump_const(f, cell->getParam(ID::T_LIMIT2_TYP)); - f << ": "; - dump_const(f, cell->getParam(ID::T_LIMIT2_MAX)); - } - - f << ");\n"; - decimal = bak_decimal; - - f << stringf("%s" "endspecify\n", indent.c_str()); - return true; - } - - // FIXME: $fsm - - return false; -} - -void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) -{ - // Handled by dump_memory - if (cell->is_mem_cell()) - return; - - 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 && RTLIL::builtin_ff_cell_types().count(cell->type) && cell->hasPort(ID::Q) && !cell->type.in(ID($ff), ID($_FF_))) { - std::stringstream ss; - dump_reg_init(ss, cell->getPort(ID::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) -{ - if (simple_lhs) { - int offset = 0; - for (auto &chunk : left.chunks()) { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, chunk); - f << stringf(" = "); - dump_sigspec(f, right.extract(offset, GetSize(chunk))); - f << stringf(";\n"); - offset += GetSize(chunk); - } - } else { - 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, /*regattr=*/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%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*"); - if (!systemverilog) - f << indent + " " << "if (" << id(initial_id) << ") begin end\n"; - 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%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*"); - } else if (sync->type == RTLIL::STi) { - f << stringf("%s" "initial begin\n", indent.c_str()); - } else { - f << stringf("%s" "always%s @(", indent.c_str(), systemverilog ? "_ff" : ""); - 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(ID::init)) { - SigSpec sig = active_sigmap(wire); - Const val = wire->attributes.at(ID::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 cell : module->cells()) - { - if (!RTLIL::builtin_ff_cell_types().count(cell->type) || !cell->hasPort(ID::Q) || cell->type.in(ID($ff), ID($_FF_))) - continue; - - RTLIL::SigSpec sig = cell->getPort(ID::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 wire : module->wires()) - { - 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', /*modattr=*/true); - f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str()); - bool keep_running = true; - int cnt = 0; - for (int port_id = 1; keep_running; port_id++) { - keep_running = false; - for (auto wire : module->wires()) { - if (wire->port_id == port_id) { - if (port_id != 1) - f << stringf(", "); - f << stringf("%s", id(wire->name).c_str()); - keep_running = true; - if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++; - continue; - } - } - } - f << stringf(");\n"); - if (!systemverilog && !module->processes.empty()) { - initial_id = NEW_ID; - f << indent + " " << "reg " << id(initial_id) << " = 0;\n"; - } - - for (auto w : module->wires()) - dump_wire(f, indent + " ", w); - - for (auto &mem : Mem::get_all_memories(module)) - dump_memory(f, indent + " ", mem); - - for (auto cell : module->cells()) - dump_cell(f, indent + " ", cell); - - 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() 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(" -sv\n"); - log(" with this option, SystemVerilog constructs like always_comb are used\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(" -noparallelcase\n"); - log(" With this option no parallel_case attributes are used. Instead, a case\n"); - log(" statement that assigns don't-care values for priority dependent inputs\n"); - log(" is generated.\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(" -simple-lhs\n"); - log(" Connection assignments with simple left hand side without\n"); - log(" concatenations.\n"); - log("\n"); - log(" -extmem\n"); - log(" instead of initializing memories using assignments to individual\n"); - log(" elements, use the '$readmemh' function to read initialization data\n"); - log(" from a file. This data is written to a file named by appending\n"); - log(" a sequential index to the Verilog filename and replacing the extension\n"); - log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n"); - log(" 'foo-2.mem' and so on.\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) override - { - log_header(design, "Executing Verilog backend.\n"); - - verbose = false; - norename = false; - noattr = false; - attr2comment = false; - noexpr = false; - nodec = false; - nohex = false; - nostr = false; - extmem = false; - defparam = false; - decimal = false; - siminit = false; - simple_lhs = false; - noparallelcase = false; - auto_prefix = ""; - - bool blackboxes = false; - bool selected = false; - - auto_name_map.clear(); - reg_wires.clear(); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-sv") { - systemverilog = true; - continue; - } - 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 == "-noparallelcase") { - noparallelcase = true; - continue; - } - if (arg == "-nodec") { - nodec = true; - continue; - } - if (arg == "-nohex") { - nohex = true; - continue; - } - if (arg == "-nostr") { - nostr = true; - continue; - } - if (arg == "-extmem") { - extmem = true; - extmem_counter = 1; - 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 == "-simple-lhs") { - simple_lhs = true; - continue; - } - if (arg == "-v") { - verbose = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - if (extmem) - { - if (filename == "") - log_cmd_error("Option -extmem must be used with a filename.\n"); - extmem_prefix = filename.substr(0, filename.rfind('.')); - } - - log_push(); - if (!noexpr) { - Pass::call(design, "bmuxmap"); - Pass::call(design, "demuxmap"); - Pass::call(design, "bwmuxmap"); - } - Pass::call(design, "clean_zerowidth"); - log_pop(); - - design->sort(); - - *f << stringf("/* Generated by %s */\n", yosys_version_str); - for (auto module : design->modules()) { - if (module->get_blackbox_attribute() != blackboxes) - 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", log_id(module->name)); - continue; - } - log("Dumping module `%s'.\n", module->name.c_str()); - dump_module(*f, "", module); - } - - auto_name_map.clear(); - reg_wires.clear(); - } -} VerilogBackend; - -PRIVATE_NAMESPACE_END diff --git a/yosys/docs/.gitignore b/yosys/docs/.gitignore deleted file mode 100644 index e36f2309a01..00000000000 --- a/yosys/docs/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -/build/ -/source/cmd -/source/temp -/images/*.log -/images/*.aux -/images/*.pdf -/images/*.svg -/images/011/*.log -/images/011/*.aux -/images/011/*.pdf -/images/011/*.svg diff --git a/yosys/docs/Makefile b/yosys/docs/Makefile deleted file mode 100644 index 2319e1665c3..00000000000 --- a/yosys/docs/Makefile +++ /dev/null @@ -1,226 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " epub3 to make an epub3" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - @echo " dummy to check syntax errors of document sources" - -.PHONY: clean -clean: - rm -rf $(BUILDDIR)/* - -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -.PHONY: dirhtml -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -# singlehtml section links are broken -.PHONY: singlehtml -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -.PHONY: pickle -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -.PHONY: json -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -.PHONY: htmlhelp -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -.PHONY: qthelp -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SymbiYosys.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SymbiYosys.qhc" - -.PHONY: applehelp -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -.PHONY: devhelp -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/SymbiYosys" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SymbiYosys" - @echo "# devhelp" - -.PHONY: epub -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -.PHONY: epub3 -epub3: - $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 - @echo - @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." - -.PHONY: latex -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -.PHONY: latexpdf -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -.PHONY: latexpdfja -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -.PHONY: text -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -.PHONY: texinfo -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -.PHONY: info -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -.PHONY: gettext -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -.PHONY: changes -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -.PHONY: linkcheck -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -.PHONY: doctest -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -.PHONY: coverage -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -.PHONY: xml -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -.PHONY: pseudoxml -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." - -.PHONY: dummy -dummy: - $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy - @echo - @echo "Build finished. Dummy builder generates no files." diff --git a/yosys/docs/images/011/example_out.tex b/yosys/docs/images/011/example_out.tex deleted file mode 100644 index 831b036e993..00000000000 --- a/yosys/docs/images/011/example_out.tex +++ /dev/null @@ -1,18 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\usepackage{tikz} -\pagestyle{empty} - -\begin{document} -\begin{tikzpicture} - \node[inner sep=0pt] at (0,0) - {\includegraphics[width=\linewidth]{example_00.pdf}}; - \node[inner sep=0pt] at (0,-3.8) - {\includegraphics[width=\linewidth]{example_01.pdf}}; - \node[inner sep=0pt] at (0,-7) - {\includegraphics[width=\linewidth]{example_02.pdf}}; -\end{tikzpicture} -\end{document} diff --git a/yosys/docs/images/011/select_prod.tex b/yosys/docs/images/011/select_prod.tex deleted file mode 100644 index c4a3c6e379b..00000000000 --- a/yosys/docs/images/011/select_prod.tex +++ /dev/null @@ -1,19 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\pagestyle{empty} - -\begin{document} -\begin{tikzpicture} - \node[inner sep=0pt] at (0,0) - {\hfill \includegraphics[width=4cm,trim=0 1cm 0 1cm]{sumprod_02.pdf}}; - \node[inner sep=0pt] at (0,-2.8) - {\includegraphics[width=\linewidth,trim=0 0cm 0 1cm]{sumprod_03.pdf}}; - \node[inner sep=0pt] at (0,-6.2) - {\includegraphics[width=\linewidth,trim=0 0cm 0 1cm]{sumprod_04.pdf}}; - \node[inner sep=0pt] at (0,-9.2) - {\includegraphics[width=\linewidth,trim=0 1cm 0 1cm]{sumprod_05.pdf}}; -\end{tikzpicture} -\end{document} diff --git a/yosys/docs/images/011/splitnets_libfile.tex b/yosys/docs/images/011/splitnets_libfile.tex deleted file mode 100644 index 9669ef841b0..00000000000 --- a/yosys/docs/images/011/splitnets_libfile.tex +++ /dev/null @@ -1,15 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\pagestyle{empty} - -\begin{document} -\begin{tikzpicture} - \node[inner sep=0pt] at (0,0) - {\includegraphics[height=\linewidth]{cmos_00.pdf}}; - \node[inner sep=0pt] at (2,-8) - {\includegraphics[width=\linewidth]{cmos_01.pdf}}; -\end{tikzpicture} -\end{document} diff --git a/yosys/docs/images/011/submod_dots.tex b/yosys/docs/images/011/submod_dots.tex deleted file mode 100644 index 3d48b46e5a5..00000000000 --- a/yosys/docs/images/011/submod_dots.tex +++ /dev/null @@ -1,27 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\pagestyle{empty} - -\begin{document} -\begin{tikzpicture} - \node[inner sep=0pt] at (0,0) - {\includegraphics[width=\linewidth,trim=0 1.3cm 0 0cm]{submod_00.pdf}}; - \node at (0, -2.5) - {\tt memdemo}; - \node[inner sep=0pt] at (0,-5) - {\includegraphics[width=\linewidth,trim=0 1.3cm 0 0cm]{submod_01.pdf}}; - \node at (0, -7.5) - {\tt scramble}; - \node[inner sep=0pt] at (0, -11) - {\includegraphics[width=\linewidth,trim=0 1.3cm 0 0cm]{submod_02.pdf}}; - \node at (0, -14.8) - {\tt outstage}; - \node[inner sep=0pt] at (0,-16.6) - {\includegraphics[width=\linewidth,trim=0 1.3cm 0 0cm]{submod_03.pdf}}; - \node at (0, -19) - {\tt selstage}; -\end{tikzpicture} -\end{document} diff --git a/yosys/docs/images/Makefile b/yosys/docs/images/Makefile deleted file mode 100644 index a7216ec9010..00000000000 --- a/yosys/docs/images/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -all: dots tex svg tidy - -TEX_SOURCE:= $(wildcard *.tex) -DOT_LOC:= ../source/APPNOTE_011_Design_Investigation -DOT_SOURCE:= $(wildcard $(DOT_LOC)/*.dot) - -TEX_SOURCE+= 011/example_out.tex -011/example_out.pdf: 011/example_00.pdf 011/example_01.pdf 011/example_02.pdf -TEX_SOURCE+= 011/select_prod.tex -011/select_prod.pdf: 011/sumprod_02.pdf 011/sumprod_03.pdf 011/sumprod_04.pdf 011/sumprod_05.pdf -TEX_SOURCE+= 011/splitnets_libfile.tex -011/splitnets_libfile.pdf: 011/cmos_00.pdf 011/cmos_01.pdf -TEX_SOURCE+= 011/submod_dots.tex -011/submod_dots.pdf: 011/submod_00.pdf 011/submod_01.pdf 011/submod_02.pdf 011/submod_03.pdf - -TEX_PDF:= $(patsubst %.tex,%.pdf,$(TEX_SOURCE)) -DOT_PDF:= $(addprefix 011/,$(notdir $(patsubst %.dot,%.pdf,$(DOT_SOURCE)))) -SVG_OUTPUT:= $(patsubst %.pdf,%.svg,$(TEX_PDF) $(DOT_PDF)) - -dots: $(DOT_PDF) -tex: $(TEX_PDF) -svg: $(SVG_OUTPUT) - -011/%.pdf: $(DOT_LOC)/%.dot - faketime -f '2022-01-01 00:00:00 x0,001' dot -Tpdf -o $@ $< - -011/%.pdf: 011/%.tex - cd 011 && faketime -f '2022-01-01 00:00:00 x0,001' pdflatex $(] (cursor) -- node[above] {Low-Level} ++(3,0); - -\end{tikzpicture} -\end{document} diff --git a/yosys/docs/images/basics_abstractions.png b/yosys/docs/images/basics_abstractions.png deleted file mode 100644 index a735fbd3b5e..00000000000 Binary files a/yosys/docs/images/basics_abstractions.png and /dev/null differ diff --git a/yosys/docs/images/basics_abstractions.tex b/yosys/docs/images/basics_abstractions.tex deleted file mode 100644 index ece06362348..00000000000 --- a/yosys/docs/images/basics_abstractions.tex +++ /dev/null @@ -1,41 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\usepackage{amsmath} -\usepackage{pgfplots} -\usepackage{tikz} -\pagestyle{empty} - -\begin{document} -\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} -\end{document} diff --git a/yosys/docs/images/basics_ast.png b/yosys/docs/images/basics_ast.png deleted file mode 100644 index c2d95c844a9..00000000000 Binary files a/yosys/docs/images/basics_ast.png and /dev/null differ diff --git a/yosys/docs/images/basics_ast.tex b/yosys/docs/images/basics_ast.tex deleted file mode 100644 index dac6a8d47d8..00000000000 --- a/yosys/docs/images/basics_ast.tex +++ /dev/null @@ -1,30 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\usepackage{amsmath} -\usepackage{pgfplots} -\usepackage{tikz} -\usetikzlibrary{shapes.geometric} -\pagestyle{empty} - -\begin{document} -\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} -\end{document} diff --git a/yosys/docs/images/basics_flow.png b/yosys/docs/images/basics_flow.png deleted file mode 100644 index a027b5eac3e..00000000000 Binary files a/yosys/docs/images/basics_flow.png and /dev/null differ diff --git a/yosys/docs/images/basics_flow.tex b/yosys/docs/images/basics_flow.tex deleted file mode 100644 index 53b55548768..00000000000 --- a/yosys/docs/images/basics_flow.tex +++ /dev/null @@ -1,44 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\usepackage{amsmath} -\usepackage{pgfplots} -\usepackage{tikz} -\pagestyle{empty} - -\begin{document} -\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} -\end{document} diff --git a/yosys/docs/images/basics_parsetree.png b/yosys/docs/images/basics_parsetree.png deleted file mode 100644 index ff7a17e2bd2..00000000000 Binary files a/yosys/docs/images/basics_parsetree.png and /dev/null differ diff --git a/yosys/docs/images/basics_parsetree.tex b/yosys/docs/images/basics_parsetree.tex deleted file mode 100644 index 1c8392b8892..00000000000 --- a/yosys/docs/images/basics_parsetree.tex +++ /dev/null @@ -1,44 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\usepackage{amsmath} -\usepackage{pgfplots} -\usepackage{tikz} -\usetikzlibrary{shapes.geometric} -\pagestyle{empty} - -\begin{document} -\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} -\end{document} diff --git a/yosys/docs/images/overview_flow.png b/yosys/docs/images/overview_flow.png deleted file mode 100644 index c1b13a000b6..00000000000 Binary files a/yosys/docs/images/overview_flow.png and /dev/null differ diff --git a/yosys/docs/images/overview_flow.tex b/yosys/docs/images/overview_flow.tex deleted file mode 100644 index ac0afde5fda..00000000000 --- a/yosys/docs/images/overview_flow.tex +++ /dev/null @@ -1,37 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\usepackage{amsmath} -\usepackage{pgfplots} -\usepackage{tikz} -\usetikzlibrary{shapes.geometric} -\pagestyle{empty} - -\begin{document} -\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] {RTLIL 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] {RTLIL 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} -\end{document} diff --git a/yosys/docs/images/overview_rtlil.png b/yosys/docs/images/overview_rtlil.png deleted file mode 100644 index f79c667e8b4..00000000000 Binary files a/yosys/docs/images/overview_rtlil.png and /dev/null differ diff --git a/yosys/docs/images/overview_rtlil.tex b/yosys/docs/images/overview_rtlil.tex deleted file mode 100644 index ddacbff00c8..00000000000 --- a/yosys/docs/images/overview_rtlil.tex +++ /dev/null @@ -1,27 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\usepackage{amsmath} -\usepackage{pgfplots} -\usepackage{tikz} -\pagestyle{empty} - -\begin{document} -\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} -\end{document} diff --git a/yosys/docs/images/verilog_flow.png b/yosys/docs/images/verilog_flow.png deleted file mode 100644 index 1f3d82780f3..00000000000 Binary files a/yosys/docs/images/verilog_flow.png and /dev/null differ diff --git a/yosys/docs/images/verilog_flow.tex b/yosys/docs/images/verilog_flow.tex deleted file mode 100644 index d3e269d0d1f..00000000000 --- a/yosys/docs/images/verilog_flow.tex +++ /dev/null @@ -1,67 +0,0 @@ -\documentclass[12pt,tikz]{standalone} -\pdfinfoomitdate 1 -\pdfsuppressptexinfo 1 -\pdftrailerid{} -\usepackage[utf8]{inputenc} -\usepackage{amsmath} -\usepackage{pgfplots} -\usepackage{tikz} -\usetikzlibrary{shapes.geometric} -\pagestyle{empty} - -\begin{document} -\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} -\end{document} diff --git a/yosys/docs/source/APPNOTE_011_Design_Investigation/cmos.v b/yosys/docs/source/APPNOTE_011_Design_Investigation/cmos.v deleted file mode 100644 index 2912c760a7a..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/cmos_00.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/cmos_00.dot deleted file mode 100644 index 49c63008081..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/cmos_01.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/cmos_01.dot deleted file mode 100644 index ea6f4403ca8..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/example.v b/yosys/docs/source/APPNOTE_011_Design_Investigation/example.v deleted file mode 100644 index 8c71989b365..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/example.ys b/yosys/docs/source/APPNOTE_011_Design_Investigation/example.ys deleted file mode 100644 index b1e956088cc..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/example_00.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/example_00.dot deleted file mode 100644 index 1e23ed0ead3..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/example_01.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/example_01.dot deleted file mode 100644 index e89292b51ac..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/example_02.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/example_02.dot deleted file mode 100644 index f950ed2ed2c..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/example_03.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/example_03.dot deleted file mode 100644 index e19d24af78a..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/foobaraddsub.v b/yosys/docs/source/APPNOTE_011_Design_Investigation/foobaraddsub.v deleted file mode 100644 index 0f277211d1c..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/make.sh b/yosys/docs/source/APPNOTE_011_Design_Investigation/make.sh deleted file mode 100644 index 3845dac6b31..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/memdemo.v b/yosys/docs/source/APPNOTE_011_Design_Investigation/memdemo.v deleted file mode 100644 index b39564ddc20..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/memdemo_00.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/memdemo_00.dot deleted file mode 100644 index 0336a9aac2a..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/memdemo_01.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/memdemo_01.dot deleted file mode 100644 index 2ad92c78b2f..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/primetest.v b/yosys/docs/source/APPNOTE_011_Design_Investigation/primetest.v deleted file mode 100644 index 6cb766b7337..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/splice.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/splice.dot deleted file mode 100644 index 4657feed116..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/splice.v b/yosys/docs/source/APPNOTE_011_Design_Investigation/splice.v deleted file mode 100644 index 1cf7274c059..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/submod.ys b/yosys/docs/source/APPNOTE_011_Design_Investigation/submod.ys deleted file mode 100644 index 29ad61076a9..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/submod_00.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/submod_00.dot deleted file mode 100644 index 2e55268ee10..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/submod_01.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/submod_01.dot deleted file mode 100644 index f8f8c008ac6..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/submod_02.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/submod_02.dot deleted file mode 100644 index 1a672c484f1..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/submod_03.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/submod_03.dot deleted file mode 100644 index 0dbbe3baa17..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/sumprod.v b/yosys/docs/source/APPNOTE_011_Design_Investigation/sumprod.v deleted file mode 100644 index 4091bf0a151..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/sumprod_00.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/sumprod_00.dot deleted file mode 100644 index 06522dcc9ef..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/sumprod_01.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/sumprod_01.dot deleted file mode 100644 index aefe7a6da93..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/sumprod_02.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/sumprod_02.dot deleted file mode 100644 index 4646c994786..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/sumprod_03.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/sumprod_03.dot deleted file mode 100644 index dcfea2b5609..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/sumprod_04.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/sumprod_04.dot deleted file mode 100644 index e77c41aa2e1..00000000000 --- a/yosys/docs/source/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/docs/source/APPNOTE_011_Design_Investigation/sumprod_05.dot b/yosys/docs/source/APPNOTE_011_Design_Investigation/sumprod_05.dot deleted file mode 100644 index b544412909c..00000000000 --- a/yosys/docs/source/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/docs/source/CHAPTER_Approach.rst b/yosys/docs/source/CHAPTER_Approach.rst deleted file mode 100644 index 32980e788bf..00000000000 --- a/yosys/docs/source/CHAPTER_Approach.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. _chapter:approach: - -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. - -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 :numref:`Fig. %s -`). - -.. figure:: ../images/approach_flow.* - :class: width-helper - :name: fig:approach_flow - - General data- and control-flow of a synthesis tool - -The first subsystem to be called is usually called a 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 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 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. - -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 -AST and is generated by the Verilog Frontend. This data structure is consumed by -a subsystem called AST Frontend [1]_. 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: - -- The passes can be rearranged in a different order and passes can be removed - or inserted. - -- 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. - -- 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. - -The RTLIL representation is basically a netlist representation with the -following additional features: - -- 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). - -- Support for multi-bit values that can use individual bits from wires as well - as constant bits to represent coarse-grain netlists. - -- Support for basic behavioural constructs (if-then-else structures and - multi-case switches with a sensitivity list for updating the outputs). - -- Support for multi-port memories. - -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. - -.. _sec:typusecase: - -Typical use case ----------------- - -The following example script may be used in a synthesis flow to convert the -behavioural Verilog code from the input file design.v to a gate-level netlist -synth.v using the cell library described by the Liberty file : - -.. code:: yoscrypt - :number-lines: - - # 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 - -A detailed description of the commands available in Yosys can be found in -:ref:`cmd_ref`. - -.. [1] - In Yosys the term pass is only used to refer to commands that operate on the - RTLIL data structure. diff --git a/yosys/docs/source/CHAPTER_Basics.rst b/yosys/docs/source/CHAPTER_Basics.rst deleted file mode 100644 index 618bec545a9..00000000000 --- a/yosys/docs/source/CHAPTER_Basics.rst +++ /dev/null @@ -1,776 +0,0 @@ -.. role:: verilog(code) - :language: Verilog - -.. _chapter:basics: - -Basic principles -================ - -This chapter contains a short introduction to the basic principles of digital -circuit synthesis. - -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 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. -:numref:`Figure %s ` lists the different levels of -abstraction and how they relate to different kinds of synthesis. - -.. figure:: ../images/basics_abstractions.* - :class: width-helper - :name: fig:Basics_abstractions - - Different levels of abstraction and synthesis. - -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 [1]_. 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:p:`ABEL`, but -would not be considered a "High-Level Language" today. - -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:p:`IP-XACT` - -High level -~~~~~~~~~~ - -The high-level abstraction of a system (sometimes referred to as 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 . - -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 -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 always-block in Verilog and the process-block in VHDL. - -In behavioural modelling, code fragments are provided together with a -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: - -.. code:: verilog - :number-lines: - - always @(posedge clk) - y <= a + b; - -In simulation the statement ``y <= a + b`` is executed whenever a positive edge -on the signal ``clk`` is detected. The synthesis result however will contain an -adder that calculates the sum ``a + b`` all the time, followed by a d-type -flip-flop with the adder output on its D-input and the signal ``y`` on its -Q-output. - -Usually the imperative code fragments used in behavioural modelling can contain -statements for conditional execution (``if``- and ``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. - -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: - -.. code:: verilog - :number-lines: - - assign tmp = a + b; // combinatorial data path - - always @(posedge clk) // register - y <= tmp; - -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 -always-blocks (Verilog) or 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 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. - -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 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 multi-level -logic synthesis algorithms :cite:p:`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 . - -Yosys contains basic logic synthesis functionality but can also use ABC for the -logic synthesis step. Using ABC is recommended. - -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). - -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. - -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. - -Features of synthesizable Verilog ---------------------------------- - -The subset of Verilog :cite:p:`Verilog2005` that is synthesizable is specified -in a separate IEEE standards document, the IEEE standard 1364.1-2002 -:cite:p:`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. - -Structural Verilog -~~~~~~~~~~~~~~~~~~ - -Structural Verilog (also known as Verilog Netlists) is a Netlist in Verilog -syntax. Only the following language constructs are used in this -case: - -- Constant values -- Wire and port declarations -- Static assignments of signals to other signals -- Cell instantiations - -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 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. - -Expressions in Verilog -~~~~~~~~~~~~~~~~~~~~~~ - -In all situations where Verilog accepts a constant value or signal name, -expressions using arithmetic operations such as ``+``, ``-`` and ``*``, boolean -operations such as ``&`` (AND), ``|`` (OR) and ``^`` (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. - -Behavioural modelling -~~~~~~~~~~~~~~~~~~~~~ - -Code that utilizes the Verilog always statement is using 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: - -- | **Asynchronous or latched logic** - | In this case the sensitivity list must contain all expressions that - are used within the always block. The syntax ``@*`` can be used for - these cases. Examples of this kind include: - - .. code:: verilog - :number-lines: - - // asynchronous - always @* begin - if (add_mode) - y <= a + b; - else - y <= a - b; - end - - // latched - always @* begin - if (!hold) - y <= a + b; - end - - 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. - -- | **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: - - .. code:: verilog - :number-lines: - - // counter with synchronous reset - always @(posedge clk) begin - if (reset) - y <= 0; - else - y <= y + 1; - end - -- | **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: - - .. code:: verilog - :number-lines: - - // counter with asynchronous reset - always @(posedge clk, posedge reset) begin - if (reset) - y <= 0; - else - y <= y + 1; - end - -Many synthesis tools support a wider subset of flip-flops that can be modelled -using 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:p:`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 ``a <= b; b <= a;`` exchanges the values of the two registers. - - -Functions and tasks -~~~~~~~~~~~~~~~~~~~ - -Verilog supports Functions and Tasks to bundle statements that are used in -multiple places (similar to Procedures in imperative programming). Both -constructs can be implemented easily by substituting the function/task-call with -the body of the function or task. - -Conditionals, loops and generate-statements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Verilog supports ``if-else``-statements and ``for``-loops inside -``always``-statements. - -It also supports both features in ``generate``-statements on the module level. -This can be used to selectively enable or disable parts of the module based on -the module parameters (``if-else``) or to generate a set of similar subcircuits -(``for``). - -While the ``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 -``if-else``-statement in ``generate``-statements using const-folding.. - -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: - -.. code:: verilog - :number-lines: - - 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 - -This could be implemented using an addressable memory with 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. - -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. - -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: - -- Completeness of implementation of the standard -- Correctness of implementation of the standard - -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. - -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. - -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. - -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 :numref:`Fig. %s `. - -.. figure:: ../images/basics_flow.* - :class: width-helper - :name: fig:Basics_flow - - Typical design flow. Green boxes represent manually created models. - Orange boxes represent modesl generated by synthesis tools. - - -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. - -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. - -Lexing and parsing -~~~~~~~~~~~~~~~~~~ - -The best known concepts from compiler design are probably lexing and parsing. -These are two methods that together can be used to process complex computer -languages easily. :cite:p:`Dragonbook` - -A lexer consumes single characters from the input and generates a stream of -lexical tokens that consist of a type and a value. For example the Verilog input -:verilog:`assign foo = bar + 42;` might be translated by the lexer to the list -of lexical tokens given in :numref:`Tab. %s `. - -.. table:: Exemplary token list for the statement :verilog:`assign foo = bar + 42;` - :name: tab:Basics_tokens - - ============== =============== - Token-Type Token-Value - ============== =============== - TOK_ASSIGN \- - TOK_IDENTIFIER "foo" - TOK_EQ \- - TOK_IDENTIFIER "bar" - TOK_PLUS \- - TOK_NUMBER 42 - TOK_SEMICOLON \- - ============== =============== - -The lexer is usually generated by a lexer generator (e.g. 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. bison ) from a -grammar description in Backus-Naur Form (BNF). - -Let's consider the following BNF (in Bison syntax): - -.. code:: none - :number-lines: - - assign_stmt: TOK_ASSIGN TOK_IDENTIFIER TOK_EQ expr TOK_SEMICOLON; - expr: TOK_IDENTIFIER | TOK_NUMBER | expr TOK_PLUS expr; - -.. figure:: ../images/basics_parsetree.* - :class: width-helper - :name: fig:Basics_parsetree - - Example parse tree for the Verilog expression - :verilog:`assign foo = bar + 42;` - -The parser converts the token list to the parse tree in :numref:`Fig. %s -`. 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 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 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). :numref:`Figure %s ` illustrates what an -AST for the parse tree in :numref:`Fig. %s ` 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:p:`Dragonbook` - -.. figure:: ../images/basics_ast.* - :class: width-helper - :name: fig:Basics_ast - - Example abstract syntax tree for the Verilog expression - :verilog:`assign foo = bar + 42;` - - -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 Single-Pass Pipelining and by using 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. - -Static Single Assignment (SSA) 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: - -.. code:: c++ - :number-lines: - - void demo1() - { - int a = 1; - printf("%d\n", a); - - a = 2; - printf("%d\n", a); - } - -.. code:: c++ - - void demo1() - { - int a = 1; - printf("%d\n", a); - - int b = 2; - printf("%d\n", b); - } - -.. code:: c++ - :number-lines: - - void demo2(bool foo) - { - int a; - if (foo) { - a = 23; - printf("%d\n", a); - } else { - a = 42; - printf("%d\n", a); - } - } - -.. code:: c++ - - void demo2(bool foo) - { - int a, b; - if (foo) { - a = 23; - printf("%d\n", a); - } else { - b = 42; - printf("%d\n", b); - } - } - -In both examples the left version (only variable ``a``) and the right version -(variables ``a`` and ``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: - -.. code:: c++ - - void demo3(bool foo) - { - int a = 23 - if (foo) - a = 42; - printf("%d\n", a); - } - -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 -:math:`\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: - -.. code:: 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); - } - -The :math:`\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. - -.. [1] - In recent years formal equivalence checking also became an important - verification method for validating RTL and lower abstraction - representation of the design. diff --git a/yosys/docs/source/CHAPTER_CellLib.rst b/yosys/docs/source/CHAPTER_CellLib.rst deleted file mode 100644 index c5db434a64f..00000000000 --- a/yosys/docs/source/CHAPTER_CellLib.rst +++ /dev/null @@ -1,1020 +0,0 @@ -.. role:: verilog(code) - :language: Verilog - -.. _chapter:celllib: - -Internal cell library -===================== - -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. - -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 -``techlibs/common/simlib.v`` in the Yosys source tree. - -Unary operators -~~~~~~~~~~~~~~~ - -All unary RTL cells have one input port ``\A`` and one output port ``\Y``. They -also have the following parameters: - -``\A_SIGNED`` - Set to a non-zero value if the input ``\A`` is signed and therefore - should be sign-extended when needed. - -``\A_WIDTH`` - The width of the input port ``\A``. - -``\Y_WIDTH`` - The width of the output port ``\Y``. - -:numref:`tab:CellLib_unary` lists all cells for unary RTL operators. - -.. table:: Cell types for unary operators with their corresponding Verilog expressions. - :name: tab:CellLib_unary - - ================== ============ - Verilog Cell Type - ================== ============ - :verilog:`Y = ~A` $not - :verilog:`Y = +A` $pos - :verilog:`Y = -A` $neg - :verilog:`Y = &A` $reduce_and - :verilog:`Y = |A` $reduce_or - :verilog:`Y = ^A` $reduce_xor - :verilog:`Y = ~^A` $reduce_xnor - :verilog:`Y = |A` $reduce_bool - :verilog:`Y = !A` $logic_not - ================== ============ - -For the unary cells that output a logical value (``$reduce_and``, -``$reduce_or``, ``$reduce_xor``, ``$reduce_xnor``, ``$reduce_bool``, -``$logic_not``), when the ``\Y_WIDTH`` parameter is greater than 1, the output -is zero-extended, and only the least significant bit varies. - -Note that ``$reduce_or`` and ``$reduce_bool`` actually represent the same logic -function. But the HDL frontends generate them in different situations. A -``$reduce_or`` cell is generated when the prefix ``|`` operator is being used. A -``$reduce_bool`` cell is generated when a bit vector is used as a condition in -an ``if``-statement or ``?:``-expression. - -Binary operators -~~~~~~~~~~~~~~~~ - -All binary RTL cells have two input ports ``\A`` and ``\B`` and one output port -``\Y``. They also have the following parameters: - -``\A_SIGNED`` - Set to a non-zero value if the input ``\A`` is signed and therefore - should be sign-extended when needed. - -``\A_WIDTH`` - The width of the input port ``\A``. - -``\B_SIGNED`` - Set to a non-zero value if the input ``\B`` is signed and therefore - should be sign-extended when needed. - -``\B_WIDTH`` - The width of the input port ``\B``. - -``\Y_WIDTH`` - The width of the output port ``\Y``. - -:numref:`tab:CellLib_binary` lists all cells for binary RTL operators. - -.. table:: Cell types for binary operators with their corresponding Verilog expressions. - :name: tab:CellLib_binary - - ======================= ============= ======================= ========= - Verilog Cell Type Verilog Cell Type - ======================= ============= ======================= ========= - :verilog:`Y = A & B` $and :verilog:`Y = A < B` $lt - :verilog:`Y = A | B` $or :verilog:`Y = A <= B` $le - :verilog:`Y = A ^ B` $xor :verilog:`Y = A == B` $eq - :verilog:`Y = A ~^ B` $xnor :verilog:`Y = A != B` $ne - :verilog:`Y = A << B` $shl :verilog:`Y = A >= B` $ge - :verilog:`Y = A >> B` $shr :verilog:`Y = A > B` $gt - :verilog:`Y = A <<< B` $sshl :verilog:`Y = A + B` $add - :verilog:`Y = A >>> B` $sshr :verilog:`Y = A - B` $sub - :verilog:`Y = A && B` $logic_and :verilog:`Y = A * B` $mul - :verilog:`Y = A || B` $logic_or :verilog:`Y = A / B` $div - :verilog:`Y = A === B` $eqx :verilog:`Y = A % B` $mod - :verilog:`Y = A !== B` $nex ``N/A`` $divfloor - :verilog:`Y = A ** B` $pow ``N/A`` $modfoor - ======================= ============= ======================= ========= - -The ``$shl`` and ``$shr`` cells implement logical shifts, whereas the ``$sshl`` -and ``$sshr`` cells implement arithmetic shifts. The ``$shl`` and ``$sshl`` -cells implement the same operation. All four of these cells interpret the second -operand as unsigned, and require ``\B_SIGNED`` to be zero. - -Two additional shift operator cells are available that do not directly -correspond to any operator in Verilog, ``$shift`` and ``$shiftx``. The -``$shift`` cell performs a right logical shift if the second operand is positive -(or unsigned), and a left logical shift if it is negative. The ``$shiftx`` cell -performs the same operation as the ``$shift`` cell, but the vacated bit -positions are filled with undef (x) bits, and corresponds to the Verilog indexed -part-select expression. - -For the binary cells that output a logical value (``$logic_and``, ``$logic_or``, -``$eqx``, ``$nex``, ``$lt``, ``$le``, ``$eq``, ``$ne``, ``$ge``, ``$gt)``, when -the ``\Y_WIDTH`` parameter is greater than 1, the output is zero-extended, and -only the least significant bit varies. - -Division and modulo cells are available in two rounding modes. The original -``$div`` and ``$mod`` cells are based on truncating division, and correspond to -the semantics of the verilog ``/`` and ``%`` operators. The ``$divfloor`` and -``$modfloor`` cells represent flooring division and flooring modulo, the latter -of which is also known as "remainder" in several languages. See -:numref:`tab:CellLib_divmod` for a side-by-side comparison between the different -semantics. - -.. table:: Comparison between different rounding modes for division and modulo cells. - :name: tab:CellLib_divmod - - +-----------+--------+-----------+-----------+-----------+-----------+ - | Division | Result | Truncating | Flooring | - +-----------+--------+-----------+-----------+-----------+-----------+ - | | | $div | $mod | $divfloor | $modfloor | - +===========+========+===========+===========+===========+===========+ - | -10 / 3 | -3.3 | -3 | -1 | -4 | 2 | - +-----------+--------+-----------+-----------+-----------+-----------+ - | 10 / -3 | -3.3 | -3 | 1 | -4 | -2 | - +-----------+--------+-----------+-----------+-----------+-----------+ - | -10 / -3 | 3.3 | 3 | -1 | 3 | -1 | - +-----------+--------+-----------+-----------+-----------+-----------+ - | 10 / 3 | 3.3 | 3 | 1 | 3 | 1 | - +-----------+--------+-----------+-----------+-----------+-----------+ - -Multiplexers -~~~~~~~~~~~~ - -Multiplexers are generated by the Verilog HDL frontend for ``?:``-expressions. -Multiplexers are also generated by the proc pass to map the decision trees from -RTLIL::Process objects to logic. - -The simplest multiplexer cell type is ``$mux``. Cells of this type have a -``\WITDH`` parameter and data inputs ``\A`` and ``\B`` and a data output ``\Y``, -all of the specified width. This cell also has a single bit control input -``\S``. If ``\S`` is 0 the value from the input ``\A`` is sent to the output, if -it is 1 the value from the ``\B`` input is sent to the output. So the ``$mux`` -cell implements the function :verilog:`Y = S ? B : A`. - -The ``$pmux`` cell is used to multiplex between many inputs using a one-hot -select signal. Cells of this type have a ``\WIDTH`` and a ``\S_WIDTH`` parameter -and inputs ``\A``, ``\B``, and ``\S`` and an output ``\Y``. The ``\S`` input is -``\S_WIDTH`` bits wide. The ``\A`` input and the output are both ``\WIDTH`` bits -wide and the ``\B`` input is ``\WIDTH*\S_WIDTH`` bits wide. When all bits of -``\S`` are zero, the value from ``\A`` input is sent to the output. If the -:math:`n`\ 'th bit from ``\S`` is set, the value :math:`n`\ 'th ``\WIDTH`` bits -wide slice of the ``\B`` input is sent to the output. When more than one bit -from ``\S`` is set the output is undefined. Cells of this type are used to model -"parallel cases" (defined by using the ``parallel_case`` attribute or detected -by an optimization). - -The ``$tribuf`` cell is used to implement tristate logic. Cells of this type -have a ``\B`` parameter and inputs ``\A`` and ``\EN`` and an output ``\Y``. The -``\A`` input and ``\Y`` output are ``\WIDTH`` bits wide, and the ``\EN`` input -is one bit wide. When ``\EN`` is 0, the output is not driven. When ``\EN`` is 1, -the value from ``\A`` input is sent to the ``\Y`` output. Therefore, the -``$tribuf`` cell implements the function :verilog:`Y = EN ? A : 'bz`. - -Behavioural code with cascaded if-then-else- and 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 ``$and`` gate). - -Registers -~~~~~~~~~ - -SR-type latches are represented by ``$sr`` cells. These cells have input ports -``\SET`` and ``\CLR`` and an output port ``\Q``. They have the following -parameters: - -``\WIDTH`` - The width of inputs ``\SET`` and ``\CLR`` and output ``\Q``. - -``\SET_POLARITY`` - The set input bits are active-high if this parameter has the value - ``1'b1`` and active-low if this parameter is ``1'b0``. - -``\CLR_POLARITY`` - The reset input bits are active-high if this parameter has the value - ``1'b1`` and active-low if this parameter is ``1'b0``. - -Both set and reset inputs have separate bits for every output bit. When both the -set and reset inputs of an ``$sr`` cell are active for a given bit index, the -reset input takes precedence. - -D-type flip-flops are represented by ``$dff`` cells. These cells have a clock -port ``\CLK``, an input port ``\D`` and an output port ``\Q``. The following -parameters are available for ``$dff`` cells: - -``\WIDTH`` - The width of input ``\D`` and output ``\Q``. - -``\CLK_POLARITY`` - Clock is active on the positive edge if this parameter has the value - ``1'b1`` and on the negative edge if this parameter is ``1'b0``. - -D-type flip-flops with asynchronous reset are represented by ``$adff`` cells. As -the ``$dff`` cells they have ``\CLK``, ``\D`` and ``\Q`` ports. In addition they -also have a single-bit ``\ARST`` input port for the reset pin and the following -additional two parameters: - -``\ARST_POLARITY`` - The asynchronous reset is active-high if this parameter has the value - ``1'b1`` and active-low if this parameter is ``1'b0``. - -``\ARST_VALUE`` - The state of ``\Q`` will be set to this value when the reset is active. - -Usually these cells are generated by the ``proc`` pass using the information in -the designs RTLIL::Process objects. - -D-type flip-flops with synchronous reset are represented by ``$sdff`` cells. As -the ``$dff`` cells they have ``\CLK``, ``\D`` and ``\Q`` ports. In addition they -also have a single-bit ``\SRST`` input port for the reset pin and the following -additional two parameters: - -``\SRST_POLARITY`` - The synchronous reset is active-high if this parameter has the value - ``1'b1`` and active-low if this parameter is ``1'b0``. - -``\SRST_VALUE`` - The state of ``\Q`` will be set to this value when the reset is active. - -Note that the ``$adff`` and ``$sdff`` cells can only be used when the reset value is -constant. - -D-type flip-flops with asynchronous load are represented by ``$aldff`` cells. As -the ``$dff`` cells they have ``\CLK``, ``\D`` and ``\Q`` ports. In addition they -also have a single-bit ``\ALOAD`` input port for the async load enable pin, a -``\AD`` input port with the same width as data for the async load data, and the -following additional parameter: - -``\ALOAD_POLARITY`` - The asynchronous load is active-high if this parameter has the value - ``1'b1`` and active-low if this parameter is ``1'b0``. - -D-type flip-flops with asynchronous set and reset are represented by ``$dffsr`` -cells. As the ``$dff`` cells they have ``\CLK``, ``\D`` and ``\Q`` ports. In -addition they also have multi-bit ``\SET`` and ``\CLR`` input ports and the -corresponding polarity parameters, like ``$sr`` cells. - -D-type flip-flops with enable are represented by ``$dffe``, ``$adffe``, -``$aldffe``, ``$dffsre``, ``$sdffe``, and ``$sdffce`` cells, which are enhanced -variants of ``$dff``, ``$adff``, ``$aldff``, ``$dffsr``, ``$sdff`` (with reset -over enable) and ``$sdff`` (with enable over reset) cells, respectively. They -have the same ports and parameters as their base cell. In addition they also -have a single-bit ``\EN`` input port for the enable pin and the following -parameter: - -``\EN_POLARITY`` - The enable input is active-high if this parameter has the value ``1'b1`` - and active-low if this parameter is ``1'b0``. - -D-type latches are represented by ``$dlatch`` cells. These cells have an enable -port ``\EN``, an input port ``\D``, and an output port ``\Q``. The following -parameters are available for ``$dlatch`` cells: - -``\WIDTH`` - The width of input ``\D`` and output ``\Q``. - -``\EN_POLARITY`` - The enable input is active-high if this parameter has the value ``1'b1`` - and active-low if this parameter is ``1'b0``. - -The latch is transparent when the ``\EN`` input is active. - -D-type latches with reset are represented by ``$adlatch`` cells. In addition to -``$dlatch`` ports and parameters, they also have a single-bit ``\ARST`` input -port for the reset pin and the following additional parameters: - -``\ARST_POLARITY`` - The asynchronous reset is active-high if this parameter has the value - ``1'b1`` and active-low if this parameter is ``1'b0``. - -``\ARST_VALUE`` - The state of ``\Q`` will be set to this value when the reset is active. - -D-type latches with set and reset are represented by ``$dlatchsr`` cells. In -addition to ``$dlatch`` ports and parameters, they also have multi-bit ``\SET`` -and ``\CLR`` input ports and the corresponding polarity parameters, like ``$sr`` -cells. - -.. _sec:memcells: - -Memories -~~~~~~~~ - -Memories are either represented using RTLIL::Memory objects, ``$memrd_v2``, -``$memwr_v2``, and ``$meminit_v2`` cells, or by ``$mem_v2`` 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 -``$memrd_v2`` (read port) or ``$memwr_v2`` (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 ``$meminit_v2`` cells, which allow -delaying constant folding for initialization addresses and data until after the -frontend finishes. - -The ``$memrd_v2`` cells have a clock input ``\CLK``, an enable input ``\EN``, an -address input ``\ADDR``, a data output ``\DATA``, an asynchronous reset input -``\ARST``, and a synchronous reset input ``\SRST``. They also have the following -parameters: - -``\MEMID`` - The name of the RTLIL::Memory object that is associated with this read - port. - -``\ABITS`` - The number of address bits (width of the ``\ADDR`` input port). - -``\WIDTH`` - The number of data bits (width of the ``\DATA`` output port). Note that - this may be a power-of-two multiple of the underlying memory's width -- - such ports are called wide ports and access an aligned group of cells at - once. In this case, the corresponding low bits of ``\ADDR`` must be - tied to 0. - -``\CLK_ENABLE`` - When this parameter is non-zero, the clock is used. Otherwise this read - port is asynchronous and the ``\CLK`` input is not used. - -``\CLK_POLARITY`` - Clock is active on the positive edge if this parameter has the value - ``1'b1`` and on the negative edge if this parameter is ``1'b0``. - -``\TRANSPARENCY_MASK`` - This parameter is a bitmask of write ports that this read port is - transparent with. The bits of this parameter are indexed by the write - port's ``\PORTID`` parameter. Transparency can only be enabled between - synchronous ports sharing a clock domain. When transparency is enabled - for a given port pair, a read and write to the same address in the same - cycle will return the new value. Otherwise the old value is returned. - -``\COLLISION_X_MASK`` - This parameter is a bitmask of write ports that have undefined collision - behavior with this port. The bits of this parameter are indexed by the - write port's ``\PORTID`` parameter. This behavior can only be enabled - between synchronous ports sharing a clock domain. When undefined - collision is enabled for a given port pair, a read and write to the same - address in the same cycle will return the undefined (all-X) value.This - option is exclusive (for a given port pair) with the transparency - option. - -``\ARST_VALUE`` - Whenever the ``\ARST`` input is asserted, the data output will be reset - to this value. Only used for synchronous ports. - -``\SRST_VALUE`` - Whenever the ``\SRST`` input is synchronously asserted, the data output - will be reset to this value. Only used for synchronous ports. - -``\INIT_VALUE`` - The initial value of the data output, for synchronous ports. - -``\CE_OVER_SRST`` - If this parameter is non-zero, the ``\SRST`` input is only recognized - when ``\EN`` is true. Otherwise, ``\SRST`` is recognized regardless of - ``\EN``. - -The ``$memwr_v2`` cells have a clock input ``\CLK``, an enable input ``\EN`` -(one enable bit for each data bit), an address input ``\ADDR`` and a data input -``\DATA``. They also have the following parameters: - -``\MEMID`` - The name of the RTLIL::Memory object that is associated with this write - port. - -``\ABITS`` - The number of address bits (width of the ``\ADDR`` input port). - -``\WIDTH`` - The number of data bits (width of the ``\DATA`` output port). Like with - ``$memrd_v2`` cells, the width is allowed to be any power-of-two - multiple of memory width, with the corresponding restriction on address. - -``\CLK_ENABLE`` - When this parameter is non-zero, the clock is used. Otherwise this write - port is asynchronous and the ``\CLK`` input is not used. - -``\CLK_POLARITY`` - Clock is active on positive edge if this parameter has the value - ``1'b1`` and on the negative edge if this parameter is ``1'b0``. - -``\PORTID`` - An identifier for this write port, used to index write port bit mask parameters. - -``\PRIORITY_MASK`` - This parameter is a bitmask of write ports that this write port has - priority over in case of writing to the same address. The bits of this - parameter are indexed by the other write port's ``\PORTID`` parameter. - Write ports can only have priority over write ports with lower port ID. - When two ports write to the same address and neither has priority over - the other, the result is undefined. Priority can only be set between - two synchronous ports sharing the same clock domain. - -The ``$meminit_v2`` cells have an address input ``\ADDR``, a data input -``\DATA``, with the width of the ``\DATA`` port equal to ``\WIDTH`` parameter -times ``\WORDS`` parameter, and a bit enable mask input ``\EN`` with width equal -to ``\WIDTH`` parameter. All three of the inputs must resolve to a constant for -synthesis to succeed. - -``\MEMID`` - The name of the RTLIL::Memory object that is associated with this - initialization cell. - -``\ABITS`` - The number of address bits (width of the ``\ADDR`` input port). - -``\WIDTH`` - The number of data bits per memory location. - -``\WORDS`` - The number of consecutive memory locations initialized by this cell. - -``\PRIORITY`` - The cell with the higher integer value in this parameter wins an - initialization conflict. - -The HDL frontend models a memory using RTLIL::Memory objects and asynchronous -``$memrd_v2`` and ``$memwr_v2`` cells. The ``memory`` pass (i.e.~its various -sub-passes) migrates ``$dff`` cells into the ``$memrd_v2`` and ``$memwr_v2`` -cells making them synchronous, then converts them to a single ``$mem_v2`` cell -and (optionally) maps this cell type to ``$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 ``$mem_v2`` cell is left in the -design. - -The ``$mem_v2`` cell provides the following parameters: - -``\MEMID`` - The name of the original RTLIL::Memory object that became this - ``$mem_v2`` cell. - -``\SIZE`` - The number of words in the memory. - -``\ABITS`` - The number of address bits. - -``\WIDTH`` - The number of data bits per word. - -``\INIT`` - The initial memory contents. - -``\RD_PORTS`` - The number of read ports on this memory cell. - -``\RD_WIDE_CONTINUATION`` - This parameter is ``\RD_PORTS`` bits wide, containing a bitmask of - "wide continuation" read ports. Such ports are used to represent the - extra data bits of wide ports in the combined cell, and must have all - control signals identical with the preceding port, except for address, - which must have the proper sub-cell address encoded in the low bits. - -``\RD_CLK_ENABLE`` - This parameter is ``\RD_PORTS`` bits wide, containing a clock enable bit - for each read port. - -``\RD_CLK_POLARITY`` - This parameter is ``\RD_PORTS`` bits wide, containing a clock polarity - bit for each read port. - -``\RD_TRANSPARENCY_MASK`` - This parameter is ``\RD_PORTS*\WR_PORTS`` bits wide, containing a - concatenation of all ``\TRANSPARENCY_MASK`` values of the original - ``$memrd_v2`` cells. - -``\RD_COLLISION_X_MASK`` - This parameter is ``\RD_PORTS*\WR_PORTS`` bits wide, containing a - concatenation of all ``\COLLISION_X_MASK`` values of the original - ``$memrd_v2`` cells. - -``\RD_CE_OVER_SRST`` - This parameter is ``\RD_PORTS`` bits wide, determining relative - synchronous reset and enable priority for each read port. - -``\RD_INIT_VALUE`` - This parameter is ``\RD_PORTS*\WIDTH`` bits wide, containing the initial - value for each synchronous read port. - -``\RD_ARST_VALUE`` - This parameter is ``\RD_PORTS*\WIDTH`` bits wide, containing the - asynchronous reset value for each synchronous read port. - -``\RD_SRST_VALUE`` - This parameter is ``\RD_PORTS*\WIDTH`` bits wide, containing the - synchronous reset value for each synchronous read port. - -``\WR_PORTS`` - The number of write ports on this memory cell. - -``\WR_WIDE_CONTINUATION`` - This parameter is ``\WR_PORTS`` bits wide, containing a bitmask of - "wide continuation" write ports. - -``\WR_CLK_ENABLE`` - This parameter is ``\WR_PORTS`` bits wide, containing a clock enable bit - for each write port. - -``\WR_CLK_POLARITY`` - This parameter is ``\WR_PORTS`` bits wide, containing a clock polarity - bit for each write port. - -``\WR_PRIORITY_MASK`` - This parameter is ``\WR_PORTS*\WR_PORTS`` bits wide, containing a - concatenation of all ``\PRIORITY_MASK`` values of the original - ``$memwr_v2`` cells. - -The ``$mem_v2`` cell has the following ports: - -``\RD_CLK`` - This input is ``\RD_PORTS`` bits wide, containing all clock signals for - the read ports. - -``\RD_EN`` - This input is ``\RD_PORTS`` bits wide, containing all enable signals for - the read ports. - -``\RD_ADDR`` - This input is ``\RD_PORTS*\ABITS`` bits wide, containing all address - signals for the read ports. - -``\RD_DATA`` - This input is ``\RD_PORTS*\WIDTH`` bits wide, containing all data - signals for the read ports. - -``\RD_ARST`` - This input is ``\RD_PORTS`` bits wide, containing all asynchronous reset - signals for the read ports. - -``\RD_SRST`` - This input is ``\RD_PORTS`` bits wide, containing all synchronous reset - signals for the read ports. - -``\WR_CLK`` - This input is ``\WR_PORTS`` bits wide, containing all clock signals for - the write ports. - -``\WR_EN`` - This input is ``\WR_PORTS*\WIDTH`` bits wide, containing all enable - signals for the write ports. - -``\WR_ADDR`` - This input is ``\WR_PORTS*\ABITS`` bits wide, containing all address - signals for the write ports. - -``\WR_DATA`` - This input is ``\WR_PORTS*\WIDTH`` bits wide, containing all data - signals for the write ports. - -The ``memory_collect`` pass can be used to convert discrete ``$memrd_v2``, -``$memwr_v2``, and ``$meminit_v2`` cells belonging to the same memory to a -single ``$mem_v2`` cell, whereas the ``memory_unpack`` pass performs the inverse -operation. The ``memory_dff`` pass can combine asynchronous memory ports that -are fed by or feeding registers into synchronous memory ports. The -``memory_bram`` pass can be used to recognize ``$mem_v2`` cells that can be -implemented with a block RAM resource on an FPGA. The ``memory_map`` pass can be -used to implement ``$mem_v2`` cells as basic logic: word-wide DFFs and address -decoders. - -Finite state machines -~~~~~~~~~~~~~~~~~~~~~ - -Add a brief description of the ``$fsm`` cell type. - -Specify rules -~~~~~~~~~~~~~ - -Add information about ``$specify2``, ``$specify3``, and ``$specrule`` cells. - -Formal verification cells -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Add information about ``$assert``, ``$assume``, ``$live``, ``$fair``, -``$cover``, ``$equiv``, ``$initstate``, ``$anyconst``, ``$anyseq``, -``$anyinit``, ``$allconst``, ``$allseq`` cells. - -Add information about ``$ff`` and ``$_FF_`` cells. - -.. _sec:celllib_gates: - -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 -techlibs/common/simcells.v in the Yosys source tree. - -.. table:: Cell types for gate level logic networks (main list) - :name: tab:CellLib_gates - - ======================================= ============ - Verilog Cell Type - ======================================= ============ - :verilog:`Y = A` $_BUF_ - :verilog:`Y = ~A` $_NOT_ - :verilog:`Y = A & B` $_AND_ - :verilog:`Y = ~(A & B)` $_NAND_ - :verilog:`Y = A & ~B` $_ANDNOT_ - :verilog:`Y = A | B` $_OR_ - :verilog:`Y = ~(A | B)` $_NOR_ - :verilog:`Y = A | ~B` $_ORNOT_ - :verilog:`Y = A ^ B` $_XOR_ - :verilog:`Y = ~(A ^ B)` $_XNOR_ - :verilog:`Y = ~((A & B) | C)` $_AOI3_ - :verilog:`Y = ~((A | B) & C)` $_OAI3_ - :verilog:`Y = ~((A & B) | (C & D))` $_AOI4_ - :verilog:`Y = ~((A | B) & (C | D))` $_OAI4_ - :verilog:`Y = S ? B : A` $_MUX_ - :verilog:`Y = ~(S ? B : A)` $_NMUX_ - (see below) $_MUX4_ - (see below) $_MUX8_ - (see below) $_MUX16_ - :verilog:`Y = EN ? A : 1'bz` $_TBUF_ - :verilog:`always @(negedge C) Q <= D` $_DFF_N_ - :verilog:`always @(posedge C) Q <= D` $_DFF_P_ - :verilog:`always @* if (!E) Q <= D` $_DLATCH_N_ - :verilog:`always @* if (E) Q <= D` $_DLATCH_P_ - ======================================= ============ - -.. table:: Cell types for gate level logic networks (FFs with reset) - :name: tab:CellLib_gates_adff - - ================== ============== ============== ======================= - :math:`ClkEdge` :math:`RstLvl` :math:`RstVal` Cell Type - ================== ============== ============== ======================= - :verilog:`negedge` ``0`` ``0`` $_DFF_NN0_, $_SDFF_NN0_ - :verilog:`negedge` ``0`` ``1`` $_DFF_NN1_, $_SDFF_NN1_ - :verilog:`negedge` ``1`` ``0`` $_DFF_NP0_, $_SDFF_NP0_ - :verilog:`negedge` ``1`` ``1`` $_DFF_NP1_, $_SDFF_NP1_ - :verilog:`posedge` ``0`` ``0`` $_DFF_PN0_, $_SDFF_PN0_ - :verilog:`posedge` ``0`` ``1`` $_DFF_PN1_, $_SDFF_PN1_ - :verilog:`posedge` ``1`` ``0`` $_DFF_PP0_, $_SDFF_PP0_ - :verilog:`posedge` ``1`` ``1`` $_DFF_PP1_, $_SDFF_PP1_ - ================== ============== ============== ======================= - - -.. table:: Cell types for gate level logic networks (FFs with enable) - :name: tab:CellLib_gates_dffe - - ================== ============= =========== - :math:`ClkEdge` :math:`EnLvl` Cell Type - ================== ============= =========== - :verilog:`negedge` ``0`` $_DFFE_NN_ - :verilog:`negedge` ``1`` $_DFFE_NP_ - :verilog:`posedge` ``0`` $_DFFE_PN_ - :verilog:`posedge` ``1`` $_DFFE_PP_ - ================== ============= =========== - - -.. table:: Cell types for gate level logic networks (FFs with reset and enable) - :name: tab:CellLib_gates_adffe - - ================== ============== ============== ============= =========================================== - :math:`ClkEdge` :math:`RstLvl` :math:`RstVal` :math:`EnLvl` Cell Type - ================== ============== ============== ============= =========================================== - :verilog:`negedge` ``0`` ``0`` ``0`` $_DFFE_NN0N_, $_SDFFE_NN0N_, $_SDFFCE_NN0N_ - :verilog:`negedge` ``0`` ``0`` ``1`` $_DFFE_NN0P_, $_SDFFE_NN0P_, $_SDFFCE_NN0P_ - :verilog:`negedge` ``0`` ``1`` ``0`` $_DFFE_NN1N_, $_SDFFE_NN1N_, $_SDFFCE_NN1N_ - :verilog:`negedge` ``0`` ``1`` ``1`` $_DFFE_NN1P_, $_SDFFE_NN1P_, $_SDFFCE_NN1P_ - :verilog:`negedge` ``1`` ``0`` ``0`` $_DFFE_NP0N_, $_SDFFE_NP0N_, $_SDFFCE_NP0N_ - :verilog:`negedge` ``1`` ``0`` ``1`` $_DFFE_NP0P_, $_SDFFE_NP0P_, $_SDFFCE_NP0P_ - :verilog:`negedge` ``1`` ``1`` ``0`` $_DFFE_NP1N_, $_SDFFE_NP1N_, $_SDFFCE_NP1N_ - :verilog:`negedge` ``1`` ``1`` ``1`` $_DFFE_NP1P_, $_SDFFE_NP1P_, $_SDFFCE_NP1P_ - :verilog:`posedge` ``0`` ``0`` ``0`` $_DFFE_PN0N_, $_SDFFE_PN0N_, $_SDFFCE_PN0N_ - :verilog:`posedge` ``0`` ``0`` ``1`` $_DFFE_PN0P_, $_SDFFE_PN0P_, $_SDFFCE_PN0P_ - :verilog:`posedge` ``0`` ``1`` ``0`` $_DFFE_PN1N_, $_SDFFE_PN1N_, $_SDFFCE_PN1N_ - :verilog:`posedge` ``0`` ``1`` ``1`` $_DFFE_PN1P_, $_SDFFE_PN1P_, $_SDFFCE_PN1P_ - :verilog:`posedge` ``1`` ``0`` ``0`` $_DFFE_PP0N_, $_SDFFE_PP0N_, $_SDFFCE_PP0N_ - :verilog:`posedge` ``1`` ``0`` ``1`` $_DFFE_PP0P_, $_SDFFE_PP0P_, $_SDFFCE_PP0P_ - :verilog:`posedge` ``1`` ``1`` ``0`` $_DFFE_PP1N_, $_SDFFE_PP1N_, $_SDFFCE_PP1N_ - :verilog:`posedge` ``1`` ``1`` ``1`` $_DFFE_PP1P_, $_SDFFE_PP1P_, $_SDFFCE_PP1P_ - ================== ============== ============== ============= =========================================== - -.. table:: Cell types for gate level logic networks (FFs with set and reset) - :name: tab:CellLib_gates_dffsr - - ================== ============== ============== ============ - :math:`ClkEdge` :math:`SetLvl` :math:`RstLvl` Cell Type - ================== ============== ============== ============ - :verilog:`negedge` ``0`` ``0`` $_DFFSR_NNN_ - :verilog:`negedge` ``0`` ``1`` $_DFFSR_NNP_ - :verilog:`negedge` ``1`` ``0`` $_DFFSR_NPN_ - :verilog:`negedge` ``1`` ``1`` $_DFFSR_NPP_ - :verilog:`posedge` ``0`` ``0`` $_DFFSR_PNN_ - :verilog:`posedge` ``0`` ``1`` $_DFFSR_PNP_ - :verilog:`posedge` ``1`` ``0`` $_DFFSR_PPN_ - :verilog:`posedge` ``1`` ``1`` $_DFFSR_PPP_ - ================== ============== ============== ============ - - -.. table:: Cell types for gate level logic networks (FFs with set and reset and enable) - :name: tab:CellLib_gates_dffsre - - ================== ============== ============== ============= ============== - :math:`ClkEdge` :math:`SetLvl` :math:`RstLvl` :math:`EnLvl` Cell Type - ================== ============== ============== ============= ============== - :verilog:`negedge` ``0`` ``0`` ``0`` $_DFFSRE_NNNN_ - :verilog:`negedge` ``0`` ``0`` ``1`` $_DFFSRE_NNNP_ - :verilog:`negedge` ``0`` ``1`` ``0`` $_DFFSRE_NNPN_ - :verilog:`negedge` ``0`` ``1`` ``1`` $_DFFSRE_NNPP_ - :verilog:`negedge` ``1`` ``0`` ``0`` $_DFFSRE_NPNN_ - :verilog:`negedge` ``1`` ``0`` ``1`` $_DFFSRE_NPNP_ - :verilog:`negedge` ``1`` ``1`` ``0`` $_DFFSRE_NPPN_ - :verilog:`negedge` ``1`` ``1`` ``1`` $_DFFSRE_NPPP_ - :verilog:`posedge` ``0`` ``0`` ``0`` $_DFFSRE_PNNN_ - :verilog:`posedge` ``0`` ``0`` ``1`` $_DFFSRE_PNNP_ - :verilog:`posedge` ``0`` ``1`` ``0`` $_DFFSRE_PNPN_ - :verilog:`posedge` ``0`` ``1`` ``1`` $_DFFSRE_PNPP_ - :verilog:`posedge` ``1`` ``0`` ``0`` $_DFFSRE_PPNN_ - :verilog:`posedge` ``1`` ``0`` ``1`` $_DFFSRE_PPNP_ - :verilog:`posedge` ``1`` ``1`` ``0`` $_DFFSRE_PPPN_ - :verilog:`posedge` ``1`` ``1`` ``1`` $_DFFSRE_PPPP_ - ================== ============== ============== ============= ============== - - -.. table:: Cell types for gate level logic networks (latches with reset) - :name: tab:CellLib_gates_adlatch - - ============= ============== ============== ============= - :math:`EnLvl` :math:`RstLvl` :math:`RstVal` Cell Type - ============= ============== ============== ============= - ``0`` ``0`` ``0`` $_DLATCH_NN0_ - ``0`` ``0`` ``1`` $_DLATCH_NN1_ - ``0`` ``1`` ``0`` $_DLATCH_NP0_ - ``0`` ``1`` ``1`` $_DLATCH_NP1_ - ``1`` ``0`` ``0`` $_DLATCH_PN0_ - ``1`` ``0`` ``1`` $_DLATCH_PN1_ - ``1`` ``1`` ``0`` $_DLATCH_PP0_ - ``1`` ``1`` ``1`` $_DLATCH_PP1_ - ============= ============== ============== ============= - - -.. table:: Cell types for gate level logic networks (latches with set and reset) - :name: tab:CellLib_gates_dlatchsr - - ============= ============== ============== =============== - :math:`EnLvl` :math:`SetLvl` :math:`RstLvl` Cell Type - ============= ============== ============== =============== - ``0`` ``0`` ``0`` $_DLATCHSR_NNN_ - ``0`` ``0`` ``1`` $_DLATCHSR_NNP_ - ``0`` ``1`` ``0`` $_DLATCHSR_NPN_ - ``0`` ``1`` ``1`` $_DLATCHSR_NPP_ - ``1`` ``0`` ``0`` $_DLATCHSR_PNN_ - ``1`` ``0`` ``1`` $_DLATCHSR_PNP_ - ``1`` ``1`` ``0`` $_DLATCHSR_PPN_ - ``1`` ``1`` ``1`` $_DLATCHSR_PPP_ - ============= ============== ============== =============== - - - -.. table:: Cell types for gate level logic networks (SR latches) - :name: tab:CellLib_gates_sr - - ============== ============== ========= - :math:`SetLvl` :math:`RstLvl` Cell Type - ============== ============== ========= - ``0`` ``0`` $_SR_NN_ - ``0`` ``1`` $_SR_NP_ - ``1`` ``0`` $_SR_PN_ - ``1`` ``1`` $_SR_PP_ - ============== ============== ========= - - -Tables \ :numref:`%s `, :numref:`%s -`, :numref:`%s `, :numref:`%s -`, :numref:`%s `, :numref:`%s -`, :numref:`%s `, -:numref:`%s ` and :numref:`%s -` list all cell types used for gate level logic. The cell -types ``$_BUF_``, ``$_NOT_``, ``$_AND_``, ``$_NAND_``, ``$_ANDNOT_``, ``$_OR_``, -``$_NOR_``, ``$_ORNOT_``, ``$_XOR_``, ``$_XNOR_``, ``$_AOI3_``, ``$_OAI3_``, -``$_AOI4_``, ``$_OAI4_``, ``$_MUX_``, ``$_MUX4_``, ``$_MUX8_``, ``$_MUX16_`` and -``$_NMUX_`` are used to model combinatorial logic. The cell type ``$_TBUF_`` is -used to model tristate logic. - -The ``$_MUX4_``, ``$_MUX8_`` and ``$_MUX16_`` cells are used to model wide -muxes, and correspond to the following Verilog code: - -.. code-block:: verilog - :force: - - // $_MUX4_ - assign Y = T ? (S ? D : C) : - (S ? B : A); - // $_MUX8_ - assign Y = U ? T ? (S ? H : G) : - (S ? F : E) : - T ? (S ? D : C) : - (S ? B : A); - // $_MUX16_ - assign Y = V ? U ? T ? (S ? P : O) : - (S ? N : M) : - T ? (S ? L : K) : - (S ? J : I) : - U ? T ? (S ? H : G) : - (S ? F : E) : - T ? (S ? D : C) : - (S ? B : A); - -The cell types ``$_DFF_N_`` and ``$_DFF_P_`` represent d-type flip-flops. - -The cell types ``$_DFFE_[NP][NP]_`` implement d-type flip-flops with enable. The -values in the table for these cell types relate to the following Verilog code -template. - -.. code-block:: verilog - :force: - - always @(CLK_EDGE C) - if (EN == EN_LVL) - Q <= D; - -The cell types ``$_DFF_[NP][NP][01]_`` implement d-type flip-flops with -asynchronous reset. The values in the table for these cell types relate to the -following Verilog code template, where ``RST_EDGE`` is ``posedge`` if -``RST_LVL`` if ``1``, and ``negedge`` otherwise. - -.. code-block:: verilog - :force: - - always @(CLK_EDGE C, RST_EDGE R) - if (R == RST_LVL) - Q <= RST_VAL; - else - Q <= D; - -The cell types ``$_SDFF_[NP][NP][01]_`` implement d-type flip-flops with -synchronous reset. The values in the table for these cell types relate to the -following Verilog code template: - -.. code-block:: verilog - :force: - - always @(CLK_EDGE C) - if (R == RST_LVL) - Q <= RST_VAL; - else - Q <= D; - -The cell types ``$_DFFE_[NP][NP][01][NP]_`` implement d-type flip-flops with -asynchronous reset and enable. The values in the table for these cell types -relate to the following Verilog code template, where ``RST_EDGE`` is -``posedge`` if ``RST_LVL`` if ``1``, and ``negedge`` otherwise. - -.. code-block:: verilog - :force: - - always @(CLK_EDGE C, RST_EDGE R) - if (R == RST_LVL) - Q <= RST_VAL; - else if (EN == EN_LVL) - Q <= D; - -The cell types ``$_SDFFE_[NP][NP][01][NP]_`` implement d-type flip-flops with -synchronous reset and enable, with reset having priority over enable. The values -in the table for these cell types relate to the following Verilog code template: - -.. code-block:: verilog - :force: - - always @(CLK_EDGE C) - if (R == RST_LVL) - Q <= RST_VAL; - else if (EN == EN_LVL) - Q <= D; - -The cell types ``$_SDFFCE_[NP][NP][01][NP]_`` implement d-type flip-flops with -synchronous reset and enable, with enable having priority over reset. The values -in the table for these cell types relate to the following Verilog code template: - -.. code-block:: verilog - :force: - - always @(CLK_EDGE C) - if (EN == EN_LVL) - if (R == RST_LVL) - Q <= RST_VAL; - else - Q <= D; - -The cell types ``$_DFFSR_[NP][NP][NP]_`` implement d-type flip-flops with -asynchronous set and reset. The values in the table for these cell types relate -to the following Verilog code template, where ``RST_EDGE`` is ``posedge`` if -``RST_LVL`` if ``1``, ``negedge`` otherwise, and ``SET_EDGE`` is ``posedge`` -if ``SET_LVL`` if ``1``, ``negedge`` otherwise. - -.. code-block:: verilog - :force: - - always @(CLK_EDGE C, RST_EDGE R, SET_EDGE S) - if (R == RST_LVL) - Q <= 0; - else if (S == SET_LVL) - Q <= 1; - else - Q <= D; - -The cell types ``$_DFFSRE_[NP][NP][NP][NP]_`` implement d-type flip-flops with -asynchronous set and reset and enable. The values in the table for these cell -types relate to the following Verilog code template, where ``RST_EDGE`` is -``posedge`` if ``RST_LVL`` if ``1``, ``negedge`` otherwise, and ``SET_EDGE`` -is ``posedge`` if ``SET_LVL`` if ``1``, ``negedge`` otherwise. - -.. code-block:: verilog - :force: - - always @(CLK_EDGE C, RST_EDGE R, SET_EDGE S) - if (R == RST_LVL) - Q <= 0; - else if (S == SET_LVL) - Q <= 1; - else if (E == EN_LVL) - Q <= D; - -The cell types ``$_DLATCH_N_`` and ``$_DLATCH_P_`` represent d-type latches. - -The cell types ``$_DLATCH_[NP][NP][01]_`` implement d-type latches with reset. -The values in the table for these cell types relate to the following Verilog -code template: - -.. code-block:: verilog - :force: - - always @* - if (R == RST_LVL) - Q <= RST_VAL; - else if (E == EN_LVL) - Q <= D; - -The cell types ``$_DLATCHSR_[NP][NP][NP]_`` implement d-type latches with set -and reset. The values in the table for these cell types relate to the following -Verilog code template: - -.. code-block:: verilog - :force: - - always @* - if (R == RST_LVL) - Q <= 0; - else if (S == SET_LVL) - Q <= 1; - else if (E == EN_LVL) - Q <= D; - -The cell types ``$_SR_[NP][NP]_`` implement sr-type latches. The values in the -table for these cell types relate to the following Verilog code template: - -.. code-block:: verilog - :force: - - always @* - if (R == RST_LVL) - Q <= 0; - else if (S == SET_LVL) - Q <= 1; - -In most cases gate level logic networks are created from RTL networks using the -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 dfflibmap pass. -The combinatorial logic cells can be mapped to physical cells from a Liberty -file via ABC using the abc pass. - -Add information about ``$slice`` and ``$concat`` cells. - -Add information about ``$lut`` and ``$sop`` cells. - -Add information about ``$alu``, ``$macc``, ``$fa``, and ``$lcu`` cells. diff --git a/yosys/docs/source/CHAPTER_Eval.rst b/yosys/docs/source/CHAPTER_Eval.rst deleted file mode 100644 index 3d463d3f90b..00000000000 --- a/yosys/docs/source/CHAPTER_Eval.rst +++ /dev/null @@ -1,233 +0,0 @@ -.. _chapter:eval: - -Evaluation, conclusion, future Work -=================================== - -The Yosys source tree contains over 200 test cases [1]_ which are used -in the make test make-target. Besides these there is an external Yosys -benchmark and test case package that contains a few larger designs . -This package contains the designs listed in -Tab. \ `[tab:yosys-test-designs] <#tab:yosys-test-designs>`__. - -.. table:: Tests included in the yosys-tests package. - - =========== ========= ================ - ====================================================== - Test-Design Source Gates Description / Comments - =========== ========= ================ - ====================================================== - aes_core IWLS2005 :math:`41{,}837` AES Cipher written by Rudolf Usselmann - i2c IWLS2005 :math:`1{,}072` WISHBONE compliant I2C Master by Richard Herveille - openmsp430 OpenCores :math:`7{,}173` MSP430 compatible CPU by Olivier Girard - or1200 OpenCores :math:`42{,}675` The OpenRISC 1200 CPU by Damjan Lampret - sasc IWLS2005 :math:`456` Simple Async. Serial Comm. Device by Rudolf Usselmann - simple_spi IWLS2005 :math:`690` MC68HC11E based SPI interface by Richard Herveille - spi IWLS2005 :math:`2{,}478` SPI IP core by Simon Srot - ss_pcm IWLS2005 :math:`279` PCM IO Slave by Rudolf Usselmann - systemcaes IWLS2005 :math:`6{,}893` AES core (using SystemC to Verilog) by Javier Castillo - usb_phy IWLS2005 :math:`515` USB 1.1 PHY by Rudolf Usselmann - =========== ========= ================ - ====================================================== - -Correctness of synthesis results --------------------------------- - -The following measures were taken to increase the confidence in the -correctness of the Yosys synthesis results: - -- Yosys comes with a large selection [2]_ of small test cases that are - evaluated when the command 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 make test to ensure better testability of the feature in - question in the future. - -- The designs listed in - Tab. \ `[tab:yosys-test-designs] <#tab:yosys-test-designs>`__ where - validated using the formal verification tool Synopsys 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 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. \ `[tab:yosys-test-designs] <#tab:yosys-test-designs>`__ - validate successfully using Formality. - -- VlogHammer is a set of scripts that auto-generate a large collection - of test cases [3]_ and synthesize them using Yosys and the following - freely available proprietary synthesis tools. - - - Xilinx Vivado WebPack (2013.2) - - - Xilinx ISE (XST) WebPack (14.5) - - - Altera Quartus II Web Edition (13.0) - - 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. [4]_ 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. - - - Xilinx ISIM (from Xilinx ISE 14.5 ) - - - Modelsim 10.1d (from Quartus II 13.0 ) - - - Icarus Verilog (no specific version) - - The set of tests performed by VlogHammer systematically verify the - correct behaviour of - - - Yosys Verilog Frontend and RTL generation - - - Yosys Gate-Level Technology Mapping - - - Yosys SAT Models for RTL- and Gate-Level cells - - - Yosys Constant Evaluator Models for RTL- and Gate-Level cells - - 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). - -Although complex software can never be expected to be fully bug-free -:cite:p:`MURPHY`, it has been shown that Yosys is mature and -feature-complete enough to handle most real-world cases correctly. - -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: - -:: - - hierarchy -check - proc; opt; fsm; opt; memory; opt - techmap; opt; abc; opt - -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: - -:: - - -p artix7 - -use_dsp48 NO - -iobuf NO - -ram_extract NO - -rom_extract NO - -fsm_extract YES - -fsm_encoding Auto - -The results of this comparison is summarized in -Tab. \ `[tab:synth-test] <#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. - -.. table:: Synthesis results (as reported by XST) for OpenMSP430 and -OpenRISC 1200 - - ============================ ==== ==== ========== ==== ===== - ========== - \ - Module Regs LUTs Max. Freq. Regs LUTs Max. Freq. - openMSP430 689 2210 71 MHz 719 2779 53 MHz - 1em omsp_clock_module 21 30 645 MHz 21 30 644 MHz - 1em 1em omsp_sync_cell 2 — 1542 MHz 2 — 1542 MHz - 1em 1em omsp_sync_reset 2 — 1542 MHz 2 — 1542 MHz - 1em omsp_dbg 143 344 292 MHz 149 430 353 MHz - 1em 1em omsp_dbg_uart 76 135 377 MHz 79 139 389 MHz - 1em omsp_execution_unit 266 911 80 MHz 266 1034 137 MHz - 1em 1em omsp_alu — 202 — — 263 — - 1em 1em omsp_register_file 231 478 285 MHz 231 506 293 MHz - 1em omsp_frontend 115 340 178 MHz 118 527 206 MHz - 1em omsp_mem_backbone 38 141 1087 MHz 38 144 1087 MHz - 1em omsp_multiplier 73 397 129 MHz 102 1053 55 MHz - 1em omsp_sfr 6 18 1023 MHz 6 20 1023 MHz - 1em omsp_watchdog 24 53 362 MHz 24 70 360 MHz - or1200_top 7148 9969 135 MHz 7173 10238 108 MHz - 1em or1200_alu — 681 — — 641 — - 1em or1200_cfgr — 11 — — 11 — - 1em or1200_ctrl 175 186 464 MHz 174 279 377 MHz - 1em or1200_except 241 451 313 MHz 241 353 301 MHz - 1em or1200_freeze 6 18 507 MHz 6 16 515 MHz - 1em or1200_if 68 143 806 MHz 68 139 790 MHz - 1em or1200_lsu 8 138 — 12 205 1306 MHz - 1em 1em or1200_mem2reg — 60 — — 66 — - 1em 1em or1200_reg2mem — 29 — — 29 — - 1em or1200_mult_mac 394 2209 240 MHz 394 2230 241 MHz - 1em 1em or1200_amultp2_32x32 256 1783 240 MHz 256 1770 241 MHz - 1em or1200_operandmuxes 65 129 1145 MHz 65 129 1145 MHz - 1em or1200_rf 1041 1722 822 MHz 1042 1722 581 MHz - 1em or1200_sprs 18 432 724 MHz 18 469 722 MHz - 1em or1200_wbmux 33 93 — 33 78 — - 1em or1200_dc_top — 5 — — 5 — - 1em or1200_dmmu_top 2445 1004 — 2445 1043 — - 1em 1em or1200_dmmu_tlb 2444 975 — 2444 1013 — - 1em or1200_du 67 56 859 MHz 67 56 859 MHz - 1em or1200_ic_top 39 100 527 MHz 41 136 514 MHz - 1em 1em or1200_ic_fsm 40 42 408 MHz 40 75 484 MHz - 1em or1200_pic 38 50 1169 MHz 38 50 1177 MHz - 1em or1200_tt 64 112 370 MHz 64 186 437 MHz - ============================ ==== ==== ========== ==== ===== - ========== - -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 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. - -.. [1] - Most of this test cases are copied from HANA or the ASIC-WORLD - website . - -.. [2] - At the time of this writing 269 test cases. - -.. [3] - At the time of this writing over 6600 test cases. - -.. [4] - 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. \ \ `[cmd:sat] <#cmd:sat>`__ for details. - -.. footbibliography:: diff --git a/yosys/docs/source/CHAPTER_Intro.rst b/yosys/docs/source/CHAPTER_Intro.rst deleted file mode 100644 index 90b001c2312..00000000000 --- a/yosys/docs/source/CHAPTER_Intro.rst +++ /dev/null @@ -1,96 +0,0 @@ -.. _chapter:intro: - -Introduction -============ - -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. - -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:p:`Verilog2005,VerilogSynth` and :abbr:`VHDL (VHSIC HDL, where -VHSIC is an acronym for Very-High-Speed Integrated Circuits)` -:cite:p:`VHDL,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:p:`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:p:`LogicSynthesis`. Lexing, -parsing and processing of computer languages :cite:p:`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 [#]_. So the existing FOSS Verilog synthesis -tools were evaluated. 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. - -Structure of this document --------------------------- - -The structure of this document is as follows: - -:numref:`Chapter %s ` is this introduction. - -:numref:`Chapter %s ` covers a short introduction to the world -of HDL synthesis. Basic principles and the terminology are outlined in this -chapter. - -:numref:`Chapter %s ` gives the quickest possible outline to -how the problem of implementing a HDL synthesis tool is approached in the case -of Yosys. - -:numref:`Chapter %s ` 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. - -:numref:`Chapter %s ` 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. - -:numref:`Chapter %s ` 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 :numref:`%s `, :numref:`%s ` and -:numref:`%s ` cover three important pieces of the synthesis -pipeline: The Verilog frontend, the optimization passes and the technology -mapping to the target architecture, respectively. - -Various appendices, including a :ref:`cmd_ref`, complete this document. - -.. [#] - A quick investigation into FOSS VHDL tools yielded similar grim results for - FOSS VHDL synthesis tools. diff --git a/yosys/docs/source/CHAPTER_Optimize.rst b/yosys/docs/source/CHAPTER_Optimize.rst deleted file mode 100644 index 53e0a67aa09..00000000000 --- a/yosys/docs/source/CHAPTER_Optimize.rst +++ /dev/null @@ -1,330 +0,0 @@ -.. _chapter:opt: - -Optimizations -============= - -Yosys employs a number of optimizations to generate better and cleaner results. -This chapter outlines these optimizations. - -Simple optimizations --------------------- - -The Yosys pass 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 -opt pass executes the following passes that each perform a simple optimization: - -- Once at the beginning of opt: - - - opt_expr - - opt_merge -nomux - -- Repeat until result is stable: - - - opt_muxtree - - opt_reduce - - opt_merge - - opt_rmdff - - opt_clean - - opt_expr - -The following section describes each of the opt\_ passes. - -The opt_expr pass -~~~~~~~~~~~~~~~~~ - -This pass performs const folding on the internal combinational cell types -described in :numref:`Chap. %s `. 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. - -.. table:: Const folding rules for $_AND\_ cells as used in opt_expr. - :name: tab:opt_expr_and - :align: center - - ========= ========= =========== - A-Input B-Input Replacement - ========= ========= =========== - any 0 0 - 0 any 0 - 1 1 1 - --------- --------- ----------- - X/Z X/Z X - 1 X/Z X - X/Z 1 X - --------- --------- ----------- - any X/Z 0 - X/Z any 0 - --------- --------- ----------- - :math:`a` 1 :math:`a` - 1 :math:`b` :math:`b` - ========= ========= =========== - -.. How to format table? - -:numref:`Table %s ` shows the replacement rules used for -optimizing an $_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:p:`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 $_AND\_ gate with one constant-1 input with -a buffer. - -Besides this basic const folding the opt_expr pass can replace 1-bit wide $eq -and $ne cells with buffers or not-gates if one input is constant. - -The opt_expr pass is very conservative regarding optimizing $mux cells, as these -cells are often used to model decision-trees and breaking these trees can -interfere with other optimizations. - -The opt_muxtree pass -~~~~~~~~~~~~~~~~~~~~ - -This pass optimizes trees of multiplexer cells by analyzing the select inputs. -Consider the following simple example: - -.. code:: verilog - :number-lines: - - module uut(a, y); input a; output [1:0] y = a ? (a ? 1 : 2) : 3; endmodule - -The output can never be 2, as this would require ``a`` to be 1 for the outer -multiplexer and 0 for the inner multiplexer. The opt_muxtree pass detects this -contradiction and replaces the inner multiplexer with a constant 1, yielding the -logic for ``y = a ? 1 : 3``. - -The opt_reduce pass -~~~~~~~~~~~~~~~~~~~ - -This is a simple optimization pass that identifies and consolidates identical -input bits to $reduce_and and $reduce_or cells. It also sorts the input bits to -ease identification of shareable $reduce_and and $reduce_or cells in other -passes. - -This pass also identifies and consolidates identical inputs to multiplexer -cells. In this case the new shared select bit is driven using a $reduce_or cell -that combines the original select bits. - -Lastly this pass consolidates trees of $reduce_and cells and trees of $reduce_or -cells to single large $reduce_and or $reduce_or cells. - -These three simple optimizations are performed in a loop until a stable result -is produced. - -The opt_rmdff pass -~~~~~~~~~~~~~~~~~~ - -This pass identifies single-bit d-type flip-flops ($_DFF\_, $dff, and $adff -cells) with a constant data input and replaces them with a constant driver. - -The opt_clean pass -~~~~~~~~~~~~~~~~~~ - -This pass identifies unused signals and cells and removes them from the design. -It also creates an ``\unused_bits`` attribute on wires with unused bits. This -attribute can be used for debugging or by other optimization passes. - -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 -nomux can be used to disable resource sharing for multiplexer cells -($mux and $pmux. This can be useful as it prevents multiplexer trees to be -merged, which might prevent opt_muxtree to identify possible optimizations. - -FSM extraction and encoding ---------------------------- - -The fsm pass performs finite-state-machine (FSM) extraction and recoding. The -fsm pass simply executes the following other passes: - -- Identify and extract FSMs: - - - fsm_detect - - fsm_extract - -- Basic optimizations: - - - fsm_opt - - opt_clean - - fsm_opt - -- Expanding to nearby gate-logic (if called with -expand): - - - fsm_expand - - opt_clean - - fsm_opt - -- Re-code FSM states (unless called with -norecode): - - - fsm_recode - -- Print information about FSMs: - - - fsm_info - -- Export FSMs in KISS2 file format (if called with -export): - - - fsm_export - -- Map FSMs to RTL cells (unless called with -nomap): - - - fsm_map - -The fsm_detect pass identifies FSM state registers and marks them using the -``\fsm_encoding = "auto"`` attribute. The fsm_extract extracts all FSMs marked -using the ``\fsm_encoding`` attribute (unless ``\fsm_encoding`` is set to -"none") and replaces the corresponding RTL cells with a $fsm cell. All other -fsm\_ passes operate on these $fsm cells. The fsm_map call finally replaces the -$fsm cells with RTL cells. - -Note that these optimizations operate on an RTL netlist. I.e. the fsm pass -should be executed after the proc pass has transformed all RTLIL::Process -objects to RTL cells. - -The algorithms used for FSM detection and extraction are influenced by a more -general reported technique :cite:p:`fsmextract`. - -FSM detection -~~~~~~~~~~~~~ - -The fsm_detect pass identifies FSM state registers. It sets the ``\fsm_encoding -= "auto"`` attribute on any (multi-bit) wire that matches the following -description: - -- Does not already have the ``\fsm_encoding`` attribute. -- Is not an output of the containing module. -- Is driven by single $dff or $adff cell. -- The ``\D``-Input of this $dff or $adff cell is driven by a multiplexer tree - that only has constants or the old state value on its leaves. -- 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 $eq - cells). - -This heuristic has proven to work very well. It is possible to overwrite it by -setting ``\fsm_encoding = "auto"`` on registers that should be considered FSM -state registers and setting ``\fsm_encoding = "none"`` on registers that match -the above criteria but should not be considered FSM state registers. - -Note however that marking state registers with ``\fsm_encoding`` that are not -suitable for FSM recoding can cause synthesis to fail or produce invalid -results. - -FSM extraction -~~~~~~~~~~~~~~ - -The fsm_extract pass operates on all state signals marked with the -(``\fsm_encoding != "none"``) attribute. For each state signal the following -information is determined: - -- The state registers - -- The asynchronous reset state if the state registers use asynchronous reset - -- All states and the control input signals used in the state transition - functions - -- The control output signals calculated from the state signals and control - inputs - -- A table of all state transitions and corresponding control inputs- and - outputs - -The state registers (and asynchronous reset state, if applicable) is simply -determined by identifying the driver for the state signal. - -From there the $mux-tree driving the state register inputs is recursively -traversed. All select inputs are control signals and the leaves of the $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 -ConstEval C++ helper class (defined in kernel/consteval.h) that can be used to -evaluate parts of the design. The 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 ConstEval algorithm if the value -of a stop-signal is needed in order to calculate the result signals. - -The fsm_extract pass uses the ConstEval class in the following way to create a -transition table. For each state: - -1. Create a ConstEval object for the module containing the FSM -2. Add all control inputs to the list of stop signals -3. Set the state signal to the current state -4. Try to evaluate the next state and control output -5. If step 4 was not successful: - - - Recursively goto step 4 with the offending stop-signal set to 0. - - Recursively goto step 4 with the offending stop-signal set to 1. - -6. If step 4 was successful: Emit transition - -Finally a $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. - -FSM optimization -~~~~~~~~~~~~~~~~ - -The fsm_opt pass performs basic optimizations on $fsm cells (not including state -recoding). The following optimizations are performed (in this order): - -- Unused control outputs are removed from the $fsm cell. The attribute - ``\unused_bits`` (that is usually set by the opt_clean pass) is used to - determine which control outputs are unused. - -- Control inputs that are connected to the same driver are merged. - -- 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. - -- 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). - -- Constant inputs are removed and the transition table is altered to give an - unchanged behaviour. - -- Unused inputs are removed. - -FSM recoding -~~~~~~~~~~~~ - -The 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 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 . - -Logic optimization ------------------- - -Yosys can perform multi-level combinational logic optimization on gate-level -netlists using the external program ABC . The abc pass extracts the -combinational gate-level parts of the design, passes it through ABC, and -re-integrates the results. The abc pass can also be used to perform other -operations using ABC, such as technology mapping (see :numref:`Sec %s -` for details). diff --git a/yosys/docs/source/CHAPTER_Overview.rst b/yosys/docs/source/CHAPTER_Overview.rst deleted file mode 100644 index 10d2ce47840..00000000000 --- a/yosys/docs/source/CHAPTER_Overview.rst +++ /dev/null @@ -1,571 +0,0 @@ -.. _chapter:overview: - -Implementation 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`_, the -`openMSP430 CPU`_, the `OpenCores I2C master`_, and the `k68 CPU`_. - -.. _OpenRISC 1200 CPU: https://github.com/openrisc/or1200 - -.. _openMSP430 CPU: http://opencores.org/projects/openmsp430 - -.. _OpenCores I2C master: http://opencores.org/projects/i2c - -.. _k68 CPU: http://opencores.org/projects/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. - -Simplified data flow --------------------- - -:numref:`Figure %s ` 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 RTLIL 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 -RTLIL Backend for writing the RTLIL data in the same format that is understood -by the RTLIL 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. - -.. figure:: ../images/overview_flow.* - :class: width-helper - :name: fig:Overview_flow - - Yosys simplified data flow (ellipses: data structures, rectangles: - program modules) - -The RTL Intermediate Language (RTLIL) -------------------------------------- - -All frontends, passes and backends in Yosys operate on a design in RTLIL -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 RTLIL:: namespace prefix, -in this document. - -:numref:`Figure %s ` shows a simplified Entity-Relationship -Diagram (ER Diagram) of RTLIL. In :math:`1:N` relationships the arrow points -from the :math:`N` side to the :math:`1`. For example one RTLIL::Design contains -:math:`N` (zero to many) instances of RTLIL::Module. A two-pointed arrow -indicates a :math:`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. - -.. figure:: ../images/overview_rtlil.* - :class: width-helper - :name: fig:Overview_RTLIL - - Simplified RTLIL Entity-Relationship Diagram - -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: - -- RTLIL::Cell and RTLIL::Wire objects represent classical netlist data. - -- RTLIL::Process objects represent the decision trees (if-then-else statements, - etc.) and synchronization declarations (clock signals and sensitivity) from - Verilog always and VHDL process blocks. - -- RTLIL::Memory objects represent addressable memories (arrays). - -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. - -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. - -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 (\) 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 -"\\sig42" is most likely a signal that was declared using the name "sig42" in an -HDL input file. On the other hand the signal name "$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: - -- First, it is impossible that an auto-generated identifier collides with an - identifier that was provided by the user. - -- 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. - -- 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 \_integer\_. - -Whitespace and control characters (any character with an ASCII code 32 or less) -are not allowed in RTLIL identifiers; most frontends and backends cannot support -these characters in identifiers. - -In order to avoid programming errors, the RTLIL data structures check if all -identifiers start with either a backslash or a dollar sign, and contain no -whitespace or control characters. Violating these rules results in a runtime -error. - -All RTLIL identifiers are case sensitive. - -Some transformations, such as flattening, may have to change identifiers -provided by the user to avoid name collisions. When that happens, attribute -"hdlname" is attached to the object with the changed identifier. This attribute -contains one name (if emitted directly by the frontend, or is a result of -disambiguation) or multiple names separated by spaces (if a result of -flattening). All names specified in the "hdlname" attribute are public and do -not include the leading "\". - -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 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 :numref:`Fig. %s -` an RTLIL::Module object contains the following additional -properties: - -- The module name -- A list of attributes -- A list of connections between wires -- An optional frontend callback used to derive parametrized variations of the - module - -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.) - -.. _sec:rtlil_cell_wire: - -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: - -- The wire name -- A list of attributes -- A width (buses are just wires with a width > 1) -- Bus direction (MSB to LSB or vice versa) -- Lowest valid bit index (LSB or MSB depending on bus direction) -- If the wire is a port: port number and direction (input/output/inout) - -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. - -In Verilog and VHDL, busses may have arbitrary bounds, and LSB can have either -the lowest or the highest bit index. In RTLIL, bit 0 always corresponds to LSB; -however, information from the HDL frontend is preserved so that the bus will be -correctly indexed in error messages, backend output, constraint files, etc. - -An RTLIL::Cell object has the following properties: - -- The cell name and type -- A list of attributes -- A list of parameters (for parametric cells) -- Cell ports and the connections of ports to wires and constants - -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. - -.. _sec:rtlil_sigspec: - -RTLIL::SigSpec -~~~~~~~~~~~~~~ - -A "signal" is everything that can be applied to a cell port. I.e. - -- | Any constant value of arbitrary bit-width - | 1em For example: ``1337, 16'b0000010100111001, 1'b1, 1'bx`` - -- | All bits of a wire or a selection of bits from a wire - | 1em For example: ``mywire, mywire[24], mywire[15:8]`` - -- | Concatenations of the above - | 1em For example: ``{16'd1337, mywire[15:8]}`` - -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. - -.. _sec:rtlil_process: - -RTLIL::Process -~~~~~~~~~~~~~~ - -When a high-level HDL frontend processes behavioural code it splits it up into -data path logic (e.g. the expression a + b is replaced by the output of an adder -that takes a and b as inputs) and an RTLIL::Process that models the control -logic of the behavioural code. Let's consider a simple example: - -.. code:: verilog - :number-lines: - - 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 - -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 RTLIL syntax: - -.. code:: RTLIL - :number-lines: - - 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 - -This RTLIL::Process contains two RTLIL::SyncRule objects, two RTLIL::SwitchRule -objects and five RTLIL::CaseRule objects. The wire $0\q[0:0] is an automatically -created wire that holds the next value of \\q. The lines :math:`2 \dots 12` -describe how $0\q[0:0] should be calculated. The lines :math:`13 \dots 16` -describe how the value of $0\q[0:0] is used to update \\q. - -An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and -exactly one RTLIL::CaseRule object, which is called the root case. - -An RTLIL::SyncRule object contains an (optional) synchronization condition -(signal and edge-type), zero or more assignments (RTLIL::SigSig), and zero or -more memory writes (RTLIL::MemWriteAction). The 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 :math:`2 \dots 12` are the root case. Here -$0\q[0:0] is first assigned the old value \\q as default value (line 2). The -root case also contains an RTLIL::SwitchRule object (lines :math:`3 \dots 12`). -Such an object is very similar to the C switch statement as it uses a control -signal (\\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 [1]_ for \\reset == 1 that causes $0\q[0:0] to -be set (lines 4 and 5) and a default case that in turn contains a switch that -sets $0\q[0:0] to the value of \\d if \\enable is active (lines :math:`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 parallel_case attribute allows passes to assume that no -more than one case will match, and 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 :math:`13 \dots 16` then cause \\q to be updated whenever there is a -positive clock edge on \\clock or \\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 proc_arst pass. This pass transforms the above example to the following -RTLIL::Process: - -.. code:: RTLIL - :number-lines: - - 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 - -This pass has transformed the outer RTLIL::SwitchRule into a modified -RTLIL::SyncRule object for the \\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: - -.. code:: RTLIL - :number-lines: - - 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 - -Different combinations of passes may yield different results. Note that $adff -and $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 proc pass calls a series of other passes -that together perform this conversion in a way that is suitable for most -synthesis tasks. - -.. _sec:rtlil_memory: - -RTLIL::Memory -~~~~~~~~~~~~~ - -For every array (memory) in the HDL code an RTLIL::Memory object is created. A -memory object has the following properties: - -- The memory name -- A list of attributes -- The width of an addressable word -- The size of the memory in number of words - -All read accesses to the memory are transformed to $memrd cells and all write -accesses to $memwr cells by the language frontend. These cells consist of -independent read- and write-ports to the memory. Memory initialization is -transformed to $meminit cells by the language frontend. The ``\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 $memrd and $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 $memrd -and $memwr cells to multiport memory blocks after resource sharing is completed. - -The 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 $mem cells). - -See :numref:`Sec. %s ` for details about the memory cell types. - -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 (;). Empty lines and lines -starting with the hash sign (#) are ignored. See :numref:`Sec. %s -` for an example synthesis script. - -The command help can be used to access the command reference manual. - -Most commands can operate not only on the entire design but also specifically on -selected parts of the design. For example the command dump will print all -selected objects in the current design while dump foobar will only print the -module foobar and dump \* will print the entire design regardless of the current -selection. - -.. code:: yoscrypt - - dump */t:$add %x:+[A] \*/w:\* %i - -The selection mechanism is very powerful. For example the command above will -print all wires that are connected to the ``\A`` port of a ``$add`` cell. -Detailed documentation of the select framework can be found in the command -reference for the ``select`` command. - -Source tree and build system ----------------------------- - -The Yosys source tree is organized into the following top-level -directories: - -- | backends/ - | This directory contains a subdirectory for each of the backend modules. - -- | frontends/ - | This directory contains a subdirectory for each of the frontend modules. - -- | kernel/ - | This directory contains all the core functionality of Yosys. This includes - the functions and definitions for working with the RTLIL data structures - (rtlil.h and rtlil.cc), the main() function (driver.cc), the internal - framework for generating log messages (log.h and log.cc), the internal - framework for registering and calling passes (register.h and register.cc), - some core commands that are not really passes (select.cc, show.cc, …) and a - couple of other small utility libraries. - -- | passes/ - | This directory contains a subdirectory for each pass or group of passes. - For example as of this writing the directory passes/opt/ contains the code - for seven passes: opt, opt_expr, opt_muxtree, opt_reduce, opt_rmdff, - opt_rmunused and opt_merge. - -- | techlibs/ - | This directory contains simulation models and standard implementations for - the cells from the internal cell library. - -- | tests/ - | This directory contains a couple of test cases. Most of the smaller tests - are executed automatically when 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. - -The top-level Makefile includes frontends/\*/Makefile.inc, -passes/\*/Makefile.inc and backends/\*/Makefile.inc. So when extending Yosys it -is enough to create a new directory in frontends/, passes/ or backends/ with -your sources and a 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. - -Good starting points for reading example source code to learn how to write -passes are passes/opt/opt_rmdff.cc and passes/opt/opt_merge.cc. - -See the top-level README file for a quick 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 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. - -.. [1] - The syntax 1'1 in the RTLIL code specifies a constant with a length of one - bit (the first "1"), and this bit is a one (the second "1"). diff --git a/yosys/docs/source/CHAPTER_Prog.rst b/yosys/docs/source/CHAPTER_Prog.rst deleted file mode 100644 index 23aeed5a50c..00000000000 --- a/yosys/docs/source/CHAPTER_Prog.rst +++ /dev/null @@ -1,46 +0,0 @@ -.. _chapter:prog: - -Programming Yosys extensions -============================ - -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 YosysHQ Slack. - -Guidelines ----------- - -The guidelines directory contains notes on various aspects of Yosys -development. The files GettingStarted and CodingStyle may be of -particular interest, and are reproduced here. - -.. literalinclude:: temp/GettingStarted - :language: none - :caption: guidelines/GettingStarted - -.. literalinclude:: temp/CodingStyle - :language: none - :caption: guidelines/CodingStyle - -The "stubsnets" example module ------------------------------- - -The following is the complete code of the "stubsnets" example module. It -is included in the Yosys source distribution as -docs/source/CHAPTER_Prog/stubnets.cc. - -.. literalinclude:: CHAPTER_Prog/stubnets.cc - :language: c++ - :linenos: - :caption: docs/source/CHAPTER_Prog/stubnets.cc - -.. literalinclude:: CHAPTER_Prog/Makefile - :language: makefile - :linenos: - :caption: docs/source/CHAPTER_Prog/Makefile - -.. literalinclude:: CHAPTER_Prog/test.v - :language: verilog - :linenos: - :caption: docs/source/CHAPTER_Prog/test.v diff --git a/yosys/docs/source/CHAPTER_Prog/.gitignore b/yosys/docs/source/CHAPTER_Prog/.gitignore deleted file mode 100644 index fa83c32120a..00000000000 --- a/yosys/docs/source/CHAPTER_Prog/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -stubnets.so -stubnets.d -*.log diff --git a/yosys/docs/source/CHAPTER_Prog/Makefile b/yosys/docs/source/CHAPTER_Prog/Makefile deleted file mode 100644 index 8e326bdc266..00000000000 --- a/yosys/docs/source/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/docs/source/CHAPTER_Prog/stubnets.cc b/yosys/docs/source/CHAPTER_Prog/stubnets.cc deleted file mode 100644 index 566d24b18df..00000000000 --- a/yosys/docs/source/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) 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/docs/source/CHAPTER_Prog/test.v b/yosys/docs/source/CHAPTER_Prog/test.v deleted file mode 100644 index 201f7500681..00000000000 --- a/yosys/docs/source/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/docs/source/CHAPTER_Techmap.rst b/yosys/docs/source/CHAPTER_Techmap.rst deleted file mode 100644 index 6cd1eb44f39..00000000000 --- a/yosys/docs/source/CHAPTER_Techmap.rst +++ /dev/null @@ -1,105 +0,0 @@ -.. _chapter:techmap: - -Technology mapping -================== - -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 :numref:`Sec. -%s `). 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. - -Cell substitution ------------------ - -The simplest form of technology mapping is cell substitution, as performed by -the 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, 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 techlibs/common/techmap.v in the Yosys source -tree. - -Additional features have been added to techmap to allow for conditional mapping -of cells (see :doc:`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 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. - -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 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 extract pass also finds basic variations of the given modules, such as -swapped inputs on commutative cell types. - -In addition to this the 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:p:`intersynthFdlBookChapter`. - -The hard algorithmic work done by the 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 -:ref:`sec:SubCircuit`). - -.. _sec:techmap_extern: - -Gate-level technology mapping ------------------------------ - -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 . - -Mapping a design utilizing the Yosys internal gate library (e.g. as a result of -mapping it to this representation using the 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 dfflibmap pass. This -pass expects a Liberty file as argument (using the -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 via the abc pass by using the -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 yosys-filterlib (see :ref:`sec:filterlib`) can be used to strip the -sensitive information from the Liberty file. diff --git a/yosys/docs/source/CHAPTER_Verilog.rst b/yosys/docs/source/CHAPTER_Verilog.rst deleted file mode 100644 index 484844fba04..00000000000 --- a/yosys/docs/source/CHAPTER_Verilog.rst +++ /dev/null @@ -1,666 +0,0 @@ -.. _chapter:verilog: - -The Verilog and AST frontends -============================= - -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 :numref:`Fig. %s `. - -.. figure:: ../images/verilog_flow.* - :class: width-helper - :name: fig:Verilog_flow - - Simplified Verilog to RTLIL data flow - -Transforming Verilog to AST ---------------------------- - -The 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 -Preprocessor, the Lexer and the Parser. - -The source code to the Verilog frontend can be found in -frontends/verilog/ in the Yosys source tree. - -The Verilog preprocessor -~~~~~~~~~~~~~~~~~~~~~~~~ - -The Verilog preprocessor scans over the Verilog source code and -interprets some of the Verilog compiler directives such as -:literal:`\`include`, :literal:`\`define` and :literal:`\`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 ``std::string``. - -The source code to the Verilog Preprocessor can be found in -frontends/verilog/preproc.cc in the Yosys source tree. - -The Verilog lexer -~~~~~~~~~~~~~~~~~ - -The Verilog Lexer is written using the lexer generator flex . Its source -code can be found in frontends/verilog/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. - -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. - -Finally the lexer identifies and handles special comments such as -"``// synopsys translate_off``" and "``// synopsys full_case``". (It is -recommended to use :literal:`\`ifdef` constructs instead of the -Synsopsys translate_on/off comments and attributes such as -``(* full_case *)`` over "``// synopsys full_case``" whenever possible.) - -The Verilog parser -~~~~~~~~~~~~~~~~~~ - -The Verilog Parser is written using the parser generator bison . Its -source code can be found in frontends/verilog/verilog_parser.y in the -Yosys source tree. - -It generates an AST using the ``AST::AstNode`` data structure defined in -frontends/ast/ast.h. An ``AST::AstNode`` object has the following -properties: - -.. list-table:: AST node types with their corresponding Verilog constructs. - :name: tab:Verilog_AstNodeType - :widths: 50 50 - - * - AST Node Type - - Corresponding Verilog Construct - * - AST_NONE - - This Node type should never be used. - * - AST_DESIGN - - This node type is used for the top node of the AST tree. It has no corresponding Verilog construct. - * - AST_MODULE, AST_TASK, AST_FUNCTION - - ``module``, ``task`` and ``function`` - * - AST_WIRE - - ``input``, ``output``, ``wire``, ``reg`` and ``integer`` - * - AST_MEMORY - - Verilog Arrays - * - AST_AUTOWIRE - - Created by the simplifier when an undeclared signal name is used. - * - AST_PARAMETER, AST_LOCALPARAM - - ``parameter`` and ``localparam`` - * - AST_PARASET - - Parameter set in cell instantiation - * - AST_ARGUMENT - - Port connection in cell instantiation - * - AST_RANGE - - Bit-Index in a signal or element index in array - * - AST_CONSTANT - - A literal value - * - AST_CELLTYPE - - The type of cell in cell instantiation - * - AST_IDENTIFIER - - An Identifier (signal name in expression or cell/task/etc. name in other contexts) - * - AST_PREFIX - - Construct an identifier in the form []. (used only in advanced generate constructs) - * - AST_FCALL, AST_TCALL - - Call to function or task - * - AST_TO_SIGNED, AST_TO_UNSIGNED - - The ``$signed()`` and ``$unsigned()`` functions - * - AST_CONCAT, AST_REPLICATE - - The ``{...}`` and ``{...{...}}`` operators - * - AST_BIT_NOT, AST_BIT_AND, AST_BIT_OR, AST_BIT_XOR, AST_BIT_XNOR - - The bitwise operators ``~``, ``&``, ``|``, ``^`` and ``~^`` - * - AST_REDUCE_AND, AST_REDUCE_OR, AST_REDUCE_XOR, AST_REDUCE_XNOR - - The unary reduction operators ``~``, ``&``, ``|``, ``^`` and ``~^`` - * - AST_REDUCE_BOOL - - Conversion from multi-bit value to boolean value (equivalent to AST_REDUCE_OR) - * - AST_SHIFT_LEFT, AST_SHIFT_RIGHT, AST_SHIFT_SLEFT, AST_SHIFT_SRIGHT - - The shift operators ``<<``, ``>>``, ``<<<`` and ``>>>`` - * - AST_LT, AST_LE, AST_EQ, AST_NE, AST_GE, AST_GT - - The relational operators ``<``, ``<=``, ``==``, ``!=``, ``>=`` and ``>`` - * - AST_ADD, AST_SUB, AST_MUL, AST_DIV, AST_MOD, AST_POW - - The binary operators ``+``, ``-``, ``*``, ``/``, ``%`` and ``**`` - * - AST_POS, AST_NEG - - The prefix operators ``+`` and ``-`` - * - AST_LOGIC_AND, AST_LOGIC_OR, AST_LOGIC_NOT - - The logic operators ``&&``, ``||`` and ``!`` - * - AST_TERNARY - - The ternary ``?:``-operator - * - AST_MEMRD AST_MEMWR - - Read and write memories. These nodes are generated by the AST simplifier for writes/reads to/from Verilog arrays. - * - AST_ASSIGN - - An ``assign`` statement - * - AST_CELL - - A cell instantiation - * - AST_PRIMITIVE - - A primitive cell (``and``, ``nand``, ``or``, etc.) - * - AST_ALWAYS, AST_INITIAL - - Verilog ``always``- and ``initial``-blocks - * - AST_BLOCK - - A ``begin``-``end``-block - * - AST_ASSIGN_EQ. AST_ASSIGN_LE - - Blocking (``=``) and nonblocking (``<=``) assignments within an ``always``- or ``initial``-block - * - AST_CASE. AST_COND, AST_DEFAULT - - The ``case`` (``if``) statements, conditions within a case and the default case respectively - * - AST_FOR - - A ``for``-loop with an ``always``- or ``initial``-block - * - AST_GENVAR, AST_GENBLOCK, AST_GENFOR, AST_GENIF - - The ``genvar`` and ``generate`` keywords and ``for`` and ``if`` within a generate block. - * - AST_POSEDGE, AST_NEGEDGE, AST_EDGE - - Event conditions for ``always`` blocks. - -- | The node type - | This enum (``AST::AstNodeType``) specifies the role of the node. - :numref:`Table %s ` - contains a list of all node types. - -- | The child nodes - | This is a list of pointers to all children in the abstract syntax - tree. - -- | Attributes - | As almost every AST node might have Verilog attributes assigned to - it, the ``AST::AstNode`` has direct support for attributes. Note - that the attribute values are again AST nodes. - -- | Node content - | Each node might have additional content data. A series of member - variables exist to hold such data. For example the member - ``std::string str`` can hold a string value and is used e.g. in the - AST_IDENTIFIER node type to store the identifier name. - -- | Source code location - | Each ``AST::AstNode`` is automatically annotated with the current - source code location by the ``AST::AstNode`` constructor. It is - stored in the ``std::string filename`` and ``int linenum`` member - variables. - -The ``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: - -.. code:: none - :number-lines: - - basic_expr '*' attr basic_expr { - $$ = new AstNode(AST_MUL, $1, $4); - append_attr($$, $3); - } | - -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 ``read_verilog`` provides the options ``-yydebug`` -and ``-dump_ast`` that can be used to print the parse tree or abstract -syntax tree respectively. - -Transforming AST to RTLIL -------------------------- - -The 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: simplification and RTLIL generation. - -The source code to the AST frontend can be found in ``frontends/ast/`` in -the Yosys source tree. - -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 ``AST::AstNode::simplify()`` method of all -AST_MODULE nodes in the AST. This initiates a recursive process that -performs the following transformations on the AST data structure: - -- Inline all task and function calls. - -- Evaluate all ``generate``-statements and unroll all ``for``-loops. - -- Perform const folding where it is necessary (e.g. in the value part - of AST_PARAMETER, AST_LOCALPARAM, AST_PARASET and AST_RANGE nodes). - -- Replace AST_PRIMITIVE nodes with appropriate AST_ASSIGN nodes. - -- Replace dynamic bit ranges in the left-hand-side of assignments with - AST_CASE nodes with AST_COND children for each possible case. - -- Detect array access patterns that are too complicated for the - RTLIL::Memory abstraction and replace them with a set of signals and - cases for all reads and/or writes. - -- Otherwise replace array accesses with AST_MEMRD and AST_MEMWR nodes. - -In addition to these transformations, the simplifier also annotates the -AST with additional information that is needed for the RTLIL generator, -namely: - -- 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 AST_RANGE node. - -- All identifiers are resolved and all 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 - AST_AUTOWIRE node is created and used for the annotation. - -This produces an AST that is fairly easy to convert to the RTLIL format. - -Generating RTLIL -~~~~~~~~~~~~~~~~ - -After AST simplification, the ``AST::AstNode::genRTLIL()`` method of -each AST_MODULE node in the AST is called. This initiates a recursive -process that generates equivalent RTLIL data for the AST data. - -The ``AST::AstNode::genRTLIL()`` method returns an ``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 AST_CELL), the corresponding circuit is generated and an empty -``RTLIL::SigSpec`` is returned. - -Synthesizing Verilog always blocks --------------------------------------- - -For behavioural Verilog code (code utilizing ``always``- and -``initial``-blocks) it is necessary to also generate ``RTLIL::Process`` -objects. This is done in the following way: - -Whenever ``AST::AstNode::genRTLIL()`` encounters an ``always``- or -``initial``-block, it creates an instance of -``AST_INTERNAL::ProcessGenerator``. This object then generates the -``RTLIL::Process`` object for the block. It also calls -``AST::AstNode::genRTLIL()`` for all right-hand-side expressions -contained within the block. - -First the ``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 $\ \\\ for each -of the assigned signals. - -Then an ``RTLIL::Process`` is created that assigns all intermediate -values for each left-hand-side signal to the temporary signal in its -``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree. - -Finally a ``RTLIL::SyncRule`` is created for the ``RTLIL::Process`` that -assigns the temporary signals for the final values to the actual -signals. - -A process may also contain memory writes. A ``RTLIL::MemWriteAction`` is -created for each of them. - -Calls to ``AST::AstNode::genRTLIL()`` are generated for right hand sides -as needed. When blocking assignments are used, -``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. - -Unfortunately the generation of a correct -``RTLIL::CaseRule``/``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: - -.. code:: verilog - :number-lines: - - 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 - -This is translated by the Verilog and AST frontends into the following -RTLIL code (attributes, cell parameters and wire declarations not -included): - -.. code:: RTLIL - :number-lines: - - 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 - -Note that the two operators are translated into separate cells outside -the generated process. The signal ``out1`` is assigned using blocking -assignments and therefore ``out1`` has been replaced with a different -signal in all expressions after the initial assignment. The signal -``out2`` is assigned using nonblocking assignments and therefore is not -substituted on the right-hand-side expressions. - -The ``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree must be interpreted -the following way: - -- On each case level (the body of the process is the 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 - ``RTLIL::SwitchRule`` objects within a ``RTLIL::CaseRule`` is - preserved with respect to the original AST and Verilog code. - -- The whole ``RTLIL::CaseRule``/``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". - -The only synchronous part of the process is in the ``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 (posedge) and signal (\\clock) for the -``RTLIL::SyncRule`` object. In the case of this simple example the -``RTLIL::SyncRule`` object is later simply transformed into a set of -d-type flip-flops and the ``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree -to a decision tree using multiplexers. - -In more complex examples (e.g. asynchronous resets) the part of the -``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree that describes the -asynchronous reset must first be transformed to the correct -``RTLIL::SyncRule`` objects. This is done by the proc_adff pass. - -The ProcessGenerator algorithm -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``AST_INTERNAL::ProcessGenerator`` uses the following internal state -variables: - -- | ``subst_rvalue_from`` and ``subst_rvalue_to`` - | These two variables hold the replacement pattern that should be - used by ``AST::AstNode::genRTLIL()`` for signals with blocking - assignments. After initialization of - ``AST_INTERNAL::ProcessGenerator`` these two variables are empty. - -- | ``subst_lvalue_from`` and ``subst_lvalue_to`` - | These two variables contain the mapping from left-hand-side signals - (\\\ ) to the current temporary signal for the same thing - (initially $0\\\ ). - -- | ``current_case`` - | A pointer to a ``RTLIL::CaseRule`` object. Initially this is the - root case of the generated ``RTLIL::Process``. - -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 ``RTLIL::Process`` -object with an empty root case and initializes its state variables as -described above. Then the ``RTLIL::SyncRule`` objects are created using -the synchronization events from the AST_ALWAYS node and the initial -values of ``subst_lvalue_from`` and ``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: AST_ASSIGN_LE (nonblocking assignments), -AST_ASSIGN_EQ (blocking assignments) and AST_CASE (``if`` or ``case`` -statement). - -Handling of nonblocking assignments -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When an AST_ASSIGN_LE node is discovered, the following actions are -performed by the ProcessGenerator: - -- The left-hand-side is evaluated using ``AST::AstNode::genRTLIL()`` - and mapped to a temporary signal name using ``subst_lvalue_from`` and - ``subst_lvalue_to``. - -- The right-hand-side is evaluated using ``AST::AstNode::genRTLIL()``. - For this call, the values of ``subst_rvalue_from`` and - ``subst_rvalue_to`` are used to map blocking-assigned signals - correctly. - -- Remove all assignments to the same left-hand-side as this assignment - from the ``current_case`` and all cases within it. - -- Add the new assignment to the ``current_case``. - -Handling of blocking assignments -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When an AST_ASSIGN_EQ node is discovered, the following actions are -performed by the ProcessGenerator: - -- Perform all the steps that would be performed for a nonblocking - assignment (see above). - -- Remove the found left-hand-side (before lvalue mapping) from - ``subst_rvalue_from`` and also remove the respective bits from - ``subst_rvalue_to``. - -- Append the found left-hand-side (before lvalue mapping) to - ``subst_rvalue_from`` and append the found right-hand-side to - ``subst_rvalue_to``. - -Handling of cases and if-statements -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When an AST_CASE node is discovered, the following actions are performed -by the ProcessGenerator: - -- The values of ``subst_rvalue_from``, ``subst_rvalue_to``, - ``subst_lvalue_from`` and ``subst_lvalue_to`` are pushed to the - stack. - -- A new ``RTLIL::SwitchRule`` object is generated, the selection - expression is evaluated using ``AST::AstNode::genRTLIL()`` (with the - use of ``subst_rvalue_from`` and ``subst_rvalue_to``) and added to - the ``RTLIL::SwitchRule`` object and the object is added to the - ``current_case``. - -- All lvalues assigned to within the AST_CASE node using blocking - assignments are collected and saved in the local variable - ``this_case_eq_lvalue``. - -- New temporary signals are generated for all signals in - ``this_case_eq_lvalue`` and stored in ``this_case_eq_ltemp``. - -- The signals in ``this_case_eq_lvalue`` are mapped using - ``subst_rvalue_from`` and ``subst_rvalue_to`` and the resulting set - of signals is stored in ``this_case_eq_rvalue``. - -Then the following steps are performed for each AST_COND node within the -AST_CASE node: - -- Set ``subst_rvalue_from``, ``subst_rvalue_to``, ``subst_lvalue_from`` - and ``subst_lvalue_to`` to the values that have been pushed to the - stack. - -- Remove ``this_case_eq_lvalue`` from - ``subst_lvalue_from``/``subst_lvalue_to``. - -- Append ``this_case_eq_lvalue`` to ``subst_lvalue_from`` and append - ``this_case_eq_ltemp`` to ``subst_lvalue_to``. - -- Push the value of ``current_case``. - -- Create a new ``RTLIL::CaseRule``. Set ``current_case`` to the new - object and add the new object to the ``RTLIL::SwitchRule`` created - above. - -- Add an assignment from ``this_case_eq_rvalue`` to - ``this_case_eq_ltemp`` to the new ``current_case``. - -- Evaluate the compare value for this case using - ``AST::AstNode::genRTLIL()`` (with the use of ``subst_rvalue_from`` - and ``subst_rvalue_to``) modify the new ``current_case`` accordingly. - -- Recursion into the children of the AST_COND node. - -- Restore ``current_case`` by popping the old value from the stack. - -Finally the following steps are performed: - -- The values of ``subst_rvalue_from``, ``subst_rvalue_to``, - ``subst_lvalue_from`` and ``subst_lvalue_to`` are popped from the - stack. - -- The signals from ``this_case_eq_lvalue`` are removed from the - ``subst_rvalue_from``/``subst_rvalue_to``-pair. - -- The value of ``this_case_eq_lvalue`` is appended to - ``subst_rvalue_from`` and the value of ``this_case_eq_ltemp`` is - appended to ``subst_rvalue_to``. - -- Map the signals in ``this_case_eq_lvalue`` using - ``subst_lvalue_from``/``subst_lvalue_to``. - -- Remove all assignments to signals in ``this_case_eq_lvalue`` in - ``current_case`` and all cases within it. - -- Add an assignment from ``this_case_eq_ltemp`` to - ``this_case_eq_lvalue`` to ``current_case``. - -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 $0-prefix) and this variable is used for all -assignments of the variable. - -Note how all the ``_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 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 ``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 -``AST::AstNode::genRTLIL()`` with a -``subst_rvalue_from``/``subst_rvalue_to``-tuple that contained the -right-hand-side of the old assignment. - -The proc pass -~~~~~~~~~~~~~ - -The ProcessGenerator converts a behavioural model in AST representation -to a behavioural model in ``RTLIL::Process`` representation. The actual -conversion from a behavioural model to an RTL representation is -performed by the proc pass and the passes it launches: - -- | proc_clean and proc_rmdead - | These two passes just clean up the ``RTLIL::Process`` structure. - The proc_clean pass removes empty parts (eg. empty assignments) - from the process and proc_rmdead detects and removes unreachable - branches from the process's decision trees. - -- | 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 for the reset path. - After this pass the sync rule for the reset is level-sensitive and - the top-level has been removed. - -- | proc_mux - | This pass converts the /-tree to a tree of multiplexers per written - signal. After this, the structure only contains the s that describe - the output registers. - -- | proc_dff - | This pass replaces the s to d-type flip-flops (with asynchronous - resets if necessary). - -- | proc_dff - | This pass replaces the s with $memwr cells. - -- | proc_clean - | A final call to proc_clean removes the now empty objects. - -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. - -Synthesizing Verilog arrays ---------------------------- - -Add some information on the generation of $memrd and $memwr cells and -how they are processed in the memory pass. - -Synthesizing parametric designs -------------------------------- - -Add some information on the ``RTLIL::Module::derive()`` method and how -it is used to synthesize parametric modules via the hierarchy pass. diff --git a/yosys/docs/source/appendix/APPNOTE_010_Verilog_to_BLIF.rst b/yosys/docs/source/appendix/APPNOTE_010_Verilog_to_BLIF.rst deleted file mode 100644 index a48401dcc18..00000000000 --- a/yosys/docs/source/appendix/APPNOTE_010_Verilog_to_BLIF.rst +++ /dev/null @@ -1,336 +0,0 @@ -==================================== -010: Converting Verilog to BLIF page -==================================== - -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 TCL, Qt and MiniSAT support in the -Makefile and may opt against building yosys-abc. - -This Application Note is based on `Yosys GIT`_ `Rev. e216e0e`_ from 2013-11-23. -The Verilog sources used for the examples are taken from `yosys-bigsim`_, a -collection of real-world designs used for regression testing Yosys. - -.. _Yosys GIT: https://github.com/YosysHQ/yosys - -.. _Rev. e216e0e: https://github.com/YosysHQ/yosys/tree/e216e0e - -.. _yosys-bigsim: https://github.com/YosysHQ/yosys-bigsim - -Getting started -=============== - -We start our tour with the Navré processor from yosys-bigsim. The `Navré -processor`_ is an Open Source AVR clone. It is a single module (softusb_navre) -in a single design file (softusb_navre.v). It also is using only features that -map nicely to the BLIF format, for example it only uses synchronous resets. - -.. _Navré processor: http://opencores.org/projects/navre - -Converting softusb_navre.v to softusb_navre.blif could not be easier: - -.. code:: sh - - yosys -o softusb_navre.blif -S softusb_navre.v - -Behind the scenes Yosys is controlled by synthesis scripts that execute -commands that operate on Yosys' internal state. For example, the -o -softusb_navre.blif option just adds the command write_blif -softusb_navre.blif to the end of the script. Likewise a file on the -command line – softusb_navre.v in this case – adds the command -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 -S instantiates a built-in default synthesis script. -Instead of using -S one could also specify the synthesis commands for -the script on the command line using the -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. - -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: - -.. code:: yoscrypt - - read_verilog softusb_navre.v - hierarchy - proc; opt; memory; opt; techmap; opt - write_blif softusb_navre.blif - -The first and last line obviously read the Verilog file and write the -BLIF file. - -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. - -The 3rd line does most of the actual work: - -- The command 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 clean instead of opt. - -- The command proc converts processes (Yosys' internal representation - of Verilog always- and initial-blocks) to circuits of multiplexers - and storage elements (various types of flip-flops). - -- The command 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 - -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. - -- The command 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. - -Now Yosys can be run with the filename of the synthesis script as -argument: - -.. code:: sh - - yosys softusb_navre.ys - -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 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 -hierarchy command should be called with the -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 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. - -For many designs it is also desired to optimize the encodings for the -finite state machines (FSMs) in the design. The 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 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. - -So now we have the final synthesis script for generating a BLIF file for -the Navré CPU: - -.. code:: yoscrypt - - read_verilog softusb_navre.v - hierarchy -check -top softusb_navre - proc; opt; memory; opt; fsm; opt; techmap; opt - write_blif softusb_navre.blif - -Advanced example: The Amber23 ARMv2a CPU -======================================== - -Our 2nd example is the `Amber23 ARMv2a CPU`_. Once again we base our example on -the Verilog code that is included in `yosys-bigsim`_. - -.. _Amber23 ARMv2a CPU: http://opencores.org/projects/amber - -.. code-block:: yoscrypt - :caption: `amber23.ys` - :name: amber23.ys - - 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 - -The problem with this core is that it contains no dedicated reset logic. Instead -the coding techniques shown in :numref:`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.) - -:numref:`amber23.ys` shows the synthesis script for the Amber23 core. In line 17 -the add command is used to add a 1-bit wide global input signal with the name -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. - -.. code-block:: verilog - :caption: Implicit coding of global asynchronous resets - :name: glob_arst - - reg [7:0] a = 13, b; - initial b = 37; - -.. code-block:: verilog - :caption: `adff2dff.v` - :name: adff2dff.v - - (* 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 - -In line 18 the proc command is called. But in this script the signal -name 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 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 :numref:`adff2dff.v`. Note how the -techmap_celltype attribute is used in line 1 to tell the techmap command which -cells to replace in the design, how the \_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 \_TECHMAP_DO\_ wire in -line 13 provides a mini synthesis-script to be used to process this cell. - -.. code-block:: c - :caption: Test program for the Amber23 CPU (Sieve of Eratosthenes). Compiled - using GCC 4.6.3 for ARM with ``-Os -marm -march=armv2a - -mno-thumb-interwork -ffreestanding``, linked with ``--fix-v4bx`` - set and booted with a custom setup routine written in ARM assembler. - :name: sieve - - #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; - } - -Verification of the Amber23 CPU -=============================== - -The BLIF file for the Amber23 core, generated using :numref:`amber23.ys` and -:numref:`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 :numref:`sieve` in the test-bench. - -For simulation the BLIF file was converted back to Verilog using `ABC`_. So this -test includes the successful transformation of the BLIF file into ABC's internal -format as well. - -.. _ABC: https://github.com/berkeley-abc/abc - -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. - -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 $readmemb and $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. - -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 -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. diff --git a/yosys/docs/source/appendix/APPNOTE_011_Design_Investigation.rst b/yosys/docs/source/appendix/APPNOTE_011_Design_Investigation.rst deleted file mode 100644 index 44819e28332..00000000000 --- a/yosys/docs/source/appendix/APPNOTE_011_Design_Investigation.rst +++ /dev/null @@ -1,965 +0,0 @@ -========================================== -011: Interactive design investigation page -========================================== - -Installation and prerequisites -============================== - -This Application Note is based on the `Yosys GIT`_ `Rev. 2b90ba1`_ from -2013-12-08. The README file covers how to install Yosys. The ``show`` command -requires a working installation of `GraphViz`_ and `xdot` for generating the -actual circuit diagrams. - -.. _Yosys GIT: https://github.com/YosysHQ/yosys - -.. _Rev. 2b90ba1: https://github.com/YosysHQ/yosys/tree/2b90ba1 - -.. _GraphViz: http://www.graphviz.org/ - -.. _xdot: https://github.com/jrfonseca/xdot.py - -Overview -======== - -This application note is structured as follows: - -:ref:`intro_show` introduces the ``show`` command and explains the symbols used -in the circuit diagrams generated by it. - -: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. - -:ref:`poke` introduces commands to evaluate the design and solve SAT problems -within the design. - -:ref:`conclusion` concludes the document and summarizes the key points. - -.. _intro_show: - -Introduction to the show command -================================ - -.. code-block:: console - :caption: Yosys script with ``show`` commands and example design - :name: example_src - - $ 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 - -.. figure:: ../../images/011/example_out.* - :class: width-helper - :name: example_out - - Output of the three ``show`` commands from :numref:`example_src` - -The ``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 ``xdot`` to display the diagram. Subsequent calls to show re-use the -``xdot`` instance (if still running). - -A simple circuit ----------------- - -:numref:`example_src` shows a simple synthesis script and a Verilog file that -demonstrate the usage of show in a simple setting. Note that ``show`` is called with -the ``-pause`` option, that halts execution of the Yosys script until the user -presses the Enter key. The ``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 -:numref:`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 -``'`` is used for for constants that are not 32-bit wide and/or -contain bits that are not 0 or 1 (i.e. ``x`` or ``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 *processes* are shown in boxes with round corners. Processes are Yosys' -internal representation of the decision-trees and synchronization events -modelled in a Verilog ``always``-block. The label reads ``PROC`` followed by a -unique identifier in the first line and contains the source code location of the -original ``always``-block in the 2nd line. Note how the multiplexer from the -``?:``-expression is represented as a ``$mux`` cell but the multiplexer from the -``if``-statement is yet still hidden within the process. - -The ``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 -``BUF``-node. This are artefacts left behind by the ``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 -``clean`` (or ``opt``, which includes ``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 ``;;`` 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 ``clean`` before -calling ``show``. - -In this script we directly call ``opt`` as next step, which finally leads us to -the 3rd diagram in :numref:`example_out`. Here we see that the ``opt`` command -not only has removed the artifacts left behind by ``proc``, but also determined -correctly that it can remove the first ``$mux`` cell without changing the -behavior of the circuit. - -.. figure:: ../../images/011/splice.* - :class: width-helper - :name: splice_dia - - Output of ``yosys -p 'proc; opt; show' splice.v`` - -.. literalinclude:: ../APPNOTE_011_Design_Investigation/splice.v - :caption: ``splice.v`` - :name: splice_src - -.. figure:: ../../images/011/splitnets_libfile.* - :class: width-helper - :name: splitnets_libfile - - Effects of ``splitnets`` command and of providing a cell library. (The - circuit is a half-adder built from simple CMOS gates.) - -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 :numref:`splice_src` demonstrates -how such circuits are visualized by the ``show`` command. - -The key elements in understanding this circuit diagram are of course the boxes -with round corners and rows labeled ``: - -:``. Each of this boxes has one signal per row on one side -and a common signal for all rows on the other side. The ``:`` tuples -specify which bits of the signals are broken out and connected. So the top row -of the box connecting the signals ``a`` and ``x`` indicates that the bit 0 (i.e. -the range 0:0) from signal ``a`` is connected to bit 1 (i.e. the range 1:1) of -signal ``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. - -Gate level netlists -------------------- - -Finally :numref:`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 ``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 ``show`` command using the ``-lib `` option. -Secondly it is possible to load cell libraries into the design with the -``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 ``show`` command. - -In addition to that, the 2nd diagram was generated after ``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 -``-ports`` option is required to also split module ports. Per default the -command only operates on interior signals. - -Miscellaneous notes -------------------- - -Per default the ``show`` command outputs a temporary dot file and launches -``xdot`` to display it. The options ``-format``, ``-viewer`` and ``-prefix`` can -be used to change format, viewer and filename prefix. Note that the ``pdf`` and -``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 ``show`` with -the ``-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 ``help show`` prints a complete listing of all options supported by -the ``show`` command. - -.. _navigate: - -Navigating the design -===================== - -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 *what* to display one also needs to carefully decide *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 ``techmap`` command already fails to verify, it is better to -troubleshoot the coarse-grain version of the circuit before ``techmap`` than -the gate-level circuit after ``techmap``. - -.. Note:: It is generally recommended to verify the internal state of a - design by writing it to a Verilog file using ``write_verilog -noexpr`` - and using the simulation models from ``simlib.v`` and ``simcells.v`` - from the Yosys data directory (as printed by ``yosys-config --datdir``). - -Interactive navigation ----------------------- - -.. code-block:: none - :caption: Demonstration of ``ls`` and ``cd`` using ``example.v`` from :numref:`example_src` - :name: lscd - - 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 - -.. code-block:: RTLIL - :caption: Output of ``dump \$2`` using the design from :numref:`example_src` - and :numref:`example_out` - :name: dump2 - - 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 - -Once the right state within the synthesis flow for debugging the circuit has -been identified, it is recommended to simply add the ``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 ``ls`` -can now be used to create a list of all modules. The command ``cd`` can be used -to switch to one of the modules (type ``cd ..`` to switch back). Now the `ls` -command lists the objects within that module. :numref:`lscd` demonstrates this -using the design from :numref:`example_src`. - -There is a thing to note in :numref:`lscd`: We can see that the cell names from -:numref:`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 ``cd`` -command. But it is also possible to work from the design-context (``cd ..``). In -this case all object names must be prefixed with ``/``. For example -``a*/b\*`` would refer to all objects whose names start with ``b`` from all -modules whose names start with ``a``. - -The ``dump`` command can be used to print all information about an object. For -example ``dump $2`` will print :numref:`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. - -Working with selections ------------------------ - -.. figure:: ../../images/011/example_03.* - :class: width-helper - :name: seladd - - Output of ``show`` after ``select $2`` or ``select t:$add`` (see also - :numref:`example_out`) - -When a module is selected using the ``cd`` command, all commands (with a few -exceptions, such as the ``read_`` and ``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 ``select`` command. - -For example, if the command ``select $2`` is executed, a subsequent ``show`` -command will yield the diagram shown in :numref:`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 ``select t:$add`` will select all cells of type ``$add``. In this case -this is also yields the diagram shown in :numref:`seladd`. - -.. literalinclude:: ../APPNOTE_011_Design_Investigation/foobaraddsub.v - :caption: Test module for operations on selections - :name: foobaraddsub - :language: verilog - -The output of ``help select`` contains a complete syntax reference for -matching different properties. - -Many commands can operate on explicit selections. For example the command ``dump -t:$add`` will print information on all ``$add`` cells in the active module. -Whenever a command has ``[selection]`` as last argument in its usage help, this -means that it will use the engine behind the ``select`` command to evaluate -additional arguments and use the resulting selection instead of the selection -created by the last ``select`` command. - -Normally the ``select`` command overwrites a previous selection. The commands -``select -add`` and ``select -del`` can be used to add or remove objects from -the current selection. - -The command ``select -clear`` can be used to reset the selection to the default, -which is a complete selection of everything in the current module. - -Operations on selections ------------------------- - -.. literalinclude:: ../APPNOTE_011_Design_Investigation/sumprod.v - :caption: Another test module for operations on selections - :name: sumprod - :language: verilog - -.. figure:: ../../images/011/sumprod_00.* - :class: width-helper - :name: sumprod_00 - - Output of ``show a:sumstuff`` on :numref:`sumprod` - -The ``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 ``$add`` cells and all objects with the -``foo`` attribute set: - -.. code-block:: yoscrypt - - select t:$add a:foo - -(Try this with the design shown in :numref:`foobaraddsub`. Use the ``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 ``%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 ``foo`` attribute set: - -.. code-block:: yoscrypt - - select t:$add a:foo %i - -The listing in :numref:`sumprod` uses the Yosys non-standard ``{... \*}`` syntax -to set the attribute ``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 ``a:sumstuff`` in this module will yield the circuit diagram shown in -:numref:`sumprod_00`. As only the cells themselves are selected, but not the -temporary wire ``$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 ``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 ``%x`` action, that broadens the selection, i.e. for each -selected wire it selects all cells connected to the wire and vice versa. So -``show a:sumstuff %x`` yields the diagram shown in :numref:`sumprod_01`. - -.. figure:: ../../images/011/sumprod_01.* - :class: width-helper - :name: sumprod_01 - - Output of ``show a:sumstuff %x`` on :numref:`sumprod` - -Selecting logic cones ---------------------- - -:numref:`sumprod_01` shows what is called the ``input cone`` of ``sum``, i.e. -all cells and signals that are used to generate the signal ``sum``. The ``%ci`` -action can be used to select the input cones of all object in the top selection -in the stack maintained by the ``select`` command. - -As the ``%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. - -:numref:`select_prod` show the sequence of diagrams generated by the following -commands: - -.. code-block:: yoscrypt - - show prod - show prod %ci - show prod %ci %ci - show prod %ci %ci %ci - -When selecting many levels of logic, repeating ``%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 ``%ci3`` is identical to -performing the ``%ci`` action three times. - -The action ``%ci\*`` performs the ``%ci`` action over and over again until it -has no effect anymore. - -.. figure:: ../../images/011/select_prod.* - :class: width-helper - :name: select_prod - - Objects selected by ``select prod \%ci...`` - -In most cases there are certain cell types and/or ports that should not be -considered for the ``%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 ``%ci`` action. - -Lets consider the design from :numref:`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 ``proc; opt; memory; opt`` and change -to the ``memdemo`` module with ``cd memdemo``. If we type ``show`` now we see -the diagram shown in :numref:`memdemo_00`. - -.. literalinclude:: ../APPNOTE_011_Design_Investigation/memdemo.v - :caption: Demo circuit for demonstrating some advanced Yosys features - :name: memdemo_src - :language: verilog - -.. figure:: ../../images/011/memdemo_00.* - :class: width-helper - :name: memdemo_00 - - Complete circuit diagram for the design shown in :numref:`memdemo_src` - -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: - -.. code-block:: yoscrypt - - show y %ci2 - -From this we would learn that ``y`` is driven by a ``$dff cell``, that ``y`` is -connected to the output port ``Q``, that the ``clk`` signal goes into the -``CLK`` input port of the cell, and that the data comes from a auto-generated -wire into the input ``D`` of the flip-flop cell. - -As we are not interested in the clock signal we add an additional pattern to the -``%ci`` action, that tells it to only follow ports ``Q`` and ``D`` of ``$dff`` -cells: - -.. code-block:: yoscrypt - - show y %ci2:+$dff[Q,D] - -To add a pattern we add a colon followed by the pattern to the ``%ci`` action. -The pattern it self starts with ``-`` or ``+``, 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 ``$dff`` cell, -we could as well only specify the port names: - -.. code-block:: yoscrypt - - show y %ci2:+[Q,D] - -Or we could decide to tell the ``%ci`` action to not follow the ``CLK`` input: - -.. code-block:: yoscrypt - - show y %ci2:-[CLK] - -.. figure:: ../../images/011/memdemo_01.* - :class: width-helper - :name: memdemo_01 - - Output of ``show y \%ci2:+\$dff[Q,D] \%ci*:-\$mux[S]:-\$dff`` - -Next we would investigate the next logic level by adding another ``%ci2`` to -the command: - -.. code-block:: yoscrypt - - show y %ci2:-[CLK] %ci2 - -From this we would learn that the next cell is a ``$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 - -.. code-block:: yoscrypt - - show y %ci2:+$dff[Q,D] %ci*:-$mux[S]:-$dff - -in which the first ``%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 -:numref:`memdemo_01`. - -Similar to ``%ci`` exists an action ``%co`` to select output cones that accepts -the same syntax for pattern and repetition. The ``%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 (``%i``) and difference (``%d``) are -powerful tools for extracting the relevant portions of the circuit under -investigation. - -See ``help select`` for a complete list of actions available in selections. - -Storing and recalling selections --------------------------------- - -The current selection can be stored in memory with the command ``select -set -``. It can later be recalled using ``select @``. In fact, the -``@`` expression pushes the stored selection on the stack maintained by -the ``select`` command. So for example - -.. code-block:: yoscrypt - - select @foo @bar %i - -will select the intersection between the stored selections ``foo`` and ``bar``. - -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 ``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. - -.. _poke: - -Advanced investigation techniques -================================= - -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. - -:numref:`submod` shows how the ``submod`` command can be used to split the -circuit from :numref:`memdemo_src` and :numref:`memdemo_00` into its components. -The ``-name`` option is used to specify the name of the new module and also the -name of the new cell in the current module. - -.. figure:: ../../images/011/submod_dots.* - :class: width-helper - :name: submod_dots - -.. code-block:: yoscrypt - :caption: The circuit from :numref:`memdemo_src` and :numref:`memdemo_00` - broken up using ``submod`` - :name: submod - - 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 - -Evaluation of combinatorial circuits ------------------------------------- - -The ``eval`` command can be used to evaluate combinatorial circuits. For example -(see :numref:`submod` for the circuit diagram of ``selstage``): - -:: - - yosys [selstage]> eval -set s2,s1 4'b1001 -set d 4'hc -show n2 -show n1 - - 1. 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. - -So the ``-set`` option is used to set input values and the ``-show`` option is -used to specify the nets to evaluate. If no ``-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 -``-set-undef`` can be used to instead set all unspecified input nets to undef -(``x``). - -The ``-table`` option can be used to create a truth table. For example: - -:: - - 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 - -Note that the ``eval`` command (as well as the ``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 ``flatten`` -command must be used on modules that instantiate other modules before this -commands can be applied. - -Solving combinatorial SAT problems ----------------------------------- - -.. literalinclude:: ../APPNOTE_011_Design_Investigation/primetest.v - :language: verilog - :caption: A simple miter circuit for testing if a number is prime. But it has - a problem (see main text and :numref:`primesat`). - :name: primetest - -.. code-block:: - :caption: Experiments with the miter circuit from :numref:`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. - :name: primesat - - 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! - - /$$$$$$ /$$$$$$$$ /$$$$$$$ - /$$__ $$ | $$_____/ | $$__ $$ - | $$ \ $$ | $$ | $$ \ $$ - | $$ | $$ | $$$$$ | $$ | $$ - | $$ | $$ | $$__/ | $$ | $$ - | $$/$$ $$ | $$ | $$ | $$ - | $$$$$$/ /$$| $$$$$$$$ /$$| $$$$$$$//$$ - \____ $$$|__/|________/|__/|_______/|__/ - \__/ - -Often the opposite of the ``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 ``eval -table`` command. For larger circuits -however, Yosys provides the ``sat`` command that uses a `SAT`_ solver, -`MiniSAT`_, to solve this kind of problems. - -.. _SAT: http://en.wikipedia.org/wiki/Circuit_satisfiability - -.. _MiniSAT: http://minisat.se/ - -The ``sat`` command works very similar to the ``eval`` command. The main -difference is that it is now also possible to set output values and find the -corresponding input values. For Example: - -:: - - 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 - -Note that the ``sat`` command supports signal names in both arguments to the -``-set`` option. In the above example we used ``-set s1 s2`` to constraint -``s1`` and ``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 ``-set`` option. (Such a circuit that contains the circuit under -test plus additional constraint checking circuitry is called a ``miter`` -circuit.) - -:numref:`primetest` shows a miter circuit that is supposed to be used as a prime -number test. If ``ok`` is 1 for all input values ``a`` and ``b`` for a given -``p``, then ``p`` is prime, or at least that is the idea. - -The Yosys shell session shown in :numref:`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 ``p != -a*b`` in the miter with ``p != {16'd0,a}b``, or by using a temporary variable -for the 32 bit product ``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 ``a`` and ``b`` to zero for the ``sat`` call, as is done in -the second command in :numref:`primesat` (line 31). - -The ``-prove`` option used in this example works similar to ``-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. - -Solving sequential SAT problems -------------------------------- - -.. code-block:: - :caption: Solving a sequential SAT problem in the ``memdemo`` module from :numref:`memdemo_src`. - :name: memdemo_sat - - 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 - -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 memdemo module from :numref:`memdemo_src` and suppose we want to know -which sequence of input values for ``d`` will cause the output y to produce the -sequence 1, 2, 3 from any initial state. :numref:`memdemo_sat` show the solution -to this question, as produced by the following command: - -.. code-block:: yoscrypt - - 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 - -The ``-seq 6`` option instructs the ``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 ``-set-init-undef`` option tells the ``sat`` command to initialize all -registers to the undef (``x``) state. The way the ``x`` state is treated in -Verilog will ensure that the solution will work for any initial state. - -The ``-max_undef`` option instructs the ``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 ``-set-at`` options add constraints for the ``y`` signal to -play the 1, 2, 3 sequence, starting with time step 4. - -It is not surprising that the solution sets ``d = 0`` in the first step, as this -is the only way of setting the ``s1`` and ``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. - -There is much more to write about the ``sat`` command. For example, there is a -set of options that can be used to performs sequential proofs using temporal -induction :cite:p:`een2003temporal`. The command ``help sat`` can be used to -print a list of all options with short descriptions of their functions. - -.. _conclusion: - -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 (``eval``) or by evaluation which input values and initial conditions -can result in a certain behavior at the outputs (``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. diff --git a/yosys/docs/source/appendix/APPNOTE_012_Verilog_to_BTOR.rst b/yosys/docs/source/appendix/APPNOTE_012_Verilog_to_BTOR.rst deleted file mode 100644 index e9e44d1cd11..00000000000 --- a/yosys/docs/source/appendix/APPNOTE_012_Verilog_to_BTOR.rst +++ /dev/null @@ -1,333 +0,0 @@ -==================================== -012: Converting Verilog to BTOR page -==================================== - -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 TCL and ABC support in the -Makefile. - -This Application Note is based on `Yosys GIT`_ `Rev. 082550f` from 2015-04-04. - -.. _Yosys GIT: https://github.com/YosysHQ/yosys - -.. _Rev. 082550f: https://github.com/YosysHQ/yosys/tree/082550f - -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:p:`btor`. - -We provide a shell script ``verilog2btor.sh`` which can be used to convert a -Verilog design to BTOR. The script can be found in the ``backends/btor`` -directory. The following example shows its usage: - -.. code:: sh - - verilog2btor.sh fsm.v fsm.btor test - -The script ``verilog2btor.sh`` takes three parameters. In the above example, the -first parameter ``fsm.v`` is the input design, the second parameter ``fsm.btor`` -is the file name of BTOR output, and the third parameter ``test`` is the name of -top module in the design. - -To specify the properties (that need to be checked), we have two -options: - -- We can use the Verilog ``assert`` statement in the procedural block or module - body of the Verilog design, as shown in :numref:`specifying_property_assert`. - This is the preferred option. - -- We can use a single-bit output wire, whose name starts with ``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 :numref:`specifying_property_output`. - -.. code-block:: verilog - :caption: Specifying property in Verilog design with ``assert`` - :name: specifying_property_assert - - 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 - -.. code-block:: verilog - :caption: Specifying property in Verilog design with output wire - :name: specifying_property_output - - 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 - -We can run `Boolector`_ ``1.4.1`` [1]_ on the generated BTOR file: - -.. _Boolector: http://fmv.jku.at/boolector/ - -.. code:: sh - - $ boolector fsm.btor - unsat - -We can also use `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. - -.. _nuXmv: https://es-static.fbk.eu/tools/nuxmv/index.php - -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 ``verilog2btor.sh`` script. :numref:`btor_script_memory` shows -the Yosys commands that are executed by ``verilog2btor.sh``. - -.. code-block:: yoscrypt - :caption: Synthesis Flow for BTOR with memories - :name: btor_script_memory - - 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; - -Here is short description of what is happening in the script line by -line: - -#. Reading the input file. - -#. Setting the top module in the hierarchy and trying to read automatically the - files which are given as ``include`` in the file read in first line. - -#. Checking the design hierarchy. - -#. Converting processes to multiplexers (muxs) and flip-flops. - -#. Removing undef signals from muxs. - -#. Hiding all signal names that are not used as module ports. - -#. Explicit type conversion, by introducing slice and concat cells in the - circuit. - -#. Converting write memories to synchronous memories, and collecting the - memories to multi-port memories. - -#. Flattening the design to get only one module. - -#. Separating read and write memories. - -#. Splitting the signals that are partially assigned - -#. Setting undef to zero value. - -#. Final optimization pass. - -#. Writing BTOR file. - -For detailed description of the commands mentioned above, please refer -to the Yosys documentation, or run ``yosys -h ``. - -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 ``memory`` at line number 8. -:numref:`btor_script_without_memory` shows the modified Yosys script file: - -.. code-block:: sh - :caption: Synthesis Flow for BTOR without memories - :name: btor_script_without_memory - - 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; - -Example -======= - -Here is an example Verilog design that we want to convert to BTOR: - -.. code-block:: verilog - :caption: Example - Verilog Design - :name: example_verilog - - 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 - -The generated BTOR file that contain memories, using the script shown in -:numref:`btor_memory`: - -.. code-block:: - :caption: Example - Converted BTOR with memory - :name: btor_memory - - 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 - -And the BTOR file obtained by the script shown in -:numref:`btor_without_memory`, which expands the memory into individual -elements: - -.. code-block:: - :caption: Example - Converted BTOR with memory - :name: btor_without_memory - - 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 - - ... - - 54 cond 1 53 50 52 - 55 root 1 -54 - - ... - - 77 cond 8 76 3 44 - 78 cond 8 1 77 44 - 79 next 8 44 78 - -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 ``x`` or ``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. - -Conclusion -========== - -Using the described flow, we can use Yosys to generate word-level verification -benchmarks with or without memories from Verilog designs. - -.. [1] - 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. diff --git a/yosys/docs/source/appendix/CHAPTER_Auxlibs.rst b/yosys/docs/source/appendix/CHAPTER_Auxlibs.rst deleted file mode 100644 index 361f00e025b..00000000000 --- a/yosys/docs/source/appendix/CHAPTER_Auxlibs.rst +++ /dev/null @@ -1,42 +0,0 @@ -Auxiliary libraries -=================== - -The Yosys source distribution contains some auxiliary libraries that are bundled -with Yosys. - -SHA1 ----- - -The files in ``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. - -BigInt ------- - -The files in ``libs/bigint/`` provide a library for performing arithmetic with -arbitrary length integers. It is written by Matt McCutchen. - -The BigInt library is used for evaluating constant expressions, e.g. using the -ConstEval class provided in kernel/consteval.h. - -See also: http://mattmccutchen.net/bigint/ - -.. _sec:SubCircuit: - -SubCircuit ----------- - -The files in ``libs/subcircuit`` provide a library for solving the subcircuit -isomorphism problem. It is written by C. Wolf and based on the Ullmann Subgraph -Isomorphism Algorithm :cite:p:`UllmannSubgraphIsomorphism`. It is used by the -extract pass (see :doc:`../cmd/extract`). - -ezSAT ------ - -The files in ``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 C. Wolf. It is used by the sat pass (see -:doc:`../cmd/sat`). - diff --git a/yosys/docs/source/appendix/CHAPTER_Auxprogs.rst b/yosys/docs/source/appendix/CHAPTER_Auxprogs.rst deleted file mode 100644 index e4f6f62cfb6..00000000000 --- a/yosys/docs/source/appendix/CHAPTER_Auxprogs.rst +++ /dev/null @@ -1,29 +0,0 @@ -Auxiliary programs -================== - -Besides the main yosys executable, the Yosys distribution contains a set of -additional helper programs. - -yosys-config ------------- - -The 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. See Sec. \ :numref:`chapter:prog` for details. - -.. _sec:filterlib: - -yosys-filterlib ---------------- - -The yosys-filterlib tool is a small utility that can be used to strip or extract -information from a Liberty file. See :numref:`Sec. %s ` for -details. - -yosys-abc ---------- - -This is a fork of ABC with a small set of custom modifications that have not yet -been accepted upstream. 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/docs/source/appendix/CHAPTER_StateOfTheArt.rst b/yosys/docs/source/appendix/CHAPTER_StateOfTheArt.rst deleted file mode 100644 index 894d0fbbe2b..00000000000 --- a/yosys/docs/source/appendix/CHAPTER_StateOfTheArt.rst +++ /dev/null @@ -1,410 +0,0 @@ -.. _chapter:sota: - -Evaluation of other OSS Verilog Synthesis Tools -=============================================== - -In this appendix [1]_ the existing FOSS Verilog synthesis tools [2]_ 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: - -- Icarus Verilog [3]_ - -- Verilog-to-Routing (VTR) / Odin-II - :cite:p:`vtr2012}`:raw-latex:`\cite{Odin` - -- HDL Analyzer and Netlist Architect (HANA) - -- Verilog front-end to VIS (vl2mv) :cite:p:`Cheng93vl2mv:a` - -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 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 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. - -.. code:: verilog - :number-lines: - - 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 - -.. code:: verilog - - 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 - -[fig:StateOfTheArt_always12] - -.. code:: verilog - :number-lines: - - 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 - -[fig:StateOfTheArt_always3] - -.. _sec:blocking_nonblocking: - -Always blocks and blocking vs. nonblocking assignments ------------------------------------------------------- - -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 (:math:`=`) and nonblocking -assignments (:math:`<=`) 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 (:math:`<=`) 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 -:numref:`Fig. %s ` -and :numref:`Fig. %s ` -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. - -.. code:: verilog - :number-lines: - - 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 - -[fig:StateOfTheArt_arrays] - -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: - -:: - - ERROR: (File: always02.v) (Line number: 13) - You've defined the driver "count~0" twice - -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: - -:: - - ERROR: (File: always03.v) (Line number: 8) - ODIN doesn't handle blocking statements in Sequential blocks - -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. - -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 -:numref:`Fig. %s ` -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. - -.. code:: verilog - :number-lines: - - 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 - -[fig:StateOfTheArt_for] - -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. - -.. code:: verilog - :number-lines: - - 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 - -[fig:StateOfTheArt_gen] - -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 -:numref:`Fig. %s ` 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 -:numref:`Fig. %s ` 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. - -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. - -Summary and Outlook -------------------- - -Table \ :numref:`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 \ :numref:`` 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. - -…passed 2em …produced error 2em :math:`\skull` …incorrect output - -[tab:StateOfTheArt_sum] - -.. [1] - This appendix is an updated version of an unpublished student - research paper. :cite:p:`VerilogFossEval` - -.. [2] - 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. - -.. [3] - 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.) diff --git a/yosys/docs/source/appendix/CHAPTER_TextRtlil.rst b/yosys/docs/source/appendix/CHAPTER_TextRtlil.rst deleted file mode 100644 index dc3d72230b9..00000000000 --- a/yosys/docs/source/appendix/CHAPTER_TextRtlil.rst +++ /dev/null @@ -1,298 +0,0 @@ -.. _chapter:textrtlil: - -RTLIL text representation -========================= - -This appendix documents the text representation of RTLIL in extended Backus-Naur -form (EBNF). - -The grammar is not meant to represent semantic limitations. That is, the grammar -is "permissive", and later stages of processing perform more rigorous checks. - -The grammar is also not meant to represent the exact grammar used in the RTLIL -frontend, since that grammar is specific to processing by lex and yacc, is even -more permissive, and is somewhat less understandable than simple EBNF notation. - -Finally, note that all statements (rules ending in ``-stmt``) terminate in an -end-of-line. Because of this, a statement cannot be broken into multiple lines. - -Lexical elements ----------------- - -Characters -~~~~~~~~~~ - -An RTLIL file is a stream of bytes. Strictly speaking, a "character" in an RTLIL -file is a single byte. The lexer treats multi-byte encoded characters as -consecutive single-byte characters. While other encodings *may* work, UTF-8 is -known to be safe to use. Byte order marks at the beginning of the file will -cause an error. - -ASCII spaces (32) and tabs (9) separate lexer tokens. - -A ``nonws`` character, used in identifiers, is any character whose encoding -consists solely of bytes above ASCII space (32). - -An ``eol`` is one or more consecutive ASCII newlines (10) and carriage returns -(13). - -Identifiers -~~~~~~~~~~~ - -There are two types of identifiers in RTLIL: - -- Publically visible identifiers -- Auto-generated identifiers - -.. code:: BNF - - ::= | - ::= \ + - ::= $ + - -Values -~~~~~~ - -A *value* consists of a width in bits and a bit representation, most -significant bit first. Bits may be any of: - -- ``0``: A logic zero value -- ``1``: A logic one value -- ``x``: An unknown logic value (or don't care in case patterns) -- ``z``: A high-impedance value (or don't care in case patterns) -- ``m``: A marked bit (internal use only) -- ``-``: A don't care value - -An *integer* is simply a signed integer value in decimal format. **Warning:** -Integer constants are limited to 32 bits. That is, they may only be in the range -:math:`[-2147483648, 2147483648)`. Integers outside this range will result in an -error. - -.. code:: BNF - - ::= + ' * - ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 - ::= 0 | 1 | x | z | m | - - ::= -? + - -Strings -~~~~~~~ - -A string is a series of characters delimited by double-quote characters. Within -a string, any character except ASCII NUL (0) may be used. In addition, certain -escapes can be used: - -- ``\n``: A newline -- ``\t``: A tab -- ``\ooo``: A character specified as a one, two, or three digit octal value - -All other characters may be escaped by a backslash, and become the following -character. Thus: - -- ``\\``: A backslash -- ``\"``: A double-quote -- ``\r``: An 'r' character - -Comments -~~~~~~~~ - -A comment starts with a ``#`` character and proceeds to the end of the line. All -comments are ignored. - -File ----- - -A file consists of an optional autoindex statement followed by zero or more -modules. - -.. code:: BNF - - ::= ? * - -Autoindex statements -~~~~~~~~~~~~~~~~~~~~ - -The autoindex statement sets the global autoindex value used by Yosys when it -needs to generate a unique name, e.g. ``flattenN``. The N part is filled with -the value of the global autoindex value, which is subsequently incremented. This -global has to be dumped into RTLIL, otherwise e.g. dumping and running a pass -would have different properties than just running a pass on a warm design. - -.. code:: BNF - - ::= autoidx - -Modules -~~~~~~~ - -Declares a module, with zero or more attributes, consisting of zero or more -wires, memories, cells, processes, and connections. - -.. code:: BNF - - ::= * - ::= module - ::= ( - | - | - | - | )* - ::= parameter ? - ::= | | - ::= end - -Attribute statements -~~~~~~~~~~~~~~~~~~~~ - -Declares an attribute with the given identifier and value. - -.. code:: BNF - - ::= attribute - -Signal specifications -~~~~~~~~~~~~~~~~~~~~~ - -A signal is anything that can be applied to a cell port, i.e. a constant value, -all bits or a selection of bits from a wire, or concatenations of those. - -**Warning:** When an integer constant is a sigspec, it is always 32 bits wide, -2's complement. For example, a constant of :math:`-1` is the same as -``32'11111111111111111111111111111111``, while a constant of :math:`1` is the -same as ``32'1``. - -See :numref:`Sec. %s ` for an overview of signal -specifications. - -.. code:: BNF - - ::= - | - | [ (:)? ] - | { * } - -Connections -~~~~~~~~~~~ - -Declares a connection between the given signals. - -.. code:: BNF - - ::= connect - -Wires -~~~~~ - -Declares a wire, with zero or more attributes, with the given identifier and -options in the enclosing module. - -See :numref:`Sec. %s ` for an overview of wires. - -.. code:: BNF - - ::= * - ::= wire * - ::= - ::= width - | offset - | input - | output - | inout - | upto - | signed - -Memories -~~~~~~~~ - -Declares a memory, with zero or more attributes, with the given identifier and -options in the enclosing module. - -See :numref:`Sec. %s ` for an overview of memory cells, and -:numref:`Sec. %s ` for details about memory cell types. - -.. code:: BNF - - ::= * - ::= memory * - ::= width - | size - | offset - -Cells -~~~~~ - -Declares a cell, with zero or more attributes, with the given identifier and -type in the enclosing module. - -Cells perform functions on input signals. See :numref:`Chap. %s -` for a detailed list of cell types. - -.. code:: BNF - - ::= * * - ::= cell - ::= - ::= - ::= parameter (signed | real)? - | connect - ::= end - - -Processes -~~~~~~~~~ - -Declares a process, with zero or more attributes, with the given identifier in -the enclosing module. The body of a process consists of zero or more -assignments, exactly one switch, and zero or more syncs. - -See :numref:`Sec. %s ` for an overview of processes. - -.. code:: BNF - - ::= * - ::= process - ::= * ? * * - ::= assign - ::= - ::= - ::= end - -Switches -~~~~~~~~ - -Switches test a signal for equality against a list of cases. Each case specifies -a comma-separated list of signals to check against. If there are no signals in -the list, then the case is the default case. The body of a case consists of zero -or more switches and assignments. Both switches and cases may have zero or more -attributes. - -.. code:: BNF - - ::= * - := * switch - ::= * - ::= case ? - ::= (, )* - ::= ( | )* - ::= end - -Syncs -~~~~~ - -Syncs update signals with other signals when an event happens. Such an event may -be: - -- An edge or level on a signal -- Global clock ticks -- Initialization -- Always - -.. code:: BNF - - ::= * - ::= sync - | sync global - | sync init - | sync always - ::= low | high | posedge | negedge | edge - ::= update diff --git a/yosys/docs/source/bib.rst b/yosys/docs/source/bib.rst deleted file mode 100644 index 21f85a869e2..00000000000 --- a/yosys/docs/source/bib.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. only:: html - - Literature references - ===================== - - .. rubric:: Bibliography - -.. bibliography:: literature.bib - diff --git a/yosys/docs/source/cmd_ref.rst b/yosys/docs/source/cmd_ref.rst deleted file mode 100644 index 4b9dc91f3e1..00000000000 --- a/yosys/docs/source/cmd_ref.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _cmd_ref: - -================================================================================ -Command line reference -================================================================================ -.. toctree:: - :caption: Command reference - :maxdepth: 1 - :glob: - - cmd/* diff --git a/yosys/docs/source/conf.py b/yosys/docs/source/conf.py deleted file mode 100644 index ab9618c8b47..00000000000 --- a/yosys/docs/source/conf.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 -import sys -import os - -project = 'YosysHQ Yosys' -author = 'YosysHQ GmbH' -copyright ='2022 YosysHQ GmbH' - -# select HTML theme -html_theme = 'press' -html_logo = '../static/logo.png' -html_favicon = '../static/favico.png' -html_css_files = ['yosyshq.css', 'custom.css'] -html_sidebars = {'**': ['util/searchbox.html', 'util/sidetoc.html']} - -# These folders are copied to the documentation's HTML output -html_static_path = ['../static', "../images"] - -# code blocks style -pygments_style = 'colorful' -highlight_language = 'none' - -html_theme_options = { - 'external_links' : [ - ('YosysHQ Docs', 'https://yosyshq.readthedocs.io'), - ('Blog', 'https://blog.yosyshq.com'), - ('Website', 'https://www.yosyshq.com'), - ], -} - -extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex'] - -# Ensure that autosectionlabel will produce unique names -autosectionlabel_prefix_document = True -autosectionlabel_maxdepth = 1 - -# assign figure numbers -numfig = True - -bibtex_bibfiles = ['literature.bib'] - -# unused docs -exclude_patterns = [ - "CHAPTER_Eval.rst", - "appendix/CHAPTER_StateOfTheArt.rst" -] - -latex_elements = { - 'preamble': r''' -\usepackage{lmodern} -\usepackage{comment} - -''' -} - -def setup(sphinx): - sys.path += [os.path.dirname(__file__) + "/../util"] - from RtlilLexer import RtlilLexer - sphinx.add_lexer("RTLIL", RtlilLexer) - - from YoscryptLexer import YoscryptLexer - sphinx.add_lexer("yoscrypt", YoscryptLexer) \ No newline at end of file diff --git a/yosys/docs/source/index.rst b/yosys/docs/source/index.rst deleted file mode 100644 index fb864307246..00000000000 --- a/yosys/docs/source/index.rst +++ /dev/null @@ -1,72 +0,0 @@ -:Abstract: - Most of today's digital design is done in HDL code (mostly Verilog or - VHDL) and with the help of HDL synthesis tools. - - In special cases such as synthesis for coarse-grain cell libraries or - when testing new synthesis algorithms it might be necessary to write a - custom HDL synthesis tool or add new features to an existing one. In - these cases the availability of a Free and Open Source (FOSS) synthesis - tool that can be used as basis for custom tools would be helpful. - - In the absence of such a tool, the Yosys Open SYnthesis Suite (Yosys) - was developed. This document covers the design and implementation of - this tool. At the moment the main focus of Yosys lies on the high-level - aspects of digital synthesis. The pre-existing FOSS logic-synthesis tool - ABC is used by Yosys to perform advanced gate-level optimizations. - - An evaluation of Yosys based on real-world designs is included. It is - shown that Yosys can be used as-is to synthesize such designs. The - results produced by Yosys in this tests where successfully verified - using formal verification and are comparable in quality to the results - produced by a commercial synthesis tool. - - This document was originally published as bachelor thesis at the Vienna - University of Technology :cite:p:`BACC`. - -================================================================================ -Yosys manual -================================================================================ - -.. toctree:: - :maxdepth: 2 - :caption: Manual - :numbered: - - CHAPTER_Intro - CHAPTER_Basics.rst - CHAPTER_Approach.rst - CHAPTER_Overview.rst - CHAPTER_CellLib.rst - CHAPTER_Prog.rst - - CHAPTER_Verilog.rst - CHAPTER_Optimize.rst - CHAPTER_Techmap.rst - CHAPTER_Eval.rst - -.. raw:: latex - - \appendix - -.. toctree:: - :maxdepth: 2 - :includehidden: - :caption: Appendix - - appendix/CHAPTER_Auxlibs.rst - appendix/CHAPTER_Auxprogs.rst - - appendix/CHAPTER_TextRtlil.rst - appendix/APPNOTE_010_Verilog_to_BLIF.rst - appendix/APPNOTE_011_Design_Investigation.rst - appendix/APPNOTE_012_Verilog_to_BTOR.rst - appendix/CHAPTER_StateOfTheArt.rst - - bib - -.. toctree:: - :maxdepth: 1 - :includehidden: - - cmd_ref - diff --git a/yosys/docs/source/literature.bib b/yosys/docs/source/literature.bib deleted file mode 100644 index 143e3aa36d9..00000000000 --- a/yosys/docs/source/literature.bib +++ /dev/null @@ -1,202 +0,0 @@ - -@inproceedings{intersynth, - title={Example-driven interconnect synthesis for heterogeneous coarse-grain reconfigurable logic}, - author={C. Wolf and Johann Glaser and Florian Schupfer and Jan Haase and Christoph Grimm}, - booktitle={FDL Proceeding of the 2012 Forum on Specification and Design Languages}, - pages={194--201}, - year={2012} -} - -@incollection{intersynthFdlBookChapter, - title={Methodology and Example-Driven Interconnect Synthesis for Designing Heterogeneous Coarse-Grain Reconfigurable Architectures}, - author={Johann Glaser and C. Wolf}, - booktitle={Advances in Models, Methods, and Tools for Complex Chip Design --- Selected contributions from FDL'12}, - editor={Jan Haase}, - publisher={Springer}, - year={2013}, - note={to appear} -} - -@unpublished{BACC, - author = {C. Wolf}, - title = {Design and Implementation of the Yosys Open SYnthesis Suite}, - note = {Bachelor Thesis, Vienna University of Technology}, - year = {2013} -} - -@unpublished{VerilogFossEval, - author = {C. Wolf}, - title = {Evaluation of Open Source Verilog Synthesis Tools for Feature-Completeness and Extensibility}, - note = {Unpublished Student Research Paper, Vienna University of Technology}, - year = {2012} -} - -@article{ABEL, - title={A High-Level Design Language for Programmable Logic Devices}, - author={Kyu Y. Lee and Michael Holley and Mary Bailey and Walter Bright}, - journal={VLSI Design (Manhasset NY: CPM Publications)}, - year={June 1985}, - pages={50-62} -} - -@MISC{Cheng93vl2mv:a, - author = {S-T Cheng and G York and R K Brayton}, - title = {VL2MV: A Compiler from Verilog to BLIF-MV}, - year = {1993} -} - -@MISC{Odin, - author = {Peter Jamieson and Jonathan Rose}, - title = {A VERILOG RTL SYNTHESIS TOOL FOR HETEROGENEOUS FPGAS}, - year = {2005} -} - -@inproceedings{vtr2012, - title={The VTR Project: Architecture and CAD for FPGAs from Verilog to Routing}, - author={Jonathan Rose and Jason Luu and Chi Wai Yu and Opal Densmore and Jeff Goeders and Andrew Somerville and Kenneth B. Kent and Peter Jamieson and Jason Anderson}, - booktitle={Proceedings of the 20th ACM/SIGDA International Symposium on Field-Programmable Gate Arrays}, - pages={77--86}, - year={2012}, - organization={ACM} -} - -@MISC{LogicSynthesis, - author = {G D Hachtel and F Somenzi}, - title = {Logic Synthesis and Verification Algorithms}, - year = {1996} -} - -@ARTICLE{Verilog2005, - journal={IEEE Std 1364-2005 (Revision of IEEE Std 1364-2001)}, - title={IEEE Standard for Verilog Hardware Description Language}, - author={IEEE Standards Association and others}, - year={2006}, - doi={10.1109/IEEESTD.2006.99495} -} - -@ARTICLE{VerilogSynth, - journal={IEEE Std 1364.1-2002}, - title={IEEE Standard for Verilog Register Transfer Level Synthesis}, - author={IEEE Standards Association and others}, - year={2002}, - doi={10.1109/IEEESTD.2002.94220} -} - -@ARTICLE{VHDL, - journal={IEEE Std 1076-2008 (Revision of IEEE Std 1076-2002)}, - title={IEEE Standard VHDL Language Reference Manual}, - author={IEEE Standards Association and others}, - year={2009}, - month={26}, - doi={10.1109/IEEESTD.2009.4772740} -} - -@ARTICLE{VHDLSynth, - journal={IEEE Std 1076.6-2004 (Revision of IEEE Std 1076.6-1999)}, - title={IEEE Standard for VHDL Register Transfer Level (RTL) Synthesis}, - author={IEEE Standards Association and others}, - year={2004}, - doi={10.1109/IEEESTD.2004.94802} -} - -@ARTICLE{IP-XACT, - journal={IEEE Std 1685-2009}, - title={IEEE Standard for IP-XACT, Standard Structure for Packaging, Integrating, and Reusing IP within Tools Flows}, - author={IEEE Standards Association and others}, - year={2010}, - pages={C1-360}, - keywords={abstraction definitions, address space specification, bus definitions, design environment, EDA, electronic design automation, electronic system level, ESL, implementation constraints, IP-XACT, register transfer level, RTL, SCRs, semantic consistency rules, TGI, tight generator interface, tool and data interoperability, use models, XML design meta-data, XML schema}, - doi={10.1109/IEEESTD.2010.5417309} -} - -@book{Dragonbook, - author = {Aho, Alfred V. and Sethi, Ravi and Ullman, Jeffrey D.}, - title = {Compilers: principles, techniques, and tools}, - year = {1986}, - isbn = {0-201-10088-6}, - publisher = {Addison-Wesley Longman Publishing Co., Inc.}, - address = {Boston, MA, USA} -} - -@INPROCEEDINGS{Cummings00, - author = {Clifford E. Cummings and Sunburst Design Inc}, - title = {Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill}, - booktitle = {SNUG (Synopsys Users Group) 2000 User Papers, section-MC1 (1 st paper}, - year = {2000} -} - -@ARTICLE{MURPHY, - author={D. L. Klipstein}, - journal={Cahners Publishing Co., EEE Magazine, Vol. 15, No. 8}, - title={The Contributions of Edsel Murphy to the Understanding of the Behavior of Inanimate Objects}, - year={August 1967} -} - -@INPROCEEDINGS{fsmextract, - author={Yiqiong Shi and Chan Wai Ting and Bah-Hwee Gwee and Ye Ren}, - booktitle={Circuits and Systems (ISCAS), Proceedings of 2010 IEEE International Symposium on}, - title={A highly efficient method for extracting FSMs from flattened gate-level netlist}, - year={2010}, - pages={2610-2613}, - keywords={circuit CAD;finite state machines;microcontrollers;FSM;control-intensive circuits;finite state machines;flattened gate-level netlist;state register elimination technique;Automata;Circuit synthesis;Continuous wavelet transforms;Design automation;Digital circuits;Hardware design languages;Logic;Microcontrollers;Registers;Signal processing}, - doi={10.1109/ISCAS.2010.5537093}, -} - -@ARTICLE{MultiLevelLogicSynth, - author={Brayton, R.K. and Hachtel, G.D. and Sangiovanni-Vincentelli, A.L.}, - journal={Proceedings of the IEEE}, - title={Multilevel logic synthesis}, - year={1990}, - volume={78}, - number={2}, - pages={264-300}, - keywords={circuit layout CAD;integrated logic circuits;logic CAD;capsule summaries;definitions;detailed analysis;in-depth background;logic decomposition;logic minimisation;logic synthesis;logic synthesis techniques;multilevel combinational logic;multilevel logic synthesis;notation;perspective;survey;synthesis methods;technology mapping;testing;Application specific integrated circuits;Design automation;Integrated circuit synthesis;Logic design;Logic devices;Logic testing;Network synthesis;Programmable logic arrays;Signal synthesis;Silicon}, - doi={10.1109/5.52213}, - ISSN={0018-9219}, -} - -@article{UllmannSubgraphIsomorphism, - author = {Ullmann, J. R.}, - title = {An Algorithm for Subgraph Isomorphism}, - journal = {J. ACM}, - issue_date = {Jan. 1976}, - volume = {23}, - number = {1}, - month = jan, - year = {1976}, - issn = {0004-5411}, - pages = {31--42}, - numpages = {12}, - doi = {10.1145/321921.321925}, - acmid = {321925}, - publisher = {ACM}, - address = {New York, NY, USA}, -} - -@article{een2003temporal, - title={Temporal induction by incremental SAT solving}, - author={E{\'e}n, Niklas and S{\"o}rensson, Niklas}, - journal={Electronic Notes in Theoretical Computer Science}, - volume={89}, - number={4}, - pages={543--560}, - year={2003}, - publisher={Elsevier} -} - -@inproceedings{btor, - title={BTOR: bit-precise modelling of word-level problems for model checking}, - author={Brummayer, Robert and Biere, Armin and Lonsing, Florian}, - booktitle={Proceedings of the joint workshops of the 6th international workshop on satisfiability modulo theories and 1st international workshop on bit-precise reasoning}, - pages={33--38}, - year={2008} -} - -@inproceedings{VIS, - title={VIS: A system for verification and synthesis}, - author={Brayton, Robert K and Hachtel, Gary D and Sangiovanni-Vincentelli, Alberto and Somenzi, Fabio and Aziz, Adnan and Cheng, Szu-Tsung and Edwards, Stephen and Khatri, Sunil and Kukimoto, Yuji and Pardo, Abelardo and others}, - booktitle={Proceedings of the 8th International Conference on Computer Aided Verification}, - pages={428--432}, - year={1996}, - organization={Springer} -} diff --git a/yosys/docs/source/requirements.txt b/yosys/docs/source/requirements.txt deleted file mode 100644 index d357a83b7cc..00000000000 --- a/yosys/docs/source/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -sphinx-press-theme -sphinxcontrib-bibtex diff --git a/yosys/docs/static/custom.css b/yosys/docs/static/custom.css deleted file mode 100644 index 40a8c178f10..00000000000 --- a/yosys/docs/static/custom.css +++ /dev/null @@ -1 +0,0 @@ -/* empty */ diff --git a/yosys/docs/static/favico.png b/yosys/docs/static/favico.png deleted file mode 100644 index 3f5afba7656..00000000000 Binary files a/yosys/docs/static/favico.png and /dev/null differ diff --git a/yosys/docs/static/logo.png b/yosys/docs/static/logo.png deleted file mode 100644 index 8e5a507c63c..00000000000 Binary files a/yosys/docs/static/logo.png and /dev/null differ diff --git a/yosys/docs/static/yosyshq.css b/yosys/docs/static/yosyshq.css deleted file mode 100644 index 0be7f77281d..00000000000 --- a/yosys/docs/static/yosyshq.css +++ /dev/null @@ -1,78 +0,0 @@ -h1, h3, p.topic-title, .content li.toctree-l1 > a { - color: #d6368f !important; -} - -h2, p.admonition-title, dt, .content li.toctree-l2 > a { - color: #4b72b8; -} - -a { - color: #8857a3; -} - -a.current, a:hover, a.external { - color: #d6368f !important; -} - -a.external:hover { - text-decoration: underline; -} - -p { - text-align: justify; -} - -.vp-sidebar a { - color: #d6368f; -} - -.vp-sidebar li li a { - color: #4b72b8; -} - -.vp-sidebar li li li a { - color: #2c3e50; - font-weight: 400; -} - -.vp-sidebar h3 { - padding-left: 1.5rem !important; -} - -.vp-sidebar ul a { - padding-left: 1.5rem !important; -} - -.vp-sidebar ul ul a { - padding-left: 3rem !important; -} - -.vp-sidebar ul ul ul a { - padding-left: 4.5rem !important; -} - -.vp-sidebar .toctree-l1.current a { - border-left: 0.5rem solid #6ecbd7; -} - -.vp-sidebar .toctree-l1 a.current { - border-left: 0.5rem solid #8857a3; -} - -.injected .rst-current-version, .injected dt { - color: #6ecbd7 !important; -} - -.cmdref .highlight-yoscrypt .highlight pre { - padding: 0%; - margin: 0%; -} - -.cmdref .highlight-none .highlight pre { - padding-top: 0%; - margin-top: 0%; -} - -.width-helper { - max-width: 100%; -} diff --git a/yosys/docs/util/RtlilLexer.py b/yosys/docs/util/RtlilLexer.py deleted file mode 100644 index 75aa53ec84c..00000000000 --- a/yosys/docs/util/RtlilLexer.py +++ /dev/null @@ -1,45 +0,0 @@ -from pygments.lexer import RegexLexer, bygroups, include -from pygments.token import Comment, Keyword, Name, Number, String, Whitespace - -__all__ = ['RtlilLexer'] - -class RtlilLexer(RegexLexer): - name = 'RTLIL' - aliases = ['rtlil'] - filenames = ['*.il'] - - keyword_re = r'(always|assign|attribute|autoidx|case|cell|connect|edge|end|global|high|init|inout|input|low|memory|module|negedge|offset|output|parameter|posedge|process|real|signed|size|switch|sync|update|upto|width|wire)' - - tokens = { - 'common': [ - (r'\s+', Whitespace), - (r'#.*', Comment.Single), - (keyword_re, Keyword), - (r'([\\\$][^ \t\r\n]+|\.[0-9]+)', Name.Variable), - (r"[0-9]+'[01xzm-]*", Number), - (r'-?[0-9]+', Number.Integer), - (r'"', String, 'string'), - ], - 'root': [ - (r'cell', Keyword, 'cell_definition'), - (r'(module|wire|memory|process)', Keyword, 'definition'), - include('common'), - ], - 'definition': [ - (r'([\\\$][^ \t\r\n]+|\.[0-9]+)', Name.Entity, '#pop'), - include('common') - ], - 'cell_definition': [ - (r'(\$[^ \t\r\n]+)\b', Name.Function), - (r'(\\[^ \t\r\n]+|\.[0-9]+)', Name.Variable), - (r'$', Whitespace, '#pop'), - include('common'), - ], - 'string': [ - (r'"', String, '#pop'), - (r'\\([\\abfnrtv"\']|x[a-fA-F0-9]{2,4}|[0-7]{1,3})', String.Escape), - (r'[^\\"\n]+', String), # all other characters - (r'(\\)(\n)', bygroups(String.Escape, Whitespace)), # line continuation - (r'\\', String), # stray backslash - ] - } diff --git a/yosys/docs/util/YoscryptLexer.py b/yosys/docs/util/YoscryptLexer.py deleted file mode 100644 index 8cb31c81aee..00000000000 --- a/yosys/docs/util/YoscryptLexer.py +++ /dev/null @@ -1,73 +0,0 @@ -from pygments.lexer import RegexLexer, bygroups, include -from pygments.token import (Comment, Error, Keyword, Name, Number, Operator, - String, Whitespace) - -__all__ = ['YoscryptLexer'] - -class YoscryptLexer(RegexLexer): - name = 'Yosys Script' - aliases = ['yoscrypt'] - filenames = ['*.ys'] - - - - tokens = { - 'common': [ - (r'\s+', Whitespace), - (r'#.*', Comment.Single), - (r'"', String, 'string'), - (r'(\d+)(\')([bdho]? ?\w+)', bygroups(Number, Operator, Number)), - (r'(\d+\.\d+)', Number.Float), - (r'(\d+)', Number), - (r'(\$[A-Za-z_0-9]*)', Name.Builtin), - (r'([A-Za-z_][A-Za-z_0-9\.\\/:-]*)', Name), - (r'(\[)(-\S*)(\])', # optional command - bygroups(Operator, Name.Attribute, Operator)), - (r'([\[<]\w*[\]>])', Name), # arguments - (r'[\{\}\|=\[\],]', Operator), - (r'.', Comment), - ], - 'root': [ - (r'([A-Za-z_][A-Za-z_0-9]*)', Keyword, 'command'), - (r'(-[A-Za-z_][A-Za-z_0-9]*)', Name.Attribute, 'command'), # shortcut for options - include('common'), - ], - 'command': [ - (r'(-[A-Za-z_][A-Za-z_0-9]*)', Name.Attribute), - (r'\+/[^\s]+', Name.Class), - (r'$', Whitespace, '#pop'), - (r';(?=\s)', Operator, '#pop'), - (r';{2,3}(?=\s)', Name.Class, '#pop'), - (r';{1,3}', Error, '#pop'), - (r'([ANwismctparn]:)', Keyword.Type, 'pattern'), - (r'@', Keyword.Type), - (r'%(x|ci|co)e?', Keyword.Type, 'expansion'), - (r'%[%nuidDcasmMCR]?', Keyword.Type), - (r'/', Operator), - include('common'), - ], - 'pattern': [ - (r'<<', Name), # Not an operator - (r'(=|<|<=|>|>=)', Operator), - (r':', Keyword.Type), - (r'$', Whitespace, '#pop:2'), - (r'\s+', Whitespace, '#pop'), - include('common'), - ], - 'expansion': [ - (r'$', Name.Class, '#pop:2'), - (r';(?=\s)', Operator, '#pop:2'), - (r';{2,3}(?=\s)', Name.Class, '#pop:2'), - (r'\s', Whitespace, '#pop'), - (r'[0-9\*]{1,3}', Number), - (r'[:+-,\[\]]', Operator), - include('common'), - ], - 'string': [ - (r'"', String, '#pop'), - (r'\\([\\abfnrtv"\']|x[a-fA-F0-9]{2,4}|[0-7]{1,3})', String.Escape), - (r'[^\\"\n]+', String), # all other characters - (r'(\\)(\n)', bygroups(String.Escape, Whitespace)), # line continuation - (r'\\', String), # stray backslash - ] - } diff --git a/yosys/examples/aiger/.gitignore b/yosys/examples/aiger/.gitignore deleted file mode 100644 index 3524e93629a..00000000000 --- 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 4e7694e95a3..00000000000 --- 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 8728b6722a1..00000000000 --- 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 b98287424ea..00000000000 --- 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 97c978a1505..00000000000 --- 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 35d8e9cb16e..00000000000 --- 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 e0f6b4cfe7e..00000000000 --- 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 06db525c9a1..00000000000 --- 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 ec802502e81..00000000000 --- 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 e17db771ea0..00000000000 --- 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 cb396cc2b04..00000000000 --- 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 0ce717294ac..00000000000 --- 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 2b01a22a82e..00000000000 --- 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 8cdaa19964e..00000000000 --- 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 10f05910305..00000000000 --- 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 b078ad51113..00000000000 --- 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 c3b6a610e77..00000000000 --- 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 4541826d32e..00000000000 --- 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 f58d9501819..00000000000 --- 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 c459b4b54ab..00000000000 --- 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 1b0bf8457d0..00000000000 --- 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 673b20d0824..00000000000 --- 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 27278facb3e..00000000000 --- 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 e1cb82a2fe3..00000000000 --- 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 f21658724f6..00000000000 --- 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 d0b093667ea..00000000000 --- 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 a5e728e0286..00000000000 --- 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 4a2eac40057..00000000000 --- 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 11e82507ea6..00000000000 --- 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 061704b646f..00000000000 --- 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 e571d2815e5..00000000000 --- 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 d7ab0fe1f21..00000000000 --- 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 c5f9d598700..00000000000 --- 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 a64593306a7..00000000000 --- 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 cfe0c080428..00000000000 --- 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) override - { - Module *module = design->top_module(); - - if (module == nullptr) - log_error("No top module found!\n"); - - Wire *wire_a = module->wire(ID::A); - Wire *wire_y = module->wire(ID::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 71030bdb805..00000000000 --- 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 0194e9f0915..00000000000 --- 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 c8f89dcf820..00000000000 --- a/yosys/examples/gowin/demo.cst +++ /dev/null @@ -1,10 +0,0 @@ -IO_LOC "clk" 35; -//IO_LOC "rst_n" 77; -IO_LOC "leds[0]" 79; -IO_LOC "leds[1]" 80; -IO_LOC "leds[2]" 81; -IO_LOC "leds[3]" 82; -IO_LOC "leds[4]" 83; -IO_LOC "leds[5]" 84; -IO_LOC "leds[6]" 85; -IO_LOC "leds[7]" 86; \ No newline at end of file diff --git a/yosys/examples/gowin/demo.sdc b/yosys/examples/gowin/demo.sdc deleted file mode 100644 index 6c90325fac6..00000000000 --- 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 485fec97f49..00000000000 --- a/yosys/examples/gowin/demo.v +++ /dev/null @@ -1,10 +0,0 @@ -module demo ( - input clk, - output [15:0] leds, - output unused -); - 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/device.cfg b/yosys/examples/gowin/device.cfg deleted file mode 100644 index f6ab8215954..00000000000 --- a/yosys/examples/gowin/device.cfg +++ /dev/null @@ -1,16 +0,0 @@ -set JTAG regular_io = false -set SSPI regular_io = false -set MSPI regular_io = false -set READY regular_io = false -set DONE regular_io = false -set RECONFIG_N regular_io = false -set MODE regular_io = false -set CRC_check = true -set compress = false -set encryption = false -set security_bit_enable = true -set bsram_init_fuse_print = true -set download_speed = 250/100 -set spi_flash_address = 0x00FFF000 -set format = txt -set background_programming = false diff --git a/yosys/examples/gowin/pnr.cfg b/yosys/examples/gowin/pnr.cfg deleted file mode 100644 index a1b43cc3b07..00000000000 --- a/yosys/examples/gowin/pnr.cfg +++ /dev/null @@ -1,8 +0,0 @@ --sdf --oc --ibs --posp --o --warning_all --tt --timing diff --git a/yosys/examples/gowin/run.sh b/yosys/examples/gowin/run.sh deleted file mode 100644 index cd260101ef2..00000000000 --- a/yosys/examples/gowin/run.sh +++ /dev/null @@ -1,11 +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 GW1NR-9-QFN88-6 -pn GW1NR-LV9QN88C6/I5 -cfg device.cfg -bit -tr -ph -timing -gpa -rpt -warning_all - -# 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/run.tcl b/yosys/examples/gowin/run.tcl deleted file mode 100644 index 39da11cee24..00000000000 --- a/yosys/examples/gowin/run.tcl +++ /dev/null @@ -1,9 +0,0 @@ -# gw_sh run.tcl -exec yosys -p "synth_gowin -top demo -vout demo_syn.v" demo.v -add_file -cst demo.cst -add_file -sdc demo.sdc -add_file -vm demo_syn.v -add_file -cfg device.cfg -set_option -device GW1NR-9-QFN88-6 -set_option -pn GW1NR-LV9QN88C6/I5 -run_pnr -opt pnr.cfg diff --git a/yosys/examples/gowin/testbench.v b/yosys/examples/gowin/testbench.v deleted file mode 100644 index 6d206381e49..00000000000 --- 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 33b7182d38d..00000000000 --- 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 298d9e934bd..00000000000 --- 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 f8b487316ad..00000000000 --- 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 4a9486e50f6..00000000000 --- 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 abc94e47954..00000000000 --- 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 a08894e0aed..00000000000 --- 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 9fc734eb396..00000000000 --- 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 5a230155fac..00000000000 --- 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 83aa3b60900..00000000000 --- 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 518807b574b..00000000000 --- 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 06cf7c146c5..00000000000 --- 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 2bada0e2188..00000000000 --- 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 0378e4fa7fc..00000000000 --- 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 f1621054062..00000000000 --- 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 06cf7c146c5..00000000000 --- 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 2bada0e2188..00000000000 --- 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 ba365fabf8e..00000000000 --- 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 43db1606aea..00000000000 --- 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 db29e60f192..00000000000 --- 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 c7498bded84..00000000000 --- 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 b75d552bbaf..00000000000 --- 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 c3b26b03423..00000000000 --- 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 51118bb4bb3..00000000000 --- 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/mimas2/README b/yosys/examples/mimas2/README deleted file mode 100644 index b12875cbc6e..00000000000 --- a/yosys/examples/mimas2/README +++ /dev/null @@ -1,8 +0,0 @@ -A simple example design, based on the Numato Labs Mimas V2 board -================================================================ - -This example uses Yosys for synthesis and Xilinx ISE -for place&route and bit-stream creation. - -To synthesize: - bash run.sh diff --git a/yosys/examples/mimas2/example.ucf b/yosys/examples/mimas2/example.ucf deleted file mode 100644 index 4e31b74abf1..00000000000 --- a/yosys/examples/mimas2/example.ucf +++ /dev/null @@ -1,13 +0,0 @@ -CONFIG VCCAUX = "3.3" ; - - -NET "CLK" LOC = D9 | IOSTANDARD = LVCMOS33 | PERIOD = 12MHz ; - -NET "LED[7]" LOC = P15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; -NET "LED[6]" LOC = P16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; -NET "LED[5]" LOC = N15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; -NET "LED[4]" LOC = N16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; -NET "LED[3]" LOC = U17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; -NET "LED[2]" LOC = U18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; -NET "LED[1]" LOC = T17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; -NET "LED[0]" LOC = T18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; diff --git a/yosys/examples/mimas2/example.v b/yosys/examples/mimas2/example.v deleted file mode 100644 index 2a91173936a..00000000000 --- a/yosys/examples/mimas2/example.v +++ /dev/null @@ -1,14 +0,0 @@ -module example( - input wire CLK, - output wire [7:0] LED -); - -reg [27:0] ctr; -initial ctr = 0; - -always @(posedge CLK) - ctr <= ctr + 1; - -assign LED = ctr[27:20]; - -endmodule diff --git a/yosys/examples/mimas2/run.sh b/yosys/examples/mimas2/run.sh deleted file mode 100644 index aafde78ed83..00000000000 --- a/yosys/examples/mimas2/run.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -set -e -yosys run_yosys.ys -edif2ngd example.edif -ngdbuild example -uc example.ucf -p xc6slx9csg324-3 -map -w example -par -w example.ncd example_par.ncd -bitgen -w example_par.ncd -g StartupClk:JTAGClk diff --git a/yosys/examples/mimas2/run_yosys.ys b/yosys/examples/mimas2/run_yosys.ys deleted file mode 100644 index b48877811cc..00000000000 --- a/yosys/examples/mimas2/run_yosys.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog example.v -synth_xilinx -top example -family xc6s -ise -write_edif -pvector bra example.edif diff --git a/yosys/examples/osu035/.gitignore b/yosys/examples/osu035/.gitignore deleted file mode 100644 index 3abf340bbe3..00000000000 --- 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 2bb8162b33f..00000000000 --- 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 eb2c6e8d519..00000000000 --- 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 0f043e5fc1e..00000000000 --- 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 6821ef42664..00000000000 --- 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 758de11347f..00000000000 --- 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 d67cf4a23c5..00000000000 --- 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 f0fa5a0b8f3..00000000000 --- 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 278f5ebf7dd..00000000000 --- 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 af937ea74d0..00000000000 --- a/yosys/examples/smtbmc/Makefile +++ /dev/null @@ -1,77 +0,0 @@ - -all: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 demo9 glift_mux - -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 - -demo9: demo9.smt2 - yosys-smtbmc -s z3 -t 1 -g demo9.smt2 - -glift_mux: - yosys -ql glift_mux.yslog glift/mux2.ys - -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' - -demo9.smt2: demo9.v - yosys -ql demo9.yslog -p 'read_verilog -formal demo9.v; prep -top demo9 -nordff; write_smt2 -stbv -wires demo9.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 - rm -f demo9.yslog demo9.smt2 - rm -f glift_mux.ys - -.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 demo9 clean - diff --git a/yosys/examples/smtbmc/demo1.v b/yosys/examples/smtbmc/demo1.v deleted file mode 100644 index 567dde1483e..00000000000 --- 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 0cf529a4298..00000000000 --- 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 f5e017cf026..00000000000 --- 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 13b3a19700f..00000000000 --- 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 2f91f8164a5..00000000000 --- 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 3f1b47277dd..00000000000 --- 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 63ace307cf0..00000000000 --- 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 62a72e2a85c..00000000000 --- 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 63f6272f16f..00000000000 --- 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 c4c396cde3b..00000000000 --- 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/examples/smtbmc/demo9.v b/yosys/examples/smtbmc/demo9.v deleted file mode 100644 index f0b91e2ca27..00000000000 --- a/yosys/examples/smtbmc/demo9.v +++ /dev/null @@ -1,13 +0,0 @@ -module demo9; - (* maximize *) wire[7:0] h = $anyconst; - wire [7:0] i = $allconst; - - wire [7:0] t0 = ((i << 8'b00000010) + 8'b00000011); - wire trigger = (t0 > h) && (h < 8'b00000100); - - always @* begin - assume(trigger == 1'b1); - cover(1); - end -endmodule - diff --git a/yosys/examples/smtbmc/glift/C7552.v b/yosys/examples/smtbmc/glift/C7552.v deleted file mode 100755 index 47a8b0d37d7..00000000000 --- a/yosys/examples/smtbmc/glift/C7552.v +++ /dev/null @@ -1,4194 +0,0 @@ -module C7552_lev2(pi000, pi001, pi002, pi003, pi004, pi005, pi006, pi007, pi008, pi009, - pi010, pi011, pi012, pi013, pi014, pi015, pi016, pi017, pi018, pi019, - pi020, pi021, pi022, pi023, pi024, pi025, pi026, pi027, pi028, pi029, - pi030, pi031, pi032, pi033, pi034, pi035, pi036, pi037, pi038, pi039, - pi040, pi041, pi042, pi043, pi044, pi045, pi046, pi047, pi048, pi049, - pi050, pi051, pi052, pi053, pi054, pi055, pi056, pi057, pi058, pi059, - pi060, pi061, pi062, pi063, pi064, pi065, pi066, pi067, pi068, pi069, - pi070, pi071, pi072, pi073, pi074, pi075, pi076, pi077, pi078, pi079, - pi080, pi081, pi082, pi083, pi084, pi085, pi086, pi087, pi088, pi089, - pi090, pi091, pi092, pi093, pi094, pi095, pi096, pi097, pi098, pi099, - pi100, pi101, pi102, pi103, pi104, pi105, pi106, pi107, pi108, pi109, - pi110, pi111, pi112, pi113, pi114, pi115, pi116, pi117, pi118, pi119, - pi120, pi121, pi122, pi123, pi124, pi125, pi126, pi127, pi128, pi129, - pi130, pi131, pi132, pi133, pi134, pi135, pi136, pi137, pi138, pi139, - pi140, pi141, pi142, pi143, pi144, pi145, pi146, pi147, pi148, pi149, - pi150, pi151, pi152, pi153, pi154, pi155, pi156, pi157, pi158, pi159, - pi160, pi161, pi162, pi163, pi164, pi165, pi166, pi167, pi168, pi169, - pi170, pi171, pi172, pi173, pi174, pi175, pi176, pi177, pi178, pi179, - pi180, pi181, pi182, pi183, pi184, pi185, pi186, pi187, pi188, pi189, - pi190, pi191, pi192, pi193, pi194, pi195, pi196, pi197, pi198, pi199, - pi200, pi201, pi202, pi203, pi204, pi205, pi206, po000, po001, po002, - po003, po004, po005, po006, po007, po008, po009, po010, po011, po012, - po013, po014, po015, po016, po017, po018, po019, po020, po021, po022, - po023, po024, po025, po026, po027, po028, po029, po030, po031, po032, - po033, po034, po035, po036, po037, po038, po039, po040, po041, po042, - po043, po044, po045, po046, po047, po048, po049, po050, po051, po052, - po053, po054, po055, po056, po057, po058, po059, po060, po061, po062, - po063, po064, po065, po066, po067, po068, po069, po070, po071, po072, - po073, po074, po075, po076, po077, po078, po079, po080, po081, po082, - po083, po084, po085, po086, po087, po088, po089, po090, po091, po092, - po093, po094, po095, po096, po097, po098, po099, po100, po101, po102, - po103, po104, po105, po106, po107); - -input pi000, pi001, pi002, pi003, pi004, pi005, pi006, pi007, pi008, pi009, - pi010, pi011, pi012, pi013, pi014, pi015, pi016, pi017, pi018, pi019, - pi020, pi021, pi022, pi023, pi024, pi025, pi026, pi027, pi028, pi029, - pi030, pi031, pi032, pi033, pi034, pi035, pi036, pi037, pi038, pi039, - pi040, pi041, pi042, pi043, pi044, pi045, pi046, pi047, pi048, pi049, - pi050, pi051, pi052, pi053, pi054, pi055, pi056, pi057, pi058, pi059, - pi060, pi061, pi062, pi063, pi064, pi065, pi066, pi067, pi068, pi069, - pi070, pi071, pi072, pi073, pi074, pi075, pi076, pi077, pi078, pi079, - pi080, pi081, pi082, pi083, pi084, pi085, pi086, pi087, pi088, pi089, - pi090, pi091, pi092, pi093, pi094, pi095, pi096, pi097, pi098, pi099, - pi100, pi101, pi102, pi103, pi104, pi105, pi106, pi107, pi108, pi109, - pi110, pi111, pi112, pi113, pi114, pi115, pi116, pi117, pi118, pi119, - pi120, pi121, pi122, pi123, pi124, pi125, pi126, pi127, pi128, pi129, - pi130, pi131, pi132, pi133, pi134, pi135, pi136, pi137, pi138, pi139, - pi140, pi141, pi142, pi143, pi144, pi145, pi146, pi147, pi148, pi149, - pi150, pi151, pi152, pi153, pi154, pi155, pi156, pi157, pi158, pi159, - pi160, pi161, pi162, pi163, pi164, pi165, pi166, pi167, pi168, pi169, - pi170, pi171, pi172, pi173, pi174, pi175, pi176, pi177, pi178, pi179, - pi180, pi181, pi182, pi183, pi184, pi185, pi186, pi187, pi188, pi189, - pi190, pi191, pi192, pi193, pi194, pi195, pi196, pi197, pi198, pi199, - pi200, pi201, pi202, pi203, pi204, pi205, pi206; - -output po000, po001, po002, po003, po004, po005, po006, po007, po008, po009, - po010, po011, po012, po013, po014, po015, po016, po017, po018, po019, - po020, po021, po022, po023, po024, po025, po026, po027, po028, po029, - po030, po031, po032, po033, po034, po035, po036, po037, po038, po039, - po040, po041, po042, po043, po044, po045, po046, po047, po048, po049, - po050, po051, po052, po053, po054, po055, po056, po057, po058, po059, - po060, po061, po062, po063, po064, po065, po066, po067, po068, po069, - po070, po071, po072, po073, po074, po075, po076, po077, po078, po079, - po080, po081, po082, po083, po084, po085, po086, po087, po088, po089, - po090, po091, po092, po093, po094, po095, po096, po097, po098, po099, - po100, po101, po102, po103, po104, po105, po106, po107; - -wire n2822, n2823, n2824, n2825, n2826, n2827, n2828, n2829, n2830, n2831, - n2832, n2833, n2834, n2835, n2836, n2837, n2838, n2839, n2840, n2841, - n2842, n2843, n2844, n2845, n2846, n2847, n2848, n2849, n2850, n2851, - n2852, n2853, n2854, n2855, n2856, n2857, n2858, n2859, n2860, n2861, - n2862, n2863, n2864, n2865, n2866, n2867, n2868, n2869, n2870, n2871, - n2872, n2873, n2874, n2875, n2876, n2877, n2878, n2879, n2880, n2881, - n2882, n2883, n2884, n2885, n2886, n2887, n2888, n2889, n2890, n2891, - n2892, n2893, n2894, n2895, n2896, n2897, n2898, n2899, n2900, n2901, - n2902, n2903, n2904, n2905, n2906, n2907, n2908, n2909, n2910, n2911, - n2912, n2913, n2914, n2915, n2916, n2917, n2918, n2919, n2920, n2921, - n2922, n2923, n2924, n2925, n2926, n2927, n2928, n2929, n2930, n2931, - n2932, n2933, n2934, n2935, n2936, n2937, n2938, n2939, n2940, n2941, - n2942, n2943, n2944, n2945, n2946, n2947, n2948, n2949, n2950, n2951, - n2952, n2953, n2954, n2955, n2956, n2957, n2958, n2959, n2960, n2961, - n2962, n2963, n2964, n2965, n2966, n2967, n2968, n2969, n2970, n2971, - n2972, n2973, n2974, n2975, n2976, n2977, n2978, n2979, n2980, n2981, - n2982, n2983, n2984, n2985, n2986, n2987, n2988, n2989, n2990, n2991, - n2992, n2993, n2994, n2995, n2996, n2997, n2998, n2999, n3000, n3001, - n3002, n3003, n3004, n3005, n3006, n3007, n3008, n3009, n3010, n3011, - n3012, n3013, n3014, n3015, n3016, n3017, n3018, n3019, n3020, n3021, - n3022, n3023, n3024, n3025, n3026, n3027, n3028, n3029, n3030, n3031, - n3032, n3033, n3034, n3035, n3036, n3037, n3038, n3039, n3040, n3041, - n3042, n3043, n3044, n3045, n3046, n3047, n3048, n3049, n3050, n3051, - n3052, n3053, n3054, n3055, n3056, n3057, n3058, n3059, n3060, n3061, - n3062, n3063, n3064, n3065, n3066, n3067, n3068, n3069, n3070, n3071, - n3072, n3073, n3074, n3075, n3076, n3077, n3078, n3079, n3080, n3081, - n3082, n3083, n3084, n3085, n3086, n3087, n3088, n3089, n3090, n3091, - n3092, n3093, n3094, n3095, n3096, n3097, n3098, n3099, n3100, n3101, - n3102, n3103, n3104, n3105, n3106, n3107, n3108, n3109, n3110, n3111, - n3112, n3113, n3114, n3115, n3116, n3117, n3118, n3119, n3120, n3121, - n3122, n3123, n3124, n3125, n3126, n3127, n3128, n3129, n3130, n3131, - n3132, n3133, n3134, n3135, n3136, n3137, n3138, n3139, n3140, n3141, - n3142, n3143, n3144, n3145, n3146, n3147, n3148, n3149, n3150, n3151, - n3152, n3153, n3154, n3155, n3156, n3157, n3158, n3159, n3160, n3161, - n3162, n3163, n3164, n3165, n3166, n3167, n3168, n3169, n3170, n3171, - n3172, n3173, n3174, n3175, n3176, n3177, n3178, n3179, n3180, n3181, - n3182, n3183, n3184, n3185, n3186, n3187, n3188, n3189, n3190, n3191, - n3192, n3193, n3194, n3195, n3196, n3197, n3198, n3199, n3200, n3201, - n3202, n3203, n3204, n3205, n3206, n3207, n3208, n3209, n3210, n3211, - n3212, n3213, n3214, n3215, n3216, n3217, n3218, n3219, n3220, n3221, - n3222, n3223, n3224, n3225, n3226, n3227, n3228, n3229, n3230, n3231, - n3232, n3233, n3234, n3235, n3236, n3237, n3238, n3239, n3240, n3241, - n3242, n3243, n3244, n3245, n3246, n3247, n3248, n3249, n3250, n3251, - n3252, n3253, n3254, n3255, n3256, n3257, n3258, n3259, n3260, n3261, - n3262, n3263, n3264, n3265, n3266, n3267, n3268, n3269, n3270, n3271, - n3272, n3273, n3274, n3275, n3276, n3277, n3278, n3279, n3280, n3281, - n3282, n3283, n3284, n3285, n3286, n3287, n3288, n3289, n3290, n3291, - n3292, n3293, n3294, n3295, n3296, n3297, n3298, n3299, n3300, n3301, - n3302, n3303, n3304, n3305, n3306, n3307, n3308, n3309, n3310, n3311, - n3312, n3313, n3314, n3315, n3316, n3317, n3318, n3319, n3320, n3321, - n3322, n3323, n3324, n3325, n3326, n3327, n3328, n3329, n3330, n3331, - n3332, n3333, n3334, n3335, n3336, n3337, n3338, n3339, n3340, n3341, - n3342, n3343, n3344, n3345, n3346, n3347, n3348, n3349, n3350, n3351, - n3352, n3353, n3354, n3355, n3356, n3357, n3358, n3359, n3360, n3361, - n3362, n3363, n3364, n3365, n3366, n3367, n3368, n3369, n3370, n3371, - n3372, n3373, n3374, n3375, n3376, n3377, n3378, n3379, n3380, n3381, - n3382, n3383, n3384, n3385, n3386, n3387, n3388, n3389, n3390, n3391, - n3392, n3393, n3394, n3395, n3396, n3397, n3398, n3399, n3400, n3401, - n3402, n3403, n3404, n3405, n3406, n3407, n3408, n3409, n3410, n3411, - n3412, n3413, n3414, n3415, n3416, n3417, n3418, n3419, n3420, n3421, - n3422, n3423, n3424, n3425, n3426, n3427, n3428, n3429, n3430, n3431, - n3432, n3433, n3434, n3435, n3436, n3437, n3438, n3439, n3440, n3441, - n3442, n3443, n3444, n3445, n3446, n3447, n3448, n3449, n3450, n3451, - n3452, n3453, n3454, n3455, n3456, n3457, n3458, n3459, n3460, n3461, - n3462, n3463, n3464, n3465, n3466, n3467, n3468, n3469, n3470, n3471, - n3472, n3473, n3474, n3475, n3476, n3477, n3478, n3479, n3480, n3481, - n3482, n3483, n3484, n3485, n3486, n3487, n3488, n3489, n3490, n3491, - n3492, n3493, n3494, n3495, n3496, n3497, n3498, n3499, n3500, n3501, - n3502, n3503, n3504, n3505, n3506, n3507, n3508, n3509, n3510, n3511, - n3512, n3513, n3514, n3515, n3516, n3517, n3518, n3519, n3520, n3521, - n3522, n3523, n3524, n3525, n3526, n3527, n3528, n3529, n3530, n3531, - n3532, n3533, n3534, n3535, n3536, n3537, n3538, n3539, n3540, n3541, - n3542, n3543, n3544, n3545, n3546, n3547, n3548, n3549, n3550, n3551, - n3552, n3553, n3554, n3555, n3556, n3557, n3558, n3559, n3560, n3561, - n3562, n3563, n3564, n3565, n3566, n3567, n3568, n3569, n3570, n3571, - n3572, n3573, n3574, n3575, n3576, n3577, n3578, n3579, n3580, n3581, - n3582, n3583, n3584, n3585, n3586, n3587, n3588, n3589, n3590, n3591, - n3592, n3593, n3594, n3595, n3596, n3597, n3598, n3599, n3600, n3601, - n3602, n3603, n3604, n3605, n3606, n3607, n3608, n3609, n3610, n3611, - n3612, n3613, n3614, n3615, n3616, n3617, n3618, n3619, n3620, n3621, - n3622, n3623, n3624, n3625, n3626, n3627, n3628, n3629, n3630, n3631, - n3632, n3633, n3634, n3635, n3636, n3637, n3638, n3639, n3640, n3641, - n3642, n3643, n3644, n3645, n3646, n3647, n3648, n3649, n3650, n3651, - n3652, n3653, n3654, n3655, n3656, n3657, n3658, n3659, n3660, n3661, - n3662, n3663, n3664, n3665, n3666, n3667, n3668, n3669, n3670, n3671, - n3672, n3673, n3674, n3675, n3676, n3677, n3678, n3679, n3680, n3681, - n3682, n3683, n3684, n3685, n3686, n3687, n3688, n3689, n3690, n3691, - n3692, n3693, n3694, n3695, n3696, n3697, n3698, n3699, n3700, n3701, - n3702, n3703, n3704, n3705, n3706, n3707, n3708, n3709, n3710, n3711, - n3712, n3713, n3714, n3715, n3716, n3717, n3718, n3719, n3720, n3721, - n3722, n3723, n3724, n3725, n3726, n3727, n3728, n3729, n3730, n3731, - n3732, n3733, n3734, n3735, n3736, n3737, n3738, n3739, n3740, n3741, - n3742, n3743, n3744, n3745, n3746, n3747, n3748, n3749, n3750, n3751, - n3752, n3753, n3754, n3755, n3756, n3757, n3758, n3759, n3760, n3761, - n3762, n3763, n3764, n3765, n3766, n3767, n3768, n3769, n3770, n3771, - n3772, n3773, n3774, n3775, n3776, n3777, n3778, n3779, n3780, n3781, - n3782, n3783, n3784, n3785, n3786, n3787, n3788, n3789, n3790, n3791, - n3792, n3793, n3794, n3795, n3796, n3797, n3798, n3799, n3800, n3801, - n3802, n3803, n3804, n3805, n3806, n3807, n3808, n3809, n3810, n3811, - n3812, n3813, n3814, n3815, n3816, n3817, n3818, n3819, n3820, n3821, - n3822, n3823, n3824, n3825, n3826, n3827, n3828, n3829, n3830, n3831, - n3832, n3833, n3834, n3835, n3836, n3837, n3838, n3839, n3840, n3841, - n3842, n3843, n3844, n3845, n3846, n3847, n3848, n3849, n3850, n3851, - n3852, n3853, n3854, n3855, n3856, n3857, n3858, n3859, n3860, n3861, - n3862, n3863, n3864, n3865, n3866, n3867, n3868, n3869, n3870, n3871, - n3872, n3873, n3874, n3875, n3876, n3877, n3878, n3879, n3880, n3881, - n3882, n3883, n3884, n3885, n3886, n3887, n3888, n3889, n3890, n3891, - n3892, n3893, n3894, n3895, n3896, n3897, n3898, n3899, n3900, n3901, - n3902, n3903, n3904, n3905, n3906, n3907, n3908, n3909, n3910, n3911, - n3912, n3913, n3914, n3915, n3916, n3917, n3918, n3919, n3920, n3921, - n3922, n3923, n3924, n3925, n3926, n3927, n3928, n3929, n3930, n3931, - n3932, n3933, n3934, n3935, n3936, n3937, n3938, n3939, n3940, n3941, - n3942, n3943, n3944, n3945, n3946, n3947, n3948, n3949, n3950, n3951, - n3952, n3953, n3954, n3955, n3956, n3957, n3958, n3959, n3960, n3961, - n3962, n3963, n3964, n3965, n3966, n3967, n3968, n3969, n3970, n3971, - n3972, n3973, n3974, n3975, n3976, n3977, n3978, n3979, n3980, n3981, - n3982, n3983, n3984, n3985, n3986, n3987, n3988, n3989, n3990, n3991, - n3992, n3993, n3994, n3995, n3996, n3997, n3998, n3999, n4000, n4001, - n4002, n4003, n4004, n4005, n4006, n4007, n4008, n4009, n4010, n4011, - n4012, n4013, n4014, n4015, n4016, n4017, n4018, n4019, n4020, n4021, - n4022, n4023, n4024, n4025, n4026, n4027, n4028, n4029, n4030, n4031, - n4032, n4033, n4034, n4035, n4036, n4037, n4038, n4039, n4040, n4041, - n4042, n4043, n4044, n4045, n4046, n4047, n4048, n4049, n4050, n4051, - n4052, n4053, n4054, n4055, n4056, n4057, n4058, n4059, n4060, n4061, - n4062, n4063, n4064, n4065, n4066, n4067, n4068, n4069, n4070, n4071, - n4072, n4073, n4074, n4075, n4076, n4077, n4078, n4079, n4080, n4081, - n4082, n4083, n4084, n4085, n4086, n4087, n4088, n4089, n4090, n4091, - n4092, n4093, n4094, n4095, n4096, n4097, n4098, n4099, n4100, n4101, - n4102, n4103, n4104, n4105, n4106, n4107, n4108, n4109, n4110, n4111, - n4112, n4113, n4114, n4115, n4116, n4117, n4118, n4119, n4120, n4121, - n4122, n4123, n4124, n4125, n4126, n4127, n4128, n4129, n4130, n4131, - n4132, n4133, n4134, n4135, n4136, n4137, n4138, n4139, n4140, n4141, - n4142, n4143, n4144, n4145, n4146, n4147, n4148, n4149, n4150, n4151, - n4152, n4153, n4154, n4155, n4156, n4157, n4158, n4159, n4160, n4161, - n4162, n4163, n4164, n4165, n4166, n4167, n4168, n4169, n4170, n4171, - n4172, n4173, n4174, n4175, n4176, n4177, n4178, n4179, n4180, n4181, - n4182, n4183, n4184, n4185, n4186, n4187, n4188, n4189, n4190, n4191, - n4192, n4193, n4194, n4195, n4196, n4197, n4198, n4199, n4200, n4201, - n4202, n4203, n4204, n4205, n4206, n4207, n4208, n4209, n4210, n4211, - n4212, n4213, n4214, n4215, n4216, n4217, n4218, n4219, n4220, n4221, - n4222, n4223, n4224, n4225, n4226, n4227, n4228, n4229, n4230, n4231, - n4232, n4233, n4234, n4235, n4236, n4237, n4238, n4239, n4240, n4241, - n4242, n4243, n4244, n4245, n4246, n4247, n4248, n4249, n4250, n4251, - n4252, n4253, n4254, n4255, n4256, n4257, n4258, n4259, n4260, n4261, - n4262, n4263, n4264, n4265, n4266, n4267, n4268, n4269, n4270, n4271, - n4272, n4273, n4274, n4275, n4276, n4277, n4278, n4279, n4280, n4281, - n4282, n4283, n4284, n4285, n4286, n4287, n4288, n4289, n4290, n4291, - n4292, n4293, n4294, n4295, n4296, n4297, n4298, n4299, n4300, n4301, - n4302, n4303, n4304, n4305, n4306, n4307, n4308, n4309, n4310, n4311, - n4312, n4313, n4314, n4315, n4316, n4317, n4318, n4319, n4320, n4321, - n4322, n4323, n4324, n4325, n4326, n4327, n4328, n4329, n4330, n4331, - n4332, n4333, n4334, n4335, n4336, n4337, n4338, n4339, n4340, n4341, - n4342, n4343, n4344, n4345, n4346, n4347, n4348, n4349, n4350, n4351, - n4352, n4353, n4354, n4355, n4356, n4357, n4358, n4359, n4360, n4361, - n4362, n4363, n4364, n4365, n4366, n4367, n4368, n4369, n4370, n4371, - n4372, n4373, n4374, n4375, n4376, n4377, n4378, n4379, n4380, n4381, - n4382, n4383, n4384, n4385, n4386, n4387, n4388, n4389, n4390, n4391, - n4392, n4393, n4394, n4395, n4396, n4397, n4398, n4399, n4400, n4401, - n4402, n4403, n4404, n4405, n4406, n4407, n4408, n4409, n4410, n4411, - n4412, n4413, n4414, n4415, n4416, n4417, n4418, n4419, n4420, n4421, - n4422, n4423, n4424, n4425, n4426, n4427, n4428, n4429, n4430, n4431, - n4432, n4433, n4434, n4435, n4436, n4437, n4438, n4439, n4440, n4441, - n4442, n4443, n4444, n4445, n4446, n4447, n4448, n4449, n4450, n4451, - n4452, n4453, n4454, n4455, n4456, n4457, n4458, n4459, n4460, n4461, - n4462, n4463, n4464, n4465, n4466, n4467, n4468, n4469, n4470, n4471, - n4472, n4473, n4474, n4475, n4476, n4477, n4478, n4479, n4480, n4481, - n4482, n4483, n4484, n4485, n4486, n4487, n4488, n4489, n4490, n4491, - n4492, n4493, n4494, n4495, n4496, n4497, n4498, n4499, n4500, n4501, - n4502, n4503, n4504, n4505, n4506, n4507, n4508, n4509, n4510, n4511, - n4512, n4513, n4514, n4515, n4516, n4517, n4518, n4519, n4520, n4521, - n4522, n4523, n4524, n4525, n4526, n4527, n4528, n4529, n4530, n4531, - n4532, n4533, n4534, n4535, n4536, n4537, n4538, n4539, n4540, n4541, - n4542, n4543, n4544, n4545, n4546, n4547, n4548, n4549, n4550, n4551, - n4552, n4553, n4554, n4555, n4556, n4557, n4558, n4559, n4560, n4561, - n4562, n4563, n4564, n4565, n4566, n4567, n4568, n4569, n4570, n4571, - n4572, n4573, n4574, n4575, n4576, n4577, n4578, n4579, n4580, n4581, - n4582, n4583, n4584, n4585, n4586, n4587, n4588, n4589, n4590, n4591, - n4592, n4593, n4594, n4595, n4596, n4597, n4598, n4599, n4600, n4601, - n4602, n4603, n4604, n4605, n4606, n4607, n4608, n4609, n4610, n4611, - n4612, n4613, n4614, n4615, n4616, n4617, n4618, n4619, n4620, n4621, - n4622, n4623, n4624, n4625, n4626, n4627, n4628, n4629, n4630, n4631, - n4632, n4633, n4634, n4635, n4636, n4637, n4638, n4639, n4640, n4641, - n4642, n4643, n4644, n4645, n4646, n4647, n4648, n4649, n4650, n4651, - n4652, n4653, n4654, n4655, n4656, n4657, n4658, n4659, n4660, n4661, - n4662, n4663, n4664, n4665, n4666, n4667, n4668, n4669, n4670, n4671, - n4672, n4673, n4674, n4675, n4676, n4677, n4678, n4679, n4680, n4681, - n4682, n4683, n4684, n4685, n4686, n4687, n4688, n4689, n4690, n4691, - n4692, n4693, n4694, n4695, n4696, n4697, n4698, n4699, n4700, n4701, - n4702, n4703, n4704, n4705, n4706, n4707, n4708, n4709, n4710, n4711, - n4712, n4713, n4714, n4715, n4716, n4717, n4718, n4719, n4720, n4721, - n4722, n4723, n4724, n4725, n4726, n4727, n4728, n4729, n4730, n4731, - n4732, n4733, n4734, n4735, n4736, n4737, n4738, n4739, n4740, n4741, - n4742, n4743, n4744, n4745, n4746, n4747, n4748, n4749, n4750, n4751, - n4752, n4753, n4754, n4755, n4756, n4757, n4758, n4759, n4760, n4761, - n4762, n4763, n4764, n4765, n4766, n4767, n4768, n4769, n4770, n4771, - n4772, n4773, n4774, n4775, n4776, n4777, n4778, n4779, n4780, n4781, - n4782, n4783, n4784, n4785, n4786, n4787, n4788, n4789, n4790, n4791, - n4792, n4793, n4794, n4795, n4796, n4797, n4798, n4799, n4800, n4801, - n4802, n4803, n4804, n4805, n4806, n4807, n4808, n4809, n4810, n4811, - n4812, n4813, n4814, n4815, n4816, n4817, n4818, n4819, n4820, n4821, - n4822, n4823, n4824, n4825, n4826, n4827, n4828, n4829, n4830, n4831, - n4832, n4833, n4834, n4835, n4836, n4837, n4838, n4839, n4840, n4841, - n4842, n4843, n4844, n4845, n4846, n4847, n4848, n4849, n4850, n4851, - n4852, n4853, n4854, n4855, n4856, n4857, n4858, n4859, n4860, n4861, - n4862, n4863, n4864, n4865, n4866, n4867, n4868, n4869, n4870, n4871, - n4872, n4873, n4874, n4875, n4876, n4877, n4878, n4879, n4880, n4881, - n4882, n4883, n4884, n4885, n4886, n4887, n4888, n4889, n4890, n4891, - n4892, n4893, n4894, n4895, n4896, n4897, n4898, n4899, n4900, n4901, - n4902, n4903, n4904, n4905, n4906, n4907, n4908, n4909, n4910, n4911, - n4912, n4913, n4914, n4915, n4916, n4917, n4918, n4919, n4920, n4921, - n4922, n4923, n4924, n4925, n4926, n4927, n4928, n4929, n4930, n4931, - n4932, n4933, n4934, n4935, n4936, n4937, n4938, n4939, n4940, n4941, - n4942, n4943, n4944, n4945, n4946, n4947, n4948, n4949, n4950, n4951, - n4952, n4953, n4954, n4955, n4956, n4957, n4958, n4959, n4960, n4961, - n4962, n4963, n4964, n4965, n4966, n4967, n4968, n4969, n4970, n4971, - n4972, n4973, n4974, n4975, n4976, n4977, n4978, n4979, n4980, n4981, - n4982, n4983, n4984, n4985, n4986, n4987, n4988, n4989, n4990, n4991, - n4992, n4993, n4994, n4995, n4996, n4997, n4998, n4999, n5000, n5001, - n5002, n5003, n5004, n5005, n5006, n5007, n5008, n5009, n5010, n5011, - n5012, n5013, n5014, n5015, n5016, n5017, n5018, n5019, n5020, n5021, - n5022, n5023, n5024, n5025, n5026, n5027, n5028, n5029, n5030, n5031, - n5032, n5033, n5034, n5035, n5036, n5037, n5038, n5039, n5040, n5041, - n5042, n5043, n5044, n5045, n5046, n5047, n5048, n5049, n5050, n5051, - n5052, n5053, n5054, n5055, n5056, n5057, n5058, n5059, n5060, n5061, - n5062, n5063, n5064, n5065, n5066, n5067, n5068, n5069, n5070, n5071, - n5072, n5073, n5074, n5075, n5076, n5077, n5078, n5079, n5080, n5081, - n5082, n5083, n5084, n5085, n5086, n5087, n5088, n5089, n5090, n5091, - n5092, n5093, n5094, n5095, n5096, n5097, n5098, n5099, n5100, n5101, - n5102, n5103, n5104, n5105, n5106, n5107, n5108, n5109, n5110, n5111, - n5112, n5113, n5114, n5115, n5116, n5117, n5118, n5119, n5120, n5121, - n5122, n5123, n5124, n5125, n5126, n5127, n5128, n5129, n5130, n5131, - n5132, n5133, n5134, n5135, n5136, n5137, n5138, n5139, n5140, n5141, - n5142, n5143, n5144, n5145, n5146, n5147, n5148, n5149, n5150, n5151, - n5152, n5153, n5154, n5155, n5156, n5157, n5158, n5159, n5160, n5161, - n5162, n5163, n5164, n5165, n5166, n5167, n5168, n5169, n5170, n5171, - n5172, n5173, n5174, n5175, n5176, n5177, n5178, n5179, n5180, n5181, - n5182, n5183, n5184, n5185, n5186, n5187, n5188, n5189, n5190, n5191, - n5192, n5193, n5194, n5195, n5196, n5197, n5198, n5199, n5200, n5201, - n5202, n5203, n5204, n5205, n5206, n5207, n5208, n5209, n5210, n5211, - n5212, n5213, n5214, n5215, n5216, n5217, n5218, n5219, n5220, n5221, - n5222, n5223, n5224, n5225, n5226, n5227, n5228, n5229, n5230, n5231, - n5232, n5233, n5234, n5235, n5236, n5237, n5238, n5239, n5240, n5241, - n5242, n5243, n5244, n5245, n5246, n5247, n5248, n5249, n5250, n5251, - n5252, n5253, n5254, n5255, n5256, n5257, n5258, n5259, n5260, n5261, - n5262, n5263, n5264, n5265, n5266, n5267, n5268, n5269, n5270, n5271, - n5272, n5273, n5274, n5275, n5276, n5277, n5278, n5279, n5280, n5281, - n5282, n5283, n5284, n5285, n5286, n5287, n5288, n5289, n5290, n5291, - n5292, n5293, n5294, n5295, n5296, n5297, n5298, n5299, n5300, n5301, - n5302, n5303, n5304, n5305, n5306, n5307, n5308, n5309, n5310, n5311, - n5312, n5313, n5314, n5315, n5316, n5317, n5318, n5319, n5320, n5321, - n5322, n5323, n5324, n5325, n5326, n5327, n5328, n5329, n5330, n5331, - n5332, n5333, n5334, n5335, n5336, n5337, n5338, n5339, n5340, n5341, - n5342, n5343, n5344, n5345, n5346, n5347, n5348, n5349, n5350, n5351, - n5352, n5353, n5354, n5355, n5356, n5357, n5358, n5359, n5360, n5361, - n5362, n5363, n5364, n5365, n5366, n5367, n5368, n5369, n5370, n5371, - n5372, n5373, n5374, n5375, n5376, n5377, n5378, n5379, n5380, n5381, - n5382, n5383, n5384, n5385, n5386, n5387, n5388, n5389, n5390, n5391, - n5392, n5393, n5394, n5395, n5396, n5397, n5398, n5399, n5400, n5401, - n5402, n5403, n5404, n5405, n5406, n5407, n5408, n5409, n5410, n5411, - n5412, n5413, n5414, n5415, n5416, n5417, n5418, n5419, n5420, n5421, - n5422, n5423, n5424, n5425, n5426, n5427, n5428, n5429, n5430, n5431, - n5432, n5433, n5434, n5435, n5436, n5437, n5438, n5439, n5440, n5441, - n5442, n5443, n5444, n5445, n5446, n5447, n5448, n5449, n5450, n5451, - n5452, n5453, n5454, n5455, n5456, n5457, n5458, n5459, n5460, n5461, - n5462, n5463, n5464, n5465, n5466, n5467, n5468, n5469, n5470, n5471, - n5472, n5473, n5474, n5475, n5476, n5477, n5478, n5479, n5480, n5481, - n5482, n5483, n5484, n5485, n5486, n5487, n5488, n5489, n5490, n5491, - n5492, n5493, n5494, n5495, n5496, n5497, n5498, n5499, n5500, n5501, - n5502, n5503, n5504, n5505, n5506, n5507, n5508, n5509, n5510, n5511, - n5512, n5513, n5514, n5515, n5516, n5517, n5518, n5519, n5520, n5521, - n5522, n5523, n5524, n5525, n5526, n5527, n5528, n5529, n5530, n5531, - n5532, n5533, n5534, n5535, n5536, n5537, n5538, n5539, n5540, n5541, - n5542, n5543, n5544, n5545, n5546, n5547, n5548, n5549, n5550, n5551, - n5552, n5553, n5554, n5555, n5556, n5557, n5558, n5559, n5560, n5561, - n5562, n5563, n5564, n5565, n5566, n5567, n5568, n5569, n5570, n5571, - n5572, n5573, n5574, n5575, n5576, n5577, n5578, n5579, n5580, n5581, - n5582, n5583, n5584, n5585, n5586, n5587, n5588, n5589, n5590, n5591, - n5592, n5593, n5594, n5595, n5596, n5597, n5598, n5599, n5600, n5601, - n5602, n5603, n5604, n5605, n5606, n5607, n5608, n5609, n5610, n5611, - n5612, n5613, n5614, n5615, n5616, n5617, n5618, n5619, n5620, n5621, - n5622, n5623, n5624, n5625, n5626, n5627, n5628, n5629, n5630, n5631, - n5632, n5633, n5634, n5635, n5636, n5637, n5638, n5639, n5640, n5641, - n5642, n5643, n5644, n5645, n5646, n5647, n5648, n5649, n5650, n5651, - n5652, n5653, n5654, n5655, n5656, n5657, n5658, n5659, n5660, n5661, - n5662, n5663, n5664, n5665, n5666, n5667, n5668, n5669, n5670, n5671, - n5672, n5673, n5674, n5675, n5676, n5677, n5678, n5679, n5680, n5681, - n5682, n5683, n5684, n5685, n5686, n5687, n5688, n5689, n5690, n5691, - n5692, n5693, n5694, n5695, n5696, n5697, n5698, n5699, n5700, n5701, - n5702, n5703, n5704, n5705, n5706, n5707, n5708, n5709, n5710, n5711, - n5712, n5713, n5714, n5715, n5716, n5717, n5718, n5719, n5720, n5721, - n5722, n5723, n5724, n5725, n5726, n5727, n5728, n5729, n5730, n5731, - n5732, n5733, n5734, n5735, n5736, n5737, n5738, n5739, n5740, n5741, - n5742, n5743, n5744, n5745, n5746, n5747, n5748, n5749, n5750, n5751, - n5752, n5753, n5754, n5755, n5756, n5757, n5758, n5759, n5760, n5761, - n5762, n5763, n5764, n5765, n5766, n5767, n5768, n5769, n5770, n5771, - n5772, n5773, n5774, n5775, n5776, n5777, n5778, n5779, n5780, n5781, - n5782, n5783, n5784, n5785, n5786, n5787, n5788, n5789, n5790, n5791, - n5792, n5793, n5794, n5795, n5796, n5797, n5798, n5799, n5800, n5801, - n5802, n5803, n5804, n5805, n5806, n5807, n5808, n5809, n5810, n5811, - n5812, n5813, n5814, n5815, n5816, n5817, n5818, n5819, n5820, n5821, - n5822, n5823, n5824, n5825, n5826, n5827, n5828, n5829, n5830, n5831, - n5832, n5833, n5834, n5835, n5836, n5837, n5838, n5839, n5840, n5841, - n5842, n5843, n5844, n5845, n5846, n5847, n5848, n5849, n5850, n5851, - n5852, n5853, n5854, n5855, n5856, n5857, n5858, n5859, n5860, n5861, - n5862, n5863, n5864, n5865, n5866, n5867, n5868, n5869, n5870, n5871, - n5872, n5873, n5874, n5875, n5876, n5877, n5878, n5879, n5880, n5881, - n5882, n5883, n5884, n5885, n5886, n5887, n5888, n5889, n5890, n5891, - n5892, n5893, n5894, n5895, n5896, n5897, n5898, n5899, n5900, n5901, - n5902, n5903, n5904, n5905, n5906, n5907, n5908, n5909, n5910, n5911, - n5912, n5913, n5914, n5915, n5916, n5917, n5918, n5919, n5920, n5921, - n5922, n5923, n5924, n5925, n5926, n5927, n5928, n5929, n5930, n5931, - n5932, n5933, n5934, n5935, n5936, n5937, n5938, n5939, n5940, n5941, - n5942, n5943, n5944, n5945, n5946, n5947, n5948, n5949, n5950, n5951, - n5952, n5953, n5954, n5955, n5956, n5957, n5958, n5959, n5960, n5961, - n5962, n5963, n5964, n5965, n5966, n5967, n5968, n5969, n5970, n5971, - n5972, n5973, n5974, n5975, n5976, n5977, n5978, n5979, n5980, n5981, - n5982, n5983, n5984, n5985, n5986, n5987, n5988, n5989, n5990, n5991, - n5992, n5993, n5994, n5995, n5996, n5997, n5998, n5999, n6000, n6001, - n6002, n6003, n6004, n6005, n6006, n6007, n6008, n6009, n6010, n6011, - n6012, n6013, n6014, n6015, n6016, n6017, n6018, n6019, n6020, n6021, - n6022, n6023, n6024, n6025, n6026, n6027, n6028, n6029, n6030, n6031, - n6032, n6033, n6034, n6035, n6036, n6037, n6038, n6039, n6040, n6041, - n6042, n6043, n6044, n6045, n6046, n6047, n6048, n6049, n6050, n6051, - n6052, n6053, n6054, n6055, n6056, n6057, n6058, n6059, n6060, n6061, - n6062, n6063, n6064, n6065, n6066, n6067, n6068, n6069, n6070, n6071, - n6072, n6073, n6074, n6075, n6076, n6077, n6078, n6079, n6080, n6081, - n6082, n6083, n6084, n6085, n6086, n6087, n6088, n6089, n6090, n6091, - n6092, n6093, n6094, n6095, n6096, n6097, n6098, n6099, n6100, n6101, - n6102, n6103, n6104, n6105, n6106, n6107, n6108, n6109, n6110, n6111, - n6112, n6113, n6114, n6115, n6116, n6117, n6118, n6119, n6120, n6121, - n6122, n6123, n6124, n6125, n6126, n6127, n6128, n6129, n6130, n6131, - n6132, n6133, n6134, n6135, n6136, n6137, n6138, n6139, n6140, n6141, - n6142, n6143, n6144, n6145, n6146, n6147, n6148, n6149, n6150, n6151, - n6152, n6153, n6154, n6155, n6156, n6157, n6158, n6159, n6160, n6161, - n6162, n6163, n6164, n6165, n6166, n6167, n6168, n6169, n6170, n6171, - n6172, n6173, n6174, n6175, n6176, n6177, n6178, n6179, n6180, n6181, - n6182, n6183, n6184, n6185, n6186, n6187, n6188, n6189, n6190, n6191, - n6192, n6193, n6194, n6195, n6196, n6197, n6198, n6199, n6200, n6201, - n6202, n6203, n6204, n6205, n6206, n6207, n6208, n6209, n6210, n6211, - n6212, n6213, n6214, n6215, n6216, n6217, n6218, n6219, n6220, n6221, - n6222, n6223, n6224, n6225, n6226, n6227, n6228, n6229, n6230, n6231, - n6232, n6233, n6234, n6235, n6236, n6237, n6238, n6239, n6240, n6241, - n6242, n6243, n6244, n6245, n6246, n6247, n6248, n6249, n6250, n6251, - n6252, n6253, n6254, n6255, n6256, n6257, n6258, n6259, n6260, n6261, - n6262, n6263, n6264, n6265, n6266, n6267, n6268, n6269, n6270, n6271, - n6272, n6273, n6274, n6275, n6276, n6277, n6278, n6279, n6280, n6281, - n6282, n6283, n6284, n6285, n6286, n6287, n6288, n6289, n6290, n6291, - n6292, n6293, n6294, n6295, n6296, n6297, n6298, n6299, n6300, n6301, - n6302, n6303, n6304, n6305, n6306, n6307, n6308, n6309, n6310, n6311, - n6312, n6313, n6314, n6315, n6316, n6317, n6318, n6319, n6320, n6321, - n6322, n6323, n6324, n6325, n6326, n6327, n6328, n6329, n6330, n6331, - n6332, n6333, n6334, n6335, n6336, n6337, n6338, n6339, n6340, n6341, - n6342, n6343, n6344, n6345, n6346, n6347, n6348, n6349, n6350, n6351, - n6352, n6353, n6354, n6355, n6356, n6357, n6358, n6359, n6360, n6361, - n6362, n6363, n6364, n6365, n6366, n6367, n6368, n6369, n6370, n6371, - n6372, n6373, n6374, n6375, n6376, n6377, n6378, n6379, n6380, n6381, - n6382, n6383, n6384, n6385, n6386, n6387, n6388, n6389, n6390, n6391, - n6392, n6393, n6394, n6395, n6396, n6397, n6398, n6399, n6400, n6401, - n6402, n6403, n6404, n6405; - -assign po001 = pi187; - -assign po015 = po003; - -assign po004 = pi106; - -assign po009 = pi136; - -assign po010 = pi022; - -assign po011 = pi112; - -assign po005 = po012; - -assign po013 = pi062; - -assign po014 = pi123; - -assign po101 = po023; - -assign po067 = po023; - -assign po066 = po023; - -assign po023 = pi119; - -assign po024 = pi152; - -assign po025 = pi125; - -assign po027 = pi102; - -assign po028 = pi031; - -assign po031 = pi155; - -assign po065 = po034; - -assign po035 = pi182; - -assign po036 = pi023; - -assign po038 = pi071; - -assign po039 = pi015; - -assign po040 = pi132; - -assign po044 = pi044; - -assign po052 = pi048; - -assign po057 = pi117; - -assign po059 = pi091; - -assign po063 = pi000; - -assign po064 = pi194; - -assign po069 = pi147; - -assign po070 = pi002; - -assign po071 = pi080; - -assign po072 = pi188; - -assign po018 = po074; - -assign po021 = po074; - -assign po079 = pi084; - -assign po082 = pi144; - -assign po084 = pi199; - -assign po085 = pi066; - -assign po091 = pi008; - -assign po092 = pi154; - -assign po099 = pi042; - -assign po102 = pi179; - -assign po103 = pi145; - -assign po104 = pi127; - -assign po106 = pi105; - -assign po107 = pi029; - -assign po020 = po041; - -assign po032 = po007; - -assign po089 = po076; - -assign po054 = po076; - - OR2 U2865 ( .A(n2822), .B(n2823), .Z(po100)); - AN2 U2866 ( .A(n2824), .B(pi192), .Z(n2823)); - OR2 U2867 ( .A(n2825), .B(n2826), .Z(n2824)); - AN2 U2868 ( .A(n2827), .B(n2828), .Z(n2826)); - IV2 U2869 ( .A(n2829), .Z(n2825)); - OR2 U2870 ( .A(n2828), .B(n2827), .Z(n2829)); - OR2 U2871 ( .A(n2830), .B(n2831), .Z(n2827)); - AN2 U2872 ( .A(n2832), .B(n2833), .Z(n2831)); - AN2 U2873 ( .A(n2834), .B(n2835), .Z(n2830)); - AN2 U2874 ( .A(n2836), .B(n2837), .Z(n2822)); - OR2 U2875 ( .A(n2838), .B(n2839), .Z(n2836)); - AN2 U2876 ( .A(n2840), .B(n2828), .Z(n2839)); - IV2 U2877 ( .A(n2841), .Z(n2838)); - OR2 U2878 ( .A(n2828), .B(n2840), .Z(n2841)); - OR2 U2879 ( .A(n2842), .B(n2843), .Z(n2840)); - AN2 U2880 ( .A(n2844), .B(n2845), .Z(n2843)); - AN2 U2881 ( .A(n2846), .B(n2847), .Z(n2842)); - AN2 U2882 ( .A(n2848), .B(n2849), .Z(n2828)); - IV2 U2883 ( .A(n2850), .Z(n2849)); - AN2 U2884 ( .A(n2851), .B(n2852), .Z(n2850)); - OR2 U2885 ( .A(n2852), .B(n2851), .Z(n2848)); - OR2 U2886 ( .A(n2853), .B(n2854), .Z(n2851)); - AN2 U2887 ( .A(n2855), .B(n2856), .Z(n2854)); - IV2 U2888 ( .A(n2857), .Z(n2853)); - OR2 U2889 ( .A(n2856), .B(n2855), .Z(n2857)); - IV2 U2890 ( .A(n2858), .Z(n2855)); - OR2 U2891 ( .A(n2859), .B(n2860), .Z(n2858)); - AN2 U2892 ( .A(n2861), .B(n2862), .Z(n2859)); - OR2 U2893 ( .A(n2863), .B(n2864), .Z(n2856)); - OR2 U2894 ( .A(n2865), .B(n2866), .Z(n2864)); - AN2 U2895 ( .A(pi192), .B(n2867), .Z(n2866)); - OR2 U2896 ( .A(n2868), .B(n2869), .Z(n2867)); - OR2 U2897 ( .A(n2870), .B(n2871), .Z(n2869)); - AN2 U2898 ( .A(n2872), .B(n2873), .Z(n2871)); - AN2 U2899 ( .A(n2862), .B(n2874), .Z(n2872)); - OR2 U2900 ( .A(n2875), .B(n2876), .Z(n2874)); - AN2 U2901 ( .A(n2877), .B(n2878), .Z(n2875)); - AN2 U2902 ( .A(n2879), .B(n2880), .Z(n2870)); - AN2 U2903 ( .A(n2881), .B(n2882), .Z(n2868)); - OR2 U2904 ( .A(n2883), .B(n2884), .Z(n2881)); - AN2 U2905 ( .A(n2885), .B(n2886), .Z(n2884)); - AN2 U2906 ( .A(n2879), .B(n2887), .Z(n2883)); - IV2 U2907 ( .A(n2873), .Z(n2879)); - OR2 U2908 ( .A(n2888), .B(n2889), .Z(n2873)); - AN2 U2909 ( .A(n2890), .B(n2891), .Z(n2889)); - AN2 U2910 ( .A(n2892), .B(n2886), .Z(n2888)); - AN2 U2911 ( .A(n2893), .B(n2837), .Z(n2865)); - OR2 U2912 ( .A(n2894), .B(n2895), .Z(n2893)); - OR2 U2913 ( .A(n2896), .B(n2897), .Z(n2895)); - OR2 U2914 ( .A(n2898), .B(n2899), .Z(n2897)); - AN2 U2915 ( .A(n2900), .B(n2901), .Z(n2899)); - AN2 U2916 ( .A(n2902), .B(n2903), .Z(n2900)); - OR2 U2917 ( .A(n2904), .B(n2905), .Z(n2903)); - OR2 U2918 ( .A(n2906), .B(n2907), .Z(n2905)); - AN2 U2919 ( .A(n2890), .B(n2908), .Z(n2907)); - AN2 U2920 ( .A(n2909), .B(n2886), .Z(n2906)); - AN2 U2921 ( .A(n2910), .B(pi082), .Z(n2909)); - AN2 U2922 ( .A(pi200), .B(n2911), .Z(n2898)); - OR2 U2923 ( .A(n2912), .B(n2913), .Z(n2911)); - OR2 U2924 ( .A(n2914), .B(n2915), .Z(n2913)); - AN2 U2925 ( .A(n2916), .B(n2890), .Z(n2915)); - AN2 U2926 ( .A(n2910), .B(n2917), .Z(n2916)); - OR2 U2927 ( .A(n2918), .B(n2919), .Z(n2917)); - AN2 U2928 ( .A(n2920), .B(n2886), .Z(n2914)); - OR2 U2929 ( .A(n2921), .B(n2922), .Z(n2920)); - OR2 U2930 ( .A(n2923), .B(n2924), .Z(n2922)); - AN2 U2931 ( .A(n2918), .B(n2860), .Z(n2924)); - AN2 U2932 ( .A(n2925), .B(n2926), .Z(n2923)); - OR2 U2933 ( .A(n2927), .B(n2928), .Z(n2926)); - AN2 U2934 ( .A(n2844), .B(n2929), .Z(n2928)); - AN2 U2935 ( .A(n2930), .B(n2931), .Z(n2927)); - OR2 U2936 ( .A(n2932), .B(n2933), .Z(n2921)); - AN2 U2937 ( .A(n2934), .B(n2935), .Z(n2933)); - AN2 U2938 ( .A(n2936), .B(n2910), .Z(n2934)); - AN2 U2939 ( .A(n2937), .B(n2938), .Z(n2932)); - AN2 U2940 ( .A(n2929), .B(n2939), .Z(n2937)); - AN2 U2941 ( .A(n2935), .B(n2940), .Z(n2912)); - OR2 U2942 ( .A(n2904), .B(n2941), .Z(n2940)); - AN2 U2943 ( .A(n2890), .B(n2942), .Z(n2941)); - AN2 U2944 ( .A(n2943), .B(n2944), .Z(n2942)); - OR2 U2945 ( .A(n2945), .B(n2946), .Z(n2944)); - IV2 U2946 ( .A(n2910), .Z(n2945)); - OR2 U2947 ( .A(n2936), .B(n2947), .Z(n2943)); - IV2 U2948 ( .A(n2948), .Z(n2904)); - OR2 U2949 ( .A(n2949), .B(n2939), .Z(n2948)); - AN2 U2950 ( .A(n2950), .B(n2951), .Z(n2949)); - OR2 U2951 ( .A(n2890), .B(n2947), .Z(n2951)); - OR2 U2952 ( .A(n2929), .B(n2886), .Z(n2950)); - AN2 U2953 ( .A(n2952), .B(n2953), .Z(n2896)); - AN2 U2954 ( .A(n2954), .B(n2955), .Z(n2953)); - OR2 U2955 ( .A(n2956), .B(n2957), .Z(n2955)); - AN2 U2956 ( .A(n2890), .B(n2958), .Z(n2956)); - OR2 U2957 ( .A(n2959), .B(n2960), .Z(n2958)); - OR2 U2958 ( .A(pi082), .B(n2961), .Z(n2954)); - AN2 U2959 ( .A(n2901), .B(n2886), .Z(n2961)); - AN2 U2960 ( .A(n2910), .B(n2962), .Z(n2952)); - AN2 U2961 ( .A(n2947), .B(n2862), .Z(n2910)); - OR2 U2962 ( .A(n2963), .B(n2964), .Z(n2894)); - AN2 U2963 ( .A(n2965), .B(n2890), .Z(n2964)); - AN2 U2964 ( .A(n2929), .B(n2966), .Z(n2965)); - OR2 U2965 ( .A(n2967), .B(n2968), .Z(n2966)); - AN2 U2966 ( .A(n2969), .B(n2901), .Z(n2967)); - OR2 U2967 ( .A(n2970), .B(n2971), .Z(n2969)); - OR2 U2968 ( .A(n2972), .B(n2973), .Z(n2971)); - AN2 U2969 ( .A(n2902), .B(n2962), .Z(n2973)); - AN2 U2970 ( .A(n2974), .B(n2957), .Z(n2972)); - AN2 U2971 ( .A(pi082), .B(po031), .Z(n2970)); - AN2 U2972 ( .A(n2975), .B(n2886), .Z(n2963)); - OR2 U2973 ( .A(n2976), .B(n2977), .Z(n2975)); - AN2 U2974 ( .A(n2968), .B(n2947), .Z(n2977)); - AN2 U2975 ( .A(n2978), .B(n2979), .Z(n2968)); - OR2 U2976 ( .A(n2980), .B(n2981), .Z(n2979)); - AN2 U2977 ( .A(n2982), .B(n2931), .Z(n2980)); - AN2 U2978 ( .A(n2983), .B(n2929), .Z(n2976)); - AN2 U2979 ( .A(n2984), .B(n2936), .Z(n2983)); - AN2 U2980 ( .A(n2974), .B(n2901), .Z(n2984)); - OR2 U2981 ( .A(n2985), .B(n2986), .Z(n2863)); - AN2 U2982 ( .A(n2987), .B(n2890), .Z(n2986)); - AN2 U2983 ( .A(n2988), .B(n2989), .Z(n2987)); - AN2 U2984 ( .A(n2990), .B(n2962), .Z(n2989)); - AN2 U2985 ( .A(n2862), .B(n2877), .Z(n2988)); - AN2 U2986 ( .A(n2991), .B(n2886), .Z(n2985)); - OR2 U2987 ( .A(n2992), .B(n2993), .Z(n2991)); - AN2 U2988 ( .A(n2994), .B(n2995), .Z(n2993)); - AN2 U2989 ( .A(n2990), .B(n2901), .Z(n2995)); - AN2 U2990 ( .A(n2996), .B(n2974), .Z(n2994)); - OR2 U2991 ( .A(po031), .B(n2930), .Z(n2996)); - AN2 U2992 ( .A(n2997), .B(n2860), .Z(n2992)); - AN2 U2993 ( .A(n2998), .B(n2930), .Z(n2860)); - AN2 U2994 ( .A(n2877), .B(n2999), .Z(n2997)); - IV2 U2995 ( .A(n2882), .Z(n2877)); - AN2 U2996 ( .A(n3000), .B(n3001), .Z(n2852)); - OR2 U2997 ( .A(n3002), .B(n2925), .Z(n3001)); - OR2 U2998 ( .A(n3003), .B(n3004), .Z(n3000)); - IV2 U2999 ( .A(n3002), .Z(n3004)); - OR2 U3000 ( .A(n3005), .B(n3006), .Z(n3002)); - AN2 U3001 ( .A(n3007), .B(n3008), .Z(n3006)); - OR2 U3002 ( .A(n3009), .B(n3010), .Z(n3008)); - AN2 U3003 ( .A(n3011), .B(n3012), .Z(n3009)); - AN2 U3004 ( .A(n3013), .B(n3014), .Z(n3007)); - OR2 U3005 ( .A(n3015), .B(n3016), .Z(n3014)); - IV2 U3006 ( .A(n3017), .Z(n3016)); - OR2 U3007 ( .A(n3017), .B(n3018), .Z(n3013)); - OR2 U3008 ( .A(n3019), .B(n3020), .Z(n3017)); - AN2 U3009 ( .A(n3021), .B(n3022), .Z(n3020)); - OR2 U3010 ( .A(n3023), .B(n3024), .Z(n3022)); - OR2 U3011 ( .A(n3025), .B(n3026), .Z(n3024)); - OR2 U3012 ( .A(n3027), .B(n3028), .Z(n3026)); - AN2 U3013 ( .A(po010), .B(n3029), .Z(n3028)); - AN2 U3014 ( .A(n3030), .B(pi192), .Z(n3027)); - AN2 U3015 ( .A(n3031), .B(n3032), .Z(n3030)); - OR2 U3016 ( .A(n3033), .B(n3034), .Z(n3032)); - AN2 U3017 ( .A(n3035), .B(n3036), .Z(n3034)); - AN2 U3018 ( .A(n3015), .B(n3037), .Z(n3035)); - OR2 U3019 ( .A(n3038), .B(n3039), .Z(n3031)); - OR2 U3020 ( .A(n3040), .B(n3041), .Z(n3039)); - AN2 U3021 ( .A(po010), .B(n3042), .Z(n3040)); - OR2 U3022 ( .A(n3043), .B(n3044), .Z(n3025)); - AN2 U3023 ( .A(n3015), .B(n3045), .Z(n3044)); - OR2 U3024 ( .A(n3046), .B(n3047), .Z(n3045)); - AN2 U3025 ( .A(n3048), .B(n3049), .Z(n3047)); - OR2 U3026 ( .A(n3050), .B(n3051), .Z(n3048)); - AN2 U3027 ( .A(n3052), .B(po070), .Z(n3051)); - AN2 U3028 ( .A(n3053), .B(po099), .Z(n3050)); - AN2 U3029 ( .A(n3054), .B(n3055), .Z(n3046)); - AN2 U3030 ( .A(n3018), .B(n3056), .Z(n3043)); - OR2 U3031 ( .A(n3057), .B(n3058), .Z(n3056)); - OR2 U3032 ( .A(n3059), .B(n3060), .Z(n3058)); - AN2 U3033 ( .A(n3061), .B(n3042), .Z(n3060)); - AN2 U3034 ( .A(n3062), .B(n3063), .Z(n3059)); - AN2 U3035 ( .A(n3064), .B(n3049), .Z(n3062)); - AN2 U3036 ( .A(n3065), .B(n3066), .Z(n3057)); - OR2 U3037 ( .A(n3067), .B(n3068), .Z(n3023)); - OR2 U3038 ( .A(n3069), .B(n3070), .Z(n3068)); - AN2 U3039 ( .A(n3071), .B(n3072), .Z(n3070)); - AN2 U3040 ( .A(n3053), .B(n3073), .Z(n3069)); - OR2 U3041 ( .A(n3074), .B(n3075), .Z(n3067)); - AN2 U3042 ( .A(n3076), .B(n3077), .Z(n3075)); - OR2 U3043 ( .A(n3078), .B(n3079), .Z(n3077)); - AN2 U3044 ( .A(n3080), .B(n3066), .Z(n3078)); - AN2 U3045 ( .A(n3081), .B(n3061), .Z(n3074)); - AN2 U3046 ( .A(n3082), .B(n3038), .Z(n3081)); - AN2 U3047 ( .A(n3083), .B(n3084), .Z(n3019)); - OR2 U3048 ( .A(n3085), .B(n3086), .Z(n3084)); - OR2 U3049 ( .A(n3087), .B(n3088), .Z(n3086)); - OR2 U3050 ( .A(n3089), .B(n3090), .Z(n3088)); - AN2 U3051 ( .A(n3091), .B(n3049), .Z(n3089)); - OR2 U3052 ( .A(n3092), .B(n3093), .Z(n3087)); - AN2 U3053 ( .A(n3015), .B(n3094), .Z(n3093)); - OR2 U3054 ( .A(n3095), .B(n3096), .Z(n3094)); - OR2 U3055 ( .A(n3097), .B(n3098), .Z(n3096)); - AN2 U3056 ( .A(n3099), .B(n3100), .Z(n3098)); - AN2 U3057 ( .A(po010), .B(po070), .Z(n3099)); - AN2 U3058 ( .A(n3101), .B(pi192), .Z(n3097)); - AN2 U3059 ( .A(n3041), .B(n3038), .Z(n3101)); - OR2 U3060 ( .A(n3102), .B(n3103), .Z(n3041)); - AN2 U3061 ( .A(n3104), .B(pi166), .Z(n3103)); - AN2 U3062 ( .A(n3037), .B(n3049), .Z(n3104)); - AN2 U3063 ( .A(n3105), .B(n3106), .Z(n3102)); - OR2 U3064 ( .A(n3107), .B(n3042), .Z(n3105)); - AN2 U3065 ( .A(po010), .B(n3108), .Z(n3107)); - AN2 U3066 ( .A(n3079), .B(n3109), .Z(n3095)); - OR2 U3067 ( .A(n3110), .B(n3111), .Z(n3079)); - AN2 U3068 ( .A(n3071), .B(n3112), .Z(n3111)); - AN2 U3069 ( .A(n3065), .B(n3113), .Z(n3110)); - OR2 U3070 ( .A(n3114), .B(n3066), .Z(n3113)); - AN2 U3071 ( .A(po010), .B(n3115), .Z(n3114)); - AN2 U3072 ( .A(n3018), .B(n3116), .Z(n3092)); - OR2 U3073 ( .A(n3117), .B(n3118), .Z(n3116)); - AN2 U3074 ( .A(n3065), .B(n3119), .Z(n3118)); - AN2 U3075 ( .A(n3063), .B(n3120), .Z(n3117)); - OR2 U3076 ( .A(n3121), .B(n3122), .Z(n3085)); - OR2 U3077 ( .A(n3123), .B(n3124), .Z(n3122)); - AN2 U3078 ( .A(n3125), .B(n3055), .Z(n3124)); - AN2 U3079 ( .A(n3076), .B(n3112), .Z(n3125)); - AN2 U3080 ( .A(n3126), .B(n3127), .Z(n3123)); - AN2 U3081 ( .A(n3033), .B(n3037), .Z(n3126)); - AN2 U3082 ( .A(n3080), .B(n3072), .Z(n3121)); - AN2 U3083 ( .A(n3119), .B(n3018), .Z(n3072)); - AN2 U3084 ( .A(n3128), .B(n3129), .Z(n3005)); - OR2 U3085 ( .A(n3130), .B(n3131), .Z(n3129)); - OR2 U3086 ( .A(n3132), .B(n3133), .Z(n3131)); - AN2 U3087 ( .A(n3134), .B(pi192), .Z(n3133)); - AN2 U3088 ( .A(n3135), .B(n3136), .Z(n3134)); - OR2 U3089 ( .A(n3137), .B(po044), .Z(n3135)); - AN2 U3090 ( .A(n3138), .B(n2886), .Z(n3137)); - AN2 U3091 ( .A(n3139), .B(n2837), .Z(n3132)); - AN2 U3092 ( .A(n3140), .B(n3141), .Z(n3139)); - OR2 U3093 ( .A(n3142), .B(po044), .Z(n3140)); - AN2 U3094 ( .A(n3143), .B(n2886), .Z(n3142)); - AN2 U3095 ( .A(n3144), .B(n3145), .Z(n3130)); - OR2 U3096 ( .A(n3146), .B(n3147), .Z(n3145)); - IV2 U3097 ( .A(n3012), .Z(n3144)); - AN2 U3098 ( .A(n3148), .B(n3149), .Z(n3128)); - OR2 U3099 ( .A(n3150), .B(n3018), .Z(n3149)); - OR2 U3100 ( .A(n3015), .B(n3151), .Z(n3148)); - IV2 U3101 ( .A(n3150), .Z(n3151)); - OR2 U3102 ( .A(n3152), .B(n3153), .Z(n3150)); - AN2 U3103 ( .A(n3021), .B(n3154), .Z(n3153)); - AN2 U3104 ( .A(n3155), .B(n3083), .Z(n3152)); - IV2 U3105 ( .A(n3154), .Z(n3155)); - OR2 U3106 ( .A(n3156), .B(n3157), .Z(n3154)); - OR2 U3107 ( .A(n3091), .B(n3158), .Z(n3157)); - OR2 U3108 ( .A(n3159), .B(n3160), .Z(n3158)); - AN2 U3109 ( .A(n3161), .B(n3049), .Z(n3160)); - OR2 U3110 ( .A(n3162), .B(n3029), .Z(n3161)); - OR2 U3111 ( .A(n3163), .B(n3164), .Z(n3029)); - AN2 U3112 ( .A(po099), .B(n3165), .Z(n3164)); - OR2 U3113 ( .A(n3166), .B(n3167), .Z(n3165)); - OR2 U3114 ( .A(n3168), .B(n3169), .Z(n3167)); - AN2 U3115 ( .A(n3170), .B(pi192), .Z(n3169)); - AN2 U3116 ( .A(n3038), .B(n3171), .Z(n3170)); - AN2 U3117 ( .A(n3054), .B(n2837), .Z(n3168)); - AN2 U3118 ( .A(n3172), .B(n3173), .Z(n3166)); - AN2 U3119 ( .A(n3015), .B(n3109), .Z(n3172)); - AN2 U3120 ( .A(n3100), .B(n3018), .Z(n3163)); - AN2 U3121 ( .A(n3015), .B(n3174), .Z(n3162)); - OR2 U3122 ( .A(n3175), .B(n3176), .Z(n3174)); - AN2 U3123 ( .A(n3054), .B(n3173), .Z(n3176)); - AN2 U3124 ( .A(n3177), .B(n3109), .Z(n3054)); - AN2 U3125 ( .A(n3178), .B(n3064), .Z(n3175)); - AN2 U3126 ( .A(n3038), .B(n3037), .Z(n3178)); - AN2 U3127 ( .A(po010), .B(n3179), .Z(n3159)); - OR2 U3128 ( .A(n3090), .B(n3180), .Z(n3179)); - OR2 U3129 ( .A(n3181), .B(n3182), .Z(n3180)); - AN2 U3130 ( .A(n3053), .B(n3183), .Z(n3182)); - OR2 U3131 ( .A(n3184), .B(n3119), .Z(n3183)); - AN2 U3132 ( .A(pi141), .B(n3015), .Z(n3184)); - AN2 U3133 ( .A(n3109), .B(n3065), .Z(n3053)); - AN2 U3134 ( .A(n3185), .B(n3061), .Z(n3181)); - AN2 U3135 ( .A(n3186), .B(n3038), .Z(n3185)); - OR2 U3136 ( .A(n3187), .B(n3063), .Z(n3186)); - AN2 U3137 ( .A(pi033), .B(n3015), .Z(n3187)); - OR2 U3138 ( .A(n3188), .B(n3189), .Z(n3090)); - AN2 U3139 ( .A(n3190), .B(n3065), .Z(n3189)); - AN2 U3140 ( .A(n3073), .B(n3076), .Z(n3190)); - AN2 U3141 ( .A(n3191), .B(n3061), .Z(n3188)); - AN2 U3142 ( .A(n3082), .B(n3033), .Z(n3191)); - OR2 U3143 ( .A(n3192), .B(n3193), .Z(n3091)); - OR2 U3144 ( .A(n3194), .B(n3195), .Z(n3193)); - AN2 U3145 ( .A(n3052), .B(n3018), .Z(n3195)); - AN2 U3146 ( .A(n3064), .B(n3196), .Z(n3194)); - OR2 U3147 ( .A(n3197), .B(n3198), .Z(n3196)); - AN2 U3148 ( .A(n3082), .B(n3199), .Z(n3198)); - AN2 U3149 ( .A(n3042), .B(n3033), .Z(n3197)); - OR2 U3150 ( .A(n3200), .B(n3201), .Z(n3192)); - AN2 U3151 ( .A(n3173), .B(n3202), .Z(n3201)); - OR2 U3152 ( .A(n3203), .B(n3204), .Z(n3202)); - AN2 U3153 ( .A(n3073), .B(n3205), .Z(n3204)); - AN2 U3154 ( .A(n3076), .B(n3066), .Z(n3203)); - AN2 U3155 ( .A(n3206), .B(po099), .Z(n3200)); - AN2 U3156 ( .A(po070), .B(n3207), .Z(n3206)); - OR2 U3157 ( .A(n3208), .B(n3209), .Z(n3156)); - AN2 U3158 ( .A(n3210), .B(n3055), .Z(n3209)); - AN2 U3159 ( .A(n3076), .B(n3115), .Z(n3210)); - AN2 U3160 ( .A(n3211), .B(n3127), .Z(n3208)); - AN2 U3161 ( .A(n3033), .B(n3108), .Z(n3211)); - OR2 U3162 ( .A(n3212), .B(n3213), .Z(po098)); - AN2 U3163 ( .A(n3214), .B(pi192), .Z(n3213)); - OR2 U3164 ( .A(n3215), .B(n3216), .Z(n3214)); - AN2 U3165 ( .A(n2832), .B(n2901), .Z(n3216)); - IV2 U3166 ( .A(n2835), .Z(n2832)); - AN2 U3167 ( .A(pi200), .B(n2835), .Z(n3215)); - OR2 U3168 ( .A(n2880), .B(n2876), .Z(n2835)); - AN2 U3169 ( .A(n3217), .B(n2837), .Z(n3212)); - OR2 U3170 ( .A(n3218), .B(n3219), .Z(n3217)); - AN2 U3171 ( .A(n3220), .B(n2847), .Z(n3219)); - OR2 U3172 ( .A(n3221), .B(n2902), .Z(n3220)); - AN2 U3173 ( .A(pi200), .B(n2938), .Z(n3221)); - AN2 U3174 ( .A(n2844), .B(n3222), .Z(n3218)); - IV2 U3175 ( .A(n2847), .Z(n2844)); - OR2 U3176 ( .A(n2936), .B(n2978), .Z(n2847)); - OR2 U3177 ( .A(n3223), .B(n3224), .Z(po097)); - AN2 U3178 ( .A(n3225), .B(n3226), .Z(n3224)); - OR2 U3179 ( .A(n3227), .B(n3228), .Z(n3226)); - OR2 U3180 ( .A(n3229), .B(n3230), .Z(n3228)); - OR2 U3181 ( .A(n3231), .B(n3232), .Z(n3230)); - AN2 U3182 ( .A(n3233), .B(n3234), .Z(n3232)); - AN2 U3183 ( .A(n3235), .B(n3236), .Z(n3231)); - OR2 U3184 ( .A(n3237), .B(n3238), .Z(n3227)); - OR2 U3185 ( .A(n3239), .B(n3240), .Z(n3238)); - AN2 U3186 ( .A(n3241), .B(n3242), .Z(n3240)); - AN2 U3187 ( .A(n3243), .B(n3244), .Z(n3239)); - AN2 U3188 ( .A(po082), .B(n3245), .Z(n3237)); - AN2 U3189 ( .A(n3246), .B(n3247), .Z(n3223)); - OR2 U3190 ( .A(n3248), .B(n3249), .Z(n3246)); - AN2 U3191 ( .A(n3250), .B(n3251), .Z(n3249)); - OR2 U3192 ( .A(n3252), .B(n3253), .Z(po096)); - AN2 U3193 ( .A(n3254), .B(n3255), .Z(n3252)); - OR2 U3194 ( .A(n3256), .B(n3257), .Z(n3254)); - AN2 U3195 ( .A(n3258), .B(n3259), .Z(n3256)); - AN2 U3196 ( .A(n3260), .B(n3261), .Z(n3258)); - OR2 U3197 ( .A(n3262), .B(n3263), .Z(n3260)); - AN2 U3198 ( .A(n3264), .B(n3265), .Z(n3262)); - OR2 U3199 ( .A(n3266), .B(n3267), .Z(po095)); - OR2 U3200 ( .A(n3268), .B(n3269), .Z(n3267)); - AN2 U3201 ( .A(n3270), .B(n3119), .Z(n3269)); - OR2 U3202 ( .A(n3271), .B(n3272), .Z(n3270)); - AN2 U3203 ( .A(n3273), .B(n2837), .Z(n3272)); - AN2 U3204 ( .A(n3065), .B(n3274), .Z(n3271)); - AN2 U3205 ( .A(n3063), .B(n3275), .Z(n3268)); - OR2 U3206 ( .A(n3276), .B(n3277), .Z(n3275)); - AN2 U3207 ( .A(n3273), .B(pi192), .Z(n3277)); - AN2 U3208 ( .A(n3061), .B(n3274), .Z(n3276)); - OR2 U3209 ( .A(n3278), .B(n3279), .Z(n3266)); - AN2 U3210 ( .A(n3280), .B(n3281), .Z(n3279)); - OR2 U3211 ( .A(n3282), .B(n3100), .Z(n3281)); - AN2 U3212 ( .A(n3283), .B(n3284), .Z(n3278)); - OR2 U3213 ( .A(n3285), .B(n3052), .Z(n3283)); - AN2 U3214 ( .A(n3286), .B(n3287), .Z(n3052)); - AN2 U3215 ( .A(po099), .B(n3207), .Z(n3285)); - AN2 U3216 ( .A(n3288), .B(n3289), .Z(po094)); - OR2 U3217 ( .A(n3290), .B(n3291), .Z(n3289)); - OR2 U3218 ( .A(n3234), .B(n3292), .Z(n3288)); - OR2 U3219 ( .A(n3293), .B(n3294), .Z(po093)); - AN2 U3220 ( .A(n3295), .B(n3296), .Z(n3294)); - OR2 U3221 ( .A(n3297), .B(n3298), .Z(n3296)); - AN2 U3222 ( .A(n3299), .B(n3300), .Z(n3297)); - AN2 U3223 ( .A(n3301), .B(n3302), .Z(n3293)); - IV2 U3224 ( .A(n3303), .Z(n3302)); - AN2 U3225 ( .A(n3304), .B(n3299), .Z(n3303)); - OR2 U3226 ( .A(n3305), .B(n3306), .Z(n3299)); - OR2 U3227 ( .A(n3300), .B(n3298), .Z(n3304)); - AN2 U3228 ( .A(n3305), .B(n3306), .Z(n3298)); - OR2 U3229 ( .A(n3307), .B(n3308), .Z(po090)); - OR2 U3230 ( .A(n3309), .B(n3310), .Z(n3308)); - AN2 U3231 ( .A(n3311), .B(n3312), .Z(n3310)); - AN2 U3232 ( .A(n3313), .B(n3314), .Z(n3309)); - OR2 U3233 ( .A(n3315), .B(n3316), .Z(n3313)); - OR2 U3234 ( .A(n3317), .B(n3318), .Z(n3316)); - AN2 U3235 ( .A(n3319), .B(n3320), .Z(n3315)); - OR2 U3236 ( .A(n3321), .B(n3322), .Z(n3319)); - OR2 U3237 ( .A(n3323), .B(n3324), .Z(n3307)); - AN2 U3238 ( .A(n3325), .B(n3326), .Z(n3324)); - AN2 U3239 ( .A(n3327), .B(n3328), .Z(n3323)); - OR2 U3240 ( .A(n3329), .B(n3330), .Z(n3327)); - OR2 U3241 ( .A(n3331), .B(n3332), .Z(po088)); - IV2 U3242 ( .A(n3333), .Z(n3332)); - OR2 U3243 ( .A(n3334), .B(n3335), .Z(n3333)); - AN2 U3244 ( .A(n3335), .B(n3334), .Z(n3331)); - AN2 U3245 ( .A(n3336), .B(n3337), .Z(n3334)); - OR2 U3246 ( .A(n3338), .B(n3339), .Z(n3337)); - IV2 U3247 ( .A(n3340), .Z(n3338)); - OR2 U3248 ( .A(n3341), .B(n3340), .Z(n3336)); - OR2 U3249 ( .A(n3342), .B(n3343), .Z(n3340)); - AN2 U3250 ( .A(n3291), .B(n3250), .Z(n3343)); - AN2 U3251 ( .A(n3344), .B(n3292), .Z(n3342)); - OR2 U3252 ( .A(n3345), .B(n3346), .Z(n3335)); - IV2 U3253 ( .A(n3347), .Z(n3346)); - OR2 U3254 ( .A(n3348), .B(n3349), .Z(n3347)); - AN2 U3255 ( .A(n3349), .B(n3348), .Z(n3345)); - AN2 U3256 ( .A(n3350), .B(n3351), .Z(n3348)); - OR2 U3257 ( .A(n3352), .B(n3353), .Z(n3351)); - IV2 U3258 ( .A(n3354), .Z(n3353)); - OR2 U3259 ( .A(n3354), .B(n3355), .Z(n3350)); - OR2 U3260 ( .A(n3356), .B(n3357), .Z(n3354)); - OR2 U3261 ( .A(n3358), .B(n3359), .Z(n3357)); - AN2 U3262 ( .A(n3360), .B(n3361), .Z(n3359)); - AN2 U3263 ( .A(n3362), .B(n3363), .Z(n3360)); - OR2 U3264 ( .A(n3364), .B(n3365), .Z(n3362)); - OR2 U3265 ( .A(n3366), .B(n3367), .Z(n3365)); - AN2 U3266 ( .A(n3368), .B(n3369), .Z(n3367)); - AN2 U3267 ( .A(n3370), .B(n3371), .Z(n3368)); - AN2 U3268 ( .A(n3372), .B(n3373), .Z(n3366)); - AN2 U3269 ( .A(n3374), .B(n3375), .Z(n3372)); - OR2 U3270 ( .A(n3376), .B(n3377), .Z(n3374)); - OR2 U3271 ( .A(n3378), .B(n3379), .Z(n3377)); - AN2 U3272 ( .A(n2837), .B(n3380), .Z(n3379)); - AN2 U3273 ( .A(pi060), .B(n3381), .Z(n3378)); - AN2 U3274 ( .A(n3382), .B(n3369), .Z(n3364)); - AN2 U3275 ( .A(n3369), .B(n3383), .Z(n3358)); - OR2 U3276 ( .A(n3384), .B(n3385), .Z(n3383)); - OR2 U3277 ( .A(n3386), .B(n3387), .Z(n3385)); - AN2 U3278 ( .A(n3370), .B(n3388), .Z(n3387)); - OR2 U3279 ( .A(n3389), .B(n3390), .Z(n3388)); - AN2 U3280 ( .A(n3391), .B(n3392), .Z(n3390)); - AN2 U3281 ( .A(n3393), .B(n3394), .Z(n3386)); - OR2 U3282 ( .A(n3395), .B(n3396), .Z(n3394)); - OR2 U3283 ( .A(n3321), .B(n3397), .Z(n3396)); - AN2 U3284 ( .A(n3398), .B(n3399), .Z(n3397)); - AN2 U3285 ( .A(n3400), .B(n3401), .Z(n3395)); - OR2 U3286 ( .A(n3402), .B(n3371), .Z(n3400)); - AN2 U3287 ( .A(n3403), .B(n3404), .Z(n3402)); - AN2 U3288 ( .A(pi060), .B(po071), .Z(n3403)); - OR2 U3289 ( .A(n3405), .B(n3406), .Z(n3384)); - AN2 U3290 ( .A(n3407), .B(n3363), .Z(n3406)); - AN2 U3291 ( .A(n3408), .B(n3401), .Z(n3407)); - OR2 U3292 ( .A(n3409), .B(n3410), .Z(n3408)); - AN2 U3293 ( .A(n3411), .B(n3412), .Z(n3409)); - OR2 U3294 ( .A(n3413), .B(n3414), .Z(n3411)); - AN2 U3295 ( .A(n3415), .B(n3370), .Z(n3414)); - OR2 U3296 ( .A(n3416), .B(n3417), .Z(n3415)); - AN2 U3297 ( .A(n3418), .B(n3381), .Z(n3413)); - AN2 U3298 ( .A(n3393), .B(n3419), .Z(n3418)); - AN2 U3299 ( .A(n3420), .B(po027), .Z(n3405)); - OR2 U3300 ( .A(n3421), .B(n3422), .Z(n3420)); - OR2 U3301 ( .A(n3423), .B(n3424), .Z(n3422)); - AN2 U3302 ( .A(n3410), .B(n3361), .Z(n3424)); - IV2 U3303 ( .A(n3425), .Z(n3410)); - AN2 U3304 ( .A(n3426), .B(n3401), .Z(n3423)); - OR2 U3305 ( .A(n3427), .B(n3382), .Z(n3426)); - IV2 U3306 ( .A(n3428), .Z(n3382)); - OR2 U3307 ( .A(n3429), .B(n3430), .Z(n3421)); - AN2 U3308 ( .A(n3431), .B(n3370), .Z(n3430)); - AN2 U3309 ( .A(n3393), .B(n3432), .Z(n3429)); - OR2 U3310 ( .A(n3433), .B(n3434), .Z(n3432)); - AN2 U3311 ( .A(po071), .B(n3419), .Z(n3434)); - IV2 U3312 ( .A(n3435), .Z(n3369)); - OR2 U3313 ( .A(n3436), .B(n3375), .Z(n3435)); - AN2 U3314 ( .A(n3437), .B(n3438), .Z(n3436)); - AN2 U3315 ( .A(n3439), .B(n3440), .Z(n3438)); - OR2 U3316 ( .A(n3361), .B(n3441), .Z(n3440)); - AN2 U3317 ( .A(n3442), .B(n3443), .Z(n3441)); - OR2 U3318 ( .A(n3444), .B(n3445), .Z(n3443)); - OR2 U3319 ( .A(n3370), .B(n3446), .Z(n3445)); - OR2 U3320 ( .A(n3371), .B(n3380), .Z(n3444)); - AN2 U3321 ( .A(n3447), .B(n3448), .Z(n3442)); - OR2 U3322 ( .A(po027), .B(n3449), .Z(n3448)); - AN2 U3323 ( .A(n3450), .B(n3428), .Z(n3449)); - OR2 U3324 ( .A(n3371), .B(n3451), .Z(n3428)); - OR2 U3325 ( .A(n3370), .B(n3412), .Z(n3450)); - OR2 U3326 ( .A(n3363), .B(n3425), .Z(n3447)); - OR2 U3327 ( .A(n3427), .B(n3452), .Z(n3425)); - AN2 U3328 ( .A(n3453), .B(n3412), .Z(n3452)); - AN2 U3329 ( .A(n3371), .B(n3451), .Z(n3427)); - OR2 U3330 ( .A(n3401), .B(n3454), .Z(n3439)); - IV2 U3331 ( .A(n3455), .Z(n3454)); - AN2 U3332 ( .A(n3412), .B(n3456), .Z(n3455)); - OR2 U3333 ( .A(n3457), .B(n3458), .Z(n3456)); - AN2 U3334 ( .A(n3392), .B(n3393), .Z(n3458)); - AN2 U3335 ( .A(n3459), .B(n3460), .Z(n3437)); - OR2 U3336 ( .A(n3457), .B(n3461), .Z(n3460)); - AN2 U3337 ( .A(n3462), .B(n3463), .Z(n3459)); - OR2 U3338 ( .A(n3464), .B(n3370), .Z(n3463)); - IV2 U3339 ( .A(n3465), .Z(n3464)); - OR2 U3340 ( .A(n3389), .B(n3431), .Z(n3465)); - AN2 U3341 ( .A(n3466), .B(n3419), .Z(n3431)); - AN2 U3342 ( .A(n3467), .B(n3468), .Z(n3389)); - IV2 U3343 ( .A(n3469), .Z(n3468)); - OR2 U3344 ( .A(n3417), .B(n3470), .Z(n3469)); - AN2 U3345 ( .A(n3471), .B(n3399), .Z(n3470)); - OR2 U3346 ( .A(n3371), .B(n3446), .Z(n3471)); - OR2 U3347 ( .A(n3472), .B(n3393), .Z(n3462)); - AN2 U3348 ( .A(n3473), .B(n3474), .Z(n3472)); - AN2 U3349 ( .A(n3475), .B(n3476), .Z(n3474)); - OR2 U3350 ( .A(n3412), .B(n3477), .Z(n3476)); - AN2 U3351 ( .A(n3478), .B(n3261), .Z(n3475)); - IV2 U3352 ( .A(n3479), .Z(n3478)); - AN2 U3353 ( .A(n3361), .B(n3480), .Z(n3479)); - AN2 U3354 ( .A(n3481), .B(n3482), .Z(n3473)); - OR2 U3355 ( .A(n3483), .B(n3380), .Z(n3482)); - AN2 U3356 ( .A(n3484), .B(n3461), .Z(n3483)); - OR2 U3357 ( .A(n3371), .B(n3485), .Z(n3484)); - IV2 U3358 ( .A(n3433), .Z(n3481)); - OR2 U3359 ( .A(n3486), .B(n3417), .Z(n3433)); - AN2 U3360 ( .A(n3404), .B(n3381), .Z(n3417)); - AN2 U3361 ( .A(n3487), .B(n3380), .Z(n3486)); - AN2 U3362 ( .A(n3488), .B(n3375), .Z(n3356)); - OR2 U3363 ( .A(n3489), .B(n3490), .Z(n3375)); - AN2 U3364 ( .A(n3225), .B(n3491), .Z(n3489)); - OR2 U3365 ( .A(n3492), .B(n3493), .Z(n3491)); - AN2 U3366 ( .A(n3494), .B(n3495), .Z(n3492)); - OR2 U3367 ( .A(n3496), .B(n3497), .Z(n3488)); - OR2 U3368 ( .A(n3498), .B(n3499), .Z(n3497)); - AN2 U3369 ( .A(n3371), .B(n3500), .Z(n3499)); - OR2 U3370 ( .A(n3501), .B(n3502), .Z(n3500)); - OR2 U3371 ( .A(n3503), .B(n3504), .Z(n3502)); - AN2 U3372 ( .A(n3505), .B(n3401), .Z(n3504)); - OR2 U3373 ( .A(n3506), .B(n3507), .Z(n3505)); - AN2 U3374 ( .A(n3508), .B(n3509), .Z(n3507)); - OR2 U3375 ( .A(n3510), .B(n3511), .Z(n3509)); - OR2 U3376 ( .A(n3398), .B(n3487), .Z(n3511)); - AN2 U3377 ( .A(n3512), .B(n2837), .Z(n3487)); - AN2 U3378 ( .A(n3404), .B(pi060), .Z(n3510)); - AN2 U3379 ( .A(n3513), .B(po027), .Z(n3506)); - AN2 U3380 ( .A(n3514), .B(n3515), .Z(n3513)); - OR2 U3381 ( .A(n3516), .B(n3517), .Z(n3515)); - OR2 U3382 ( .A(n3321), .B(n3373), .Z(n3514)); - AN2 U3383 ( .A(n3518), .B(n3467), .Z(n3503)); - AN2 U3384 ( .A(n3404), .B(n3519), .Z(n3518)); - OR2 U3385 ( .A(n3520), .B(n3521), .Z(n3501)); - AN2 U3386 ( .A(n3522), .B(n3517), .Z(n3521)); - AN2 U3387 ( .A(n3516), .B(n3363), .Z(n3522)); - AN2 U3388 ( .A(n3373), .B(n3523), .Z(n3520)); - OR2 U3389 ( .A(n3524), .B(n3525), .Z(n3523)); - AN2 U3390 ( .A(n3361), .B(n3526), .Z(n3524)); - OR2 U3391 ( .A(n3527), .B(n3321), .Z(n3526)); - AN2 U3392 ( .A(n3519), .B(n3528), .Z(n3498)); - OR2 U3393 ( .A(n3529), .B(n3530), .Z(n3528)); - OR2 U3394 ( .A(n3392), .B(n3531), .Z(n3530)); - AN2 U3395 ( .A(n3376), .B(n3412), .Z(n3531)); - OR2 U3396 ( .A(n3532), .B(n3321), .Z(n3376)); - AN2 U3397 ( .A(n3533), .B(n3399), .Z(n3532)); - AN2 U3398 ( .A(n3534), .B(n3381), .Z(n3529)); - OR2 U3399 ( .A(n3535), .B(n3536), .Z(n3519)); - AN2 U3400 ( .A(n3537), .B(po027), .Z(n3536)); - AN2 U3401 ( .A(n3538), .B(n3363), .Z(n3535)); - AN2 U3402 ( .A(n3517), .B(n3401), .Z(n3538)); - OR2 U3403 ( .A(n3539), .B(n3540), .Z(n3496)); - AN2 U3404 ( .A(n3541), .B(n3542), .Z(n3540)); - OR2 U3405 ( .A(n3543), .B(n3544), .Z(n3542)); - AN2 U3406 ( .A(n3453), .B(po071), .Z(n3544)); - AN2 U3407 ( .A(n3480), .B(n3534), .Z(n3543)); - AN2 U3408 ( .A(n3545), .B(n3546), .Z(n3541)); - OR2 U3409 ( .A(n3361), .B(n3547), .Z(n3546)); - AN2 U3410 ( .A(n3508), .B(n3412), .Z(n3547)); - OR2 U3411 ( .A(n3401), .B(n3548), .Z(n3545)); - IV2 U3412 ( .A(n3508), .Z(n3548)); - OR2 U3413 ( .A(n3549), .B(n3550), .Z(n3508)); - AN2 U3414 ( .A(n3373), .B(n3363), .Z(n3550)); - AN2 U3415 ( .A(n3517), .B(po027), .Z(n3549)); - AN2 U3416 ( .A(n3551), .B(n3467), .Z(n3539)); - AN2 U3417 ( .A(n3552), .B(n3381), .Z(n3551)); - OR2 U3418 ( .A(n3553), .B(n3554), .Z(n3552)); - AN2 U3419 ( .A(n3537), .B(n3363), .Z(n3554)); - AN2 U3420 ( .A(n3555), .B(po027), .Z(n3553)); - IV2 U3421 ( .A(n3537), .Z(n3555)); - OR2 U3422 ( .A(n3556), .B(n3557), .Z(n3537)); - AN2 U3423 ( .A(n3373), .B(n3401), .Z(n3557)); - AN2 U3424 ( .A(n3517), .B(n3361), .Z(n3556)); - IV2 U3425 ( .A(n3373), .Z(n3517)); - OR2 U3426 ( .A(n3558), .B(n3559), .Z(n3373)); - AN2 U3427 ( .A(n3370), .B(n3560), .Z(n3559)); - OR2 U3428 ( .A(n3561), .B(n3562), .Z(n3560)); - OR2 U3429 ( .A(n3361), .B(n3563), .Z(n3562)); - AN2 U3430 ( .A(n3321), .B(po027), .Z(n3563)); - OR2 U3431 ( .A(n3564), .B(n3565), .Z(n3561)); - OR2 U3432 ( .A(n3527), .B(n3566), .Z(n3565)); - AN2 U3433 ( .A(po027), .B(n3398), .Z(n3527)); - AN2 U3434 ( .A(n3404), .B(n3567), .Z(n3564)); - AN2 U3435 ( .A(n3393), .B(n3568), .Z(n3558)); - OR2 U3436 ( .A(n3569), .B(n3570), .Z(n3568)); - AN2 U3437 ( .A(n3571), .B(n3401), .Z(n3570)); - OR2 U3438 ( .A(n3516), .B(n3572), .Z(n3571)); - AN2 U3439 ( .A(n3419), .B(n3363), .Z(n3572)); - AN2 U3440 ( .A(po104), .B(n3453), .Z(n3516)); - AN2 U3441 ( .A(n3573), .B(n3467), .Z(n3569)); - AN2 U3442 ( .A(n3261), .B(n3533), .Z(n3467)); - AN2 U3443 ( .A(n3404), .B(po027), .Z(n3573)); - OR2 U3444 ( .A(n3574), .B(n3575), .Z(n3349)); - AN2 U3445 ( .A(n3576), .B(n3247), .Z(n3575)); - IV2 U3446 ( .A(n3577), .Z(n3576)); - AN2 U3447 ( .A(n3225), .B(n3577), .Z(n3574)); - OR2 U3448 ( .A(n3578), .B(n3579), .Z(n3577)); - OR2 U3449 ( .A(n3580), .B(n3581), .Z(n3579)); - OR2 U3450 ( .A(n3582), .B(n3583), .Z(n3581)); - AN2 U3451 ( .A(n3584), .B(n2837), .Z(n3583)); - OR2 U3452 ( .A(n3585), .B(n3586), .Z(n3584)); - OR2 U3453 ( .A(n3587), .B(n3588), .Z(n3586)); - AN2 U3454 ( .A(n3589), .B(n3590), .Z(n3588)); - AN2 U3455 ( .A(n3591), .B(n3592), .Z(n3589)); - OR2 U3456 ( .A(n3593), .B(n3355), .Z(n3592)); - AN2 U3457 ( .A(n3594), .B(n3595), .Z(n3591)); - OR2 U3458 ( .A(n3596), .B(n3597), .Z(n3595)); - OR2 U3459 ( .A(pi003), .B(n3598), .Z(n3594)); - AN2 U3460 ( .A(n3599), .B(n3600), .Z(n3587)); - OR2 U3461 ( .A(n3601), .B(n3602), .Z(n3600)); - OR2 U3462 ( .A(n3603), .B(n3604), .Z(n3602)); - AN2 U3463 ( .A(n3605), .B(n3593), .Z(n3604)); - AN2 U3464 ( .A(n3606), .B(n3607), .Z(n3603)); - OR2 U3465 ( .A(n3608), .B(n3609), .Z(n3601)); - AN2 U3466 ( .A(n3610), .B(pi003), .Z(n3609)); - AN2 U3467 ( .A(n3611), .B(n3612), .Z(n3610)); - AN2 U3468 ( .A(n3613), .B(n3597), .Z(n3608)); - OR2 U3469 ( .A(n3614), .B(n3615), .Z(n3613)); - AN2 U3470 ( .A(n3598), .B(n3616), .Z(n3615)); - AN2 U3471 ( .A(n3617), .B(n3593), .Z(n3614)); - AN2 U3472 ( .A(n3618), .B(n3619), .Z(n3585)); - AN2 U3473 ( .A(n3620), .B(n3590), .Z(n3618)); - OR2 U3474 ( .A(n3621), .B(n3622), .Z(n3620)); - OR2 U3475 ( .A(n3494), .B(n3606), .Z(n3622)); - AN2 U3476 ( .A(pi003), .B(n3623), .Z(n3606)); - AN2 U3477 ( .A(n3616), .B(po011), .Z(n3623)); - AN2 U3478 ( .A(n3624), .B(n3625), .Z(n3621)); - AN2 U3479 ( .A(n3616), .B(n3597), .Z(n3624)); - AN2 U3480 ( .A(pi192), .B(n3626), .Z(n3582)); - OR2 U3481 ( .A(n3627), .B(n3628), .Z(n3626)); - OR2 U3482 ( .A(n3629), .B(n3630), .Z(n3628)); - AN2 U3483 ( .A(n3631), .B(n3632), .Z(n3630)); - AN2 U3484 ( .A(n3633), .B(n3634), .Z(n3631)); - OR2 U3485 ( .A(n3635), .B(n3355), .Z(n3634)); - AN2 U3486 ( .A(n3636), .B(n3637), .Z(n3633)); - OR2 U3487 ( .A(n3596), .B(n3638), .Z(n3637)); - AN2 U3488 ( .A(n3639), .B(n3339), .Z(n3596)); - OR2 U3489 ( .A(pi098), .B(n3598), .Z(n3636)); - AN2 U3490 ( .A(n3640), .B(n3641), .Z(n3629)); - OR2 U3491 ( .A(n3642), .B(n3643), .Z(n3641)); - OR2 U3492 ( .A(n3644), .B(n3645), .Z(n3643)); - AN2 U3493 ( .A(n3605), .B(n3635), .Z(n3645)); - OR2 U3494 ( .A(n3646), .B(n3647), .Z(n3605)); - AN2 U3495 ( .A(n3648), .B(n3493), .Z(n3647)); - AN2 U3496 ( .A(n3341), .B(n3639), .Z(n3646)); - AN2 U3497 ( .A(n3649), .B(n3607), .Z(n3644)); - OR2 U3498 ( .A(n3650), .B(n3651), .Z(n3642)); - AN2 U3499 ( .A(n3652), .B(pi098), .Z(n3651)); - AN2 U3500 ( .A(n3653), .B(n3612), .Z(n3652)); - AN2 U3501 ( .A(n3654), .B(n3638), .Z(n3650)); - OR2 U3502 ( .A(n3655), .B(n3656), .Z(n3654)); - AN2 U3503 ( .A(n3598), .B(n3657), .Z(n3656)); - OR2 U3504 ( .A(n3658), .B(n3659), .Z(n3598)); - AN2 U3505 ( .A(n3660), .B(n3493), .Z(n3659)); - AN2 U3506 ( .A(po011), .B(n3612), .Z(n3660)); - AN2 U3507 ( .A(n3625), .B(n3661), .Z(n3658)); - AN2 U3508 ( .A(n3617), .B(n3635), .Z(n3655)); - AN2 U3509 ( .A(n3625), .B(n3493), .Z(n3617)); - AN2 U3510 ( .A(n3662), .B(n3619), .Z(n3627)); - AN2 U3511 ( .A(n3663), .B(n3632), .Z(n3662)); - OR2 U3512 ( .A(n3664), .B(n3665), .Z(n3663)); - OR2 U3513 ( .A(n3494), .B(n3649), .Z(n3665)); - AN2 U3514 ( .A(pi098), .B(n3666), .Z(n3649)); - AN2 U3515 ( .A(n3657), .B(po011), .Z(n3666)); - AN2 U3516 ( .A(n3612), .B(n3667), .Z(n3494)); - AN2 U3517 ( .A(n3668), .B(n3625), .Z(n3664)); - AN2 U3518 ( .A(n3657), .B(n3638), .Z(n3668)); - OR2 U3519 ( .A(n3669), .B(n3670), .Z(n3580)); - AN2 U3520 ( .A(n3671), .B(po011), .Z(n3670)); - AN2 U3521 ( .A(n3672), .B(n3612), .Z(n3671)); - AN2 U3522 ( .A(n3673), .B(n3674), .Z(n3672)); - OR2 U3523 ( .A(pi192), .B(n3675), .Z(n3674)); - AN2 U3524 ( .A(n3676), .B(n3597), .Z(n3675)); - OR2 U3525 ( .A(n3677), .B(n3678), .Z(n3676)); - AN2 U3526 ( .A(n3679), .B(n3680), .Z(n3677)); - AN2 U3527 ( .A(n3599), .B(n3661), .Z(n3679)); - OR2 U3528 ( .A(n2837), .B(n3681), .Z(n3673)); - AN2 U3529 ( .A(n3682), .B(n3638), .Z(n3681)); - OR2 U3530 ( .A(n3683), .B(n3684), .Z(n3682)); - AN2 U3531 ( .A(n3685), .B(n3686), .Z(n3683)); - AN2 U3532 ( .A(n3640), .B(n3661), .Z(n3685)); - AN2 U3533 ( .A(n3687), .B(n3688), .Z(n3669)); - OR2 U3534 ( .A(n3689), .B(n3690), .Z(n3687)); - OR2 U3535 ( .A(n3691), .B(n3692), .Z(n3690)); - AN2 U3536 ( .A(n3693), .B(n3612), .Z(n3692)); - AN2 U3537 ( .A(n3619), .B(n3694), .Z(n3693)); - OR2 U3538 ( .A(n3695), .B(n3696), .Z(n3694)); - OR2 U3539 ( .A(n3697), .B(n3698), .Z(n3696)); - AN2 U3540 ( .A(n3699), .B(n3616), .Z(n3698)); - AN2 U3541 ( .A(n3700), .B(n3657), .Z(n3697)); - AN2 U3542 ( .A(n3341), .B(n3701), .Z(n3695)); - AN2 U3543 ( .A(n3493), .B(n3352), .Z(n3619)); - AN2 U3544 ( .A(n3625), .B(n3702), .Z(n3691)); - OR2 U3545 ( .A(n3703), .B(n3704), .Z(n3702)); - AN2 U3546 ( .A(n3705), .B(n3706), .Z(n3704)); - OR2 U3547 ( .A(n3684), .B(n3707), .Z(n3706)); - OR2 U3548 ( .A(n3708), .B(n3709), .Z(n3707)); - AN2 U3549 ( .A(n3710), .B(n3640), .Z(n3709)); - OR2 U3550 ( .A(n3711), .B(n3712), .Z(n3710)); - AN2 U3551 ( .A(n3607), .B(n3686), .Z(n3712)); - AN2 U3552 ( .A(n3493), .B(n3713), .Z(n3711)); - IV2 U3553 ( .A(n3686), .Z(n3713)); - AN2 U3554 ( .A(n3653), .B(n3632), .Z(n3708)); - OR2 U3555 ( .A(n3714), .B(n3715), .Z(n3653)); - AN2 U3556 ( .A(n3686), .B(n3493), .Z(n3714)); - AN2 U3557 ( .A(n3635), .B(n3339), .Z(n3686)); - AN2 U3558 ( .A(n3607), .B(n3716), .Z(n3684)); - AN2 U3559 ( .A(n3632), .B(n3657), .Z(n3716)); - AN2 U3560 ( .A(n3717), .B(n3718), .Z(n3703)); - OR2 U3561 ( .A(n3678), .B(n3719), .Z(n3718)); - OR2 U3562 ( .A(n3720), .B(n3721), .Z(n3719)); - AN2 U3563 ( .A(n3722), .B(n3599), .Z(n3721)); - OR2 U3564 ( .A(n3723), .B(n3724), .Z(n3722)); - AN2 U3565 ( .A(n3680), .B(n3607), .Z(n3724)); - AN2 U3566 ( .A(n3493), .B(n3725), .Z(n3723)); - IV2 U3567 ( .A(n3680), .Z(n3725)); - AN2 U3568 ( .A(n3611), .B(n3590), .Z(n3720)); - OR2 U3569 ( .A(n3726), .B(n3715), .Z(n3611)); - AN2 U3570 ( .A(n3341), .B(n3607), .Z(n3715)); - AN2 U3571 ( .A(n3680), .B(n3493), .Z(n3726)); - AN2 U3572 ( .A(n3593), .B(n3339), .Z(n3680)); - AN2 U3573 ( .A(n3607), .B(n3727), .Z(n3678)); - AN2 U3574 ( .A(n3590), .B(n3616), .Z(n3727)); - AN2 U3575 ( .A(n3661), .B(n3352), .Z(n3607)); - AN2 U3576 ( .A(n3639), .B(n3728), .Z(n3689)); - OR2 U3577 ( .A(n3729), .B(n3730), .Z(n3728)); - OR2 U3578 ( .A(n3731), .B(n3732), .Z(n3730)); - AN2 U3579 ( .A(n3733), .B(pi192), .Z(n3732)); - AN2 U3580 ( .A(n3640), .B(n3657), .Z(n3733)); - AN2 U3581 ( .A(n3734), .B(n2837), .Z(n3731)); - AN2 U3582 ( .A(n3599), .B(n3616), .Z(n3734)); - IV2 U3583 ( .A(n3590), .Z(n3599)); - AN2 U3584 ( .A(n3735), .B(n3355), .Z(n3729)); - OR2 U3585 ( .A(n3339), .B(n3736), .Z(n3735)); - OR2 U3586 ( .A(n3737), .B(n3738), .Z(n3578)); - AN2 U3587 ( .A(n3355), .B(n3739), .Z(n3738)); - OR2 U3588 ( .A(n3740), .B(n3741), .Z(n3739)); - AN2 U3589 ( .A(n3742), .B(n3625), .Z(n3741)); - AN2 U3590 ( .A(n3743), .B(n3744), .Z(n3742)); - OR2 U3591 ( .A(n3661), .B(n3688), .Z(n3744)); - OR2 U3592 ( .A(po011), .B(n3745), .Z(n3743)); - AN2 U3593 ( .A(n3493), .B(n3746), .Z(n3745)); - AN2 U3594 ( .A(n3747), .B(n3639), .Z(n3740)); - AN2 U3595 ( .A(n3661), .B(n3612), .Z(n3639)); - AN2 U3596 ( .A(n3736), .B(n3746), .Z(n3747)); - OR2 U3597 ( .A(n3292), .B(n3344), .Z(n3736)); - IV2 U3598 ( .A(n3291), .Z(n3292)); - AN2 U3599 ( .A(n3748), .B(n3648), .Z(n3737)); - OR2 U3600 ( .A(n3749), .B(n3750), .Z(n3648)); - AN2 U3601 ( .A(n3625), .B(po011), .Z(n3750)); - IV2 U3602 ( .A(n3612), .Z(n3625)); - AN2 U3603 ( .A(n3751), .B(n3688), .Z(n3749)); - AN2 U3604 ( .A(n3339), .B(n3612), .Z(n3751)); - OR2 U3605 ( .A(n3752), .B(n3753), .Z(n3612)); - OR2 U3606 ( .A(n3754), .B(n3755), .Z(n3753)); - AN2 U3607 ( .A(n3756), .B(n3757), .Z(n3755)); - OR2 U3608 ( .A(n3758), .B(n3759), .Z(n3752)); - AN2 U3609 ( .A(n3760), .B(n3761), .Z(n3759)); - AN2 U3610 ( .A(n3661), .B(n3762), .Z(n3748)); - OR2 U3611 ( .A(n3763), .B(n3764), .Z(po087)); - OR2 U3612 ( .A(po042), .B(n3765), .Z(n3764)); - OR2 U3613 ( .A(po029), .B(po022), .Z(n3765)); - OR2 U3614 ( .A(n3766), .B(n3767), .Z(n3763)); - OR2 U3615 ( .A(po080), .B(po056), .Z(n3767)); - OR2 U3616 ( .A(po105), .B(po083), .Z(n3766)); - IV2 U3617 ( .A(n3768), .Z(po105)); - AN2 U3618 ( .A(n3769), .B(n3770), .Z(n3768)); - AN2 U3619 ( .A(pi034), .B(pi007), .Z(n3770)); - AN2 U3620 ( .A(pi139), .B(pi120), .Z(n3769)); - OR2 U3621 ( .A(n3771), .B(n3772), .Z(po086)); - AN2 U3622 ( .A(n3773), .B(n3774), .Z(n3772)); - OR2 U3623 ( .A(n3775), .B(n3776), .Z(n3774)); - AN2 U3624 ( .A(n3777), .B(n3778), .Z(n3771)); - AN2 U3625 ( .A(n3779), .B(n3780), .Z(n3777)); - OR2 U3626 ( .A(po025), .B(n3781), .Z(n3779)); - IV2 U3627 ( .A(n3782), .Z(po083)); - AN2 U3628 ( .A(n3783), .B(n3784), .Z(n3782)); - AN2 U3629 ( .A(pi067), .B(pi041), .Z(n3784)); - AN2 U3630 ( .A(pi104), .B(pi070), .Z(n3783)); - OR2 U3631 ( .A(n3785), .B(n3786), .Z(po081)); - AN2 U3632 ( .A(n2862), .B(n3787), .Z(n3786)); - AN2 U3633 ( .A(n2930), .B(n3788), .Z(n3785)); - OR2 U3634 ( .A(n3146), .B(n3789), .Z(n3788)); - OR2 U3635 ( .A(n3790), .B(n3791), .Z(n3789)); - AN2 U3636 ( .A(n3792), .B(n2901), .Z(n3791)); - OR2 U3637 ( .A(n3793), .B(n3794), .Z(n3792)); - AN2 U3638 ( .A(pi192), .B(n2887), .Z(n3794)); - AN2 U3639 ( .A(n3795), .B(n2974), .Z(n3793)); - OR2 U3640 ( .A(n3796), .B(po031), .Z(n3795)); - AN2 U3641 ( .A(n2957), .B(n2837), .Z(n3796)); - AN2 U3642 ( .A(n3797), .B(n2935), .Z(n3790)); - AN2 U3643 ( .A(n2946), .B(n2837), .Z(n3797)); - OR2 U3644 ( .A(n3798), .B(n3799), .Z(po080)); - OR2 U3645 ( .A(n3800), .B(n3801), .Z(n3799)); - OR2 U3646 ( .A(n3802), .B(n3803), .Z(n3801)); - AN2 U3647 ( .A(n3804), .B(n2837), .Z(n3803)); - OR2 U3648 ( .A(n3805), .B(n3806), .Z(n3804)); - OR2 U3649 ( .A(n3807), .B(n3808), .Z(n3806)); - AN2 U3650 ( .A(n3809), .B(n3810), .Z(n3808)); - AN2 U3651 ( .A(n3811), .B(n3812), .Z(n3807)); - AN2 U3652 ( .A(n3813), .B(n3814), .Z(n3805)); - OR2 U3653 ( .A(n3815), .B(n3816), .Z(n3814)); - OR2 U3654 ( .A(n3817), .B(n3818), .Z(n3813)); - AN2 U3655 ( .A(pi192), .B(n3819), .Z(n3802)); - OR2 U3656 ( .A(n3820), .B(n3821), .Z(n3819)); - OR2 U3657 ( .A(n3822), .B(n3823), .Z(n3821)); - AN2 U3658 ( .A(n3824), .B(n3825), .Z(n3823)); - OR2 U3659 ( .A(n3826), .B(n3827), .Z(n3825)); - IV2 U3660 ( .A(n3828), .Z(n3824)); - AN2 U3661 ( .A(n3827), .B(n3826), .Z(n3828)); - OR2 U3662 ( .A(n3829), .B(n3830), .Z(n3826)); - AN2 U3663 ( .A(n3817), .B(n3171), .Z(n3830)); - AN2 U3664 ( .A(n3816), .B(pi033), .Z(n3829)); - IV2 U3665 ( .A(n3817), .Z(n3816)); - OR2 U3666 ( .A(n3831), .B(n3832), .Z(n3817)); - AN2 U3667 ( .A(n3833), .B(pi192), .Z(n3832)); - OR2 U3668 ( .A(n3834), .B(n3835), .Z(n3833)); - IV2 U3669 ( .A(n3836), .Z(n3835)); - OR2 U3670 ( .A(n3837), .B(n3838), .Z(n3836)); - AN2 U3671 ( .A(n3838), .B(n3837), .Z(n3834)); - AN2 U3672 ( .A(n3839), .B(n3840), .Z(n3837)); - OR2 U3673 ( .A(n3841), .B(pi013), .Z(n3840)); - IV2 U3674 ( .A(n3842), .Z(n3841)); - OR2 U3675 ( .A(n3843), .B(n3842), .Z(n3839)); - OR2 U3676 ( .A(n3844), .B(n3845), .Z(n3842)); - AN2 U3677 ( .A(pi026), .B(n3846), .Z(n3845)); - AN2 U3678 ( .A(pi077), .B(n3847), .Z(n3844)); - IV2 U3679 ( .A(pi013), .Z(n3843)); - OR2 U3680 ( .A(n3848), .B(n3849), .Z(n3838)); - AN2 U3681 ( .A(n3850), .B(n3136), .Z(n3849)); - AN2 U3682 ( .A(n3851), .B(pi088), .Z(n3848)); - IV2 U3683 ( .A(n3850), .Z(n3851)); - OR2 U3684 ( .A(n3852), .B(n3853), .Z(n3850)); - IV2 U3685 ( .A(n3854), .Z(n3853)); - OR2 U3686 ( .A(n3855), .B(pi157), .Z(n3854)); - AN2 U3687 ( .A(pi157), .B(n3855), .Z(n3852)); - IV2 U3688 ( .A(pi137), .Z(n3855)); - AN2 U3689 ( .A(n3856), .B(n3857), .Z(n3827)); - OR2 U3690 ( .A(n3858), .B(pi096), .Z(n3857)); - IV2 U3691 ( .A(n3859), .Z(n3858)); - OR2 U3692 ( .A(n3859), .B(n3199), .Z(n3856)); - OR2 U3693 ( .A(n3860), .B(n3861), .Z(n3859)); - AN2 U3694 ( .A(pi166), .B(n3862), .Z(n3861)); - IV2 U3695 ( .A(pi175), .Z(n3862)); - AN2 U3696 ( .A(pi175), .B(n3106), .Z(n3860)); - OR2 U3697 ( .A(n3863), .B(n3864), .Z(n3822)); - AN2 U3698 ( .A(n3865), .B(n3866), .Z(n3864)); - IV2 U3699 ( .A(n3867), .Z(n3863)); - OR2 U3700 ( .A(n3866), .B(n3865), .Z(n3867)); - OR2 U3701 ( .A(n3868), .B(n3869), .Z(n3865)); - AN2 U3702 ( .A(n3811), .B(n3870), .Z(n3869)); - IV2 U3703 ( .A(n3810), .Z(n3811)); - AN2 U3704 ( .A(pi016), .B(n3810), .Z(n3868)); - OR2 U3705 ( .A(n3871), .B(n3872), .Z(n3810)); - OR2 U3706 ( .A(n3873), .B(n3874), .Z(n3872)); - AN2 U3707 ( .A(n3875), .B(pi148), .Z(n3874)); - OR2 U3708 ( .A(n3876), .B(n3877), .Z(n3875)); - AN2 U3709 ( .A(n3878), .B(pi135), .Z(n3877)); - AN2 U3710 ( .A(n3879), .B(n3880), .Z(n3876)); - AN2 U3711 ( .A(n3881), .B(n3882), .Z(n3873)); - IV2 U3712 ( .A(pi148), .Z(n3882)); - OR2 U3713 ( .A(n3883), .B(n3884), .Z(n3881)); - AN2 U3714 ( .A(n3879), .B(pi135), .Z(n3884)); - OR2 U3715 ( .A(n3885), .B(n3886), .Z(n3879)); - AN2 U3716 ( .A(n3887), .B(n3888), .Z(n3886)); - AN2 U3717 ( .A(n3889), .B(n3890), .Z(n3885)); - AN2 U3718 ( .A(n3878), .B(n3880), .Z(n3883)); - OR2 U3719 ( .A(n3891), .B(n3892), .Z(n3878)); - AN2 U3720 ( .A(n3887), .B(n3890), .Z(n3892)); - AN2 U3721 ( .A(n3889), .B(n3888), .Z(n3891)); - IV2 U3722 ( .A(n3887), .Z(n3889)); - OR2 U3723 ( .A(n3893), .B(n3894), .Z(n3887)); - AN2 U3724 ( .A(n3895), .B(n3896), .Z(n3894)); - AN2 U3725 ( .A(n3897), .B(pi005), .Z(n3893)); - IV2 U3726 ( .A(n3895), .Z(n3897)); - OR2 U3727 ( .A(n3898), .B(n3899), .Z(n3895)); - AN2 U3728 ( .A(pi069), .B(n3900), .Z(n3899)); - IV2 U3729 ( .A(pi072), .Z(n3900)); - AN2 U3730 ( .A(pi072), .B(n3901), .Z(n3898)); - AN2 U3731 ( .A(n3902), .B(n3903), .Z(n3866)); - OR2 U3732 ( .A(n3904), .B(pi045), .Z(n3903)); - IV2 U3733 ( .A(n3905), .Z(n3902)); - AN2 U3734 ( .A(n3904), .B(pi045), .Z(n3905)); - AN2 U3735 ( .A(n3906), .B(n3907), .Z(n3904)); - OR2 U3736 ( .A(n3908), .B(pi158), .Z(n3907)); - OR2 U3737 ( .A(n3909), .B(pi079), .Z(n3906)); - OR2 U3738 ( .A(n3910), .B(n3911), .Z(n3820)); - AN2 U3739 ( .A(n3912), .B(n3913), .Z(n3911)); - AN2 U3740 ( .A(n3534), .B(n3914), .Z(n3912)); - AN2 U3741 ( .A(pi118), .B(n3915), .Z(n3910)); - OR2 U3742 ( .A(n3916), .B(n3917), .Z(n3915)); - AN2 U3743 ( .A(n3918), .B(pi060), .Z(n3917)); - AN2 U3744 ( .A(n3919), .B(n3534), .Z(n3916)); - AN2 U3745 ( .A(n3920), .B(n3921), .Z(n3919)); - AN2 U3746 ( .A(n3922), .B(n3923), .Z(n3800)); - OR2 U3747 ( .A(n3924), .B(n3925), .Z(n3923)); - OR2 U3748 ( .A(n3321), .B(n3926), .Z(n3925)); - AN2 U3749 ( .A(n3927), .B(n3928), .Z(n3924)); - AN2 U3750 ( .A(pi050), .B(pi118), .Z(n3928)); - AN2 U3751 ( .A(pi196), .B(n3534), .Z(n3927)); - OR2 U3752 ( .A(n3929), .B(n3930), .Z(n3798)); - OR2 U3753 ( .A(n3931), .B(n3932), .Z(n3930)); - AN2 U3754 ( .A(n3933), .B(n3533), .Z(n3932)); - AN2 U3755 ( .A(n3934), .B(n3913), .Z(n3933)); - OR2 U3756 ( .A(n3918), .B(n3935), .Z(n3934)); - OR2 U3757 ( .A(n3936), .B(n3937), .Z(n3935)); - AN2 U3758 ( .A(n3938), .B(n3921), .Z(n3937)); - AN2 U3759 ( .A(n3920), .B(n3261), .Z(n3938)); - AN2 U3760 ( .A(n3939), .B(n3922), .Z(n3936)); - AN2 U3761 ( .A(pi196), .B(n3940), .Z(n3939)); - AN2 U3762 ( .A(n3922), .B(n3941), .Z(n3918)); - AN2 U3763 ( .A(n3942), .B(n3943), .Z(n3941)); - AN2 U3764 ( .A(n3944), .B(n3945), .Z(n3931)); - AN2 U3765 ( .A(pi204), .B(n3946), .Z(n3944)); - IV2 U3766 ( .A(n3947), .Z(n3946)); - AN2 U3767 ( .A(n3948), .B(n3261), .Z(n3929)); - OR2 U3768 ( .A(n3949), .B(n3950), .Z(n3948)); - AN2 U3769 ( .A(n3947), .B(n3951), .Z(n3950)); - AN2 U3770 ( .A(n3952), .B(n3953), .Z(n3947)); - IV2 U3771 ( .A(n3954), .Z(n3953)); - AN2 U3772 ( .A(n3955), .B(n3956), .Z(n3954)); - OR2 U3773 ( .A(n3956), .B(n3955), .Z(n3952)); - OR2 U3774 ( .A(n3957), .B(n3958), .Z(n3955)); - AN2 U3775 ( .A(n3959), .B(n3960), .Z(n3958)); - IV2 U3776 ( .A(pi009), .Z(n3960)); - AN2 U3777 ( .A(pi009), .B(n3961), .Z(n3957)); - AN2 U3778 ( .A(n3962), .B(n3963), .Z(n3956)); - OR2 U3779 ( .A(n3964), .B(pi129), .Z(n3963)); - IV2 U3780 ( .A(n3965), .Z(n3964)); - OR2 U3781 ( .A(n3965), .B(n3966), .Z(n3962)); - OR2 U3782 ( .A(n3967), .B(n3968), .Z(n3965)); - AN2 U3783 ( .A(pi138), .B(n3969), .Z(n3968)); - AN2 U3784 ( .A(pi169), .B(n3970), .Z(n3967)); - IV2 U3785 ( .A(pi138), .Z(n3970)); - AN2 U3786 ( .A(n3971), .B(n3533), .Z(n3949)); - AN2 U3787 ( .A(n3914), .B(pi118), .Z(n3971)); - OR2 U3788 ( .A(n3972), .B(n3973), .Z(n3914)); - AN2 U3789 ( .A(n3920), .B(n3922), .Z(n3973)); - IV2 U3790 ( .A(n3921), .Z(n3922)); - AN2 U3791 ( .A(n3921), .B(n3974), .Z(n3972)); - IV2 U3792 ( .A(n3920), .Z(n3974)); - OR2 U3793 ( .A(n3975), .B(n3976), .Z(n3920)); - AN2 U3794 ( .A(pi050), .B(n3942), .Z(n3976)); - AN2 U3795 ( .A(pi196), .B(n3943), .Z(n3975)); - OR2 U3796 ( .A(n3977), .B(n3978), .Z(n3921)); - AN2 U3797 ( .A(n3979), .B(pi192), .Z(n3978)); - OR2 U3798 ( .A(n3980), .B(n3981), .Z(n3979)); - AN2 U3799 ( .A(n3982), .B(n3983), .Z(n3981)); - IV2 U3800 ( .A(n3984), .Z(n3980)); - OR2 U3801 ( .A(n3983), .B(n3982), .Z(n3984)); - OR2 U3802 ( .A(n3985), .B(n3986), .Z(n3982)); - IV2 U3803 ( .A(n3987), .Z(n3986)); - OR2 U3804 ( .A(n3988), .B(n3989), .Z(n3987)); - AN2 U3805 ( .A(n3988), .B(n3989), .Z(n3985)); - AN2 U3806 ( .A(n3990), .B(n3991), .Z(n3988)); - OR2 U3807 ( .A(n3992), .B(pi039), .Z(n3991)); - OR2 U3808 ( .A(n3993), .B(pi004), .Z(n3990)); - IV2 U3809 ( .A(pi039), .Z(n3993)); - AN2 U3810 ( .A(n3994), .B(n3995), .Z(n3983)); - OR2 U3811 ( .A(n3996), .B(pi068), .Z(n3995)); - IV2 U3812 ( .A(n3997), .Z(n3996)); - OR2 U3813 ( .A(n3997), .B(n3998), .Z(n3994)); - OR2 U3814 ( .A(n3999), .B(n4000), .Z(n3997)); - AN2 U3815 ( .A(pi098), .B(n4001), .Z(n4000)); - AN2 U3816 ( .A(pi171), .B(n3638), .Z(n3999)); - OR2 U3817 ( .A(pi037), .B(pi043), .Z(po078)); - OR2 U3818 ( .A(n4002), .B(n4003), .Z(po077)); - AN2 U3819 ( .A(n4004), .B(n4005), .Z(n4003)); - AN2 U3820 ( .A(n4006), .B(n4007), .Z(n4002)); - OR2 U3821 ( .A(n4008), .B(n4009), .Z(n4007)); - IV2 U3822 ( .A(pi090), .Z(po076)); - OR2 U3823 ( .A(n4010), .B(n4011), .Z(po075)); - AN2 U3824 ( .A(n4012), .B(n4013), .Z(n4011)); - OR2 U3825 ( .A(n4014), .B(n4015), .Z(n4012)); - OR2 U3826 ( .A(n4016), .B(n4017), .Z(n4015)); - OR2 U3827 ( .A(n4018), .B(n4019), .Z(n4014)); - AN2 U3828 ( .A(n4020), .B(n3314), .Z(n4019)); - OR2 U3829 ( .A(n4021), .B(n4022), .Z(n4020)); - AN2 U3830 ( .A(n3926), .B(n3328), .Z(n4022)); - OR2 U3831 ( .A(n3265), .B(n3326), .Z(n3328)); - AN2 U3832 ( .A(n4023), .B(pi204), .Z(n4021)); - AN2 U3833 ( .A(n3312), .B(n3261), .Z(n4023)); - OR2 U3834 ( .A(n4024), .B(n4025), .Z(n3312)); - AN2 U3835 ( .A(n3326), .B(n4026), .Z(n4024)); - AN2 U3836 ( .A(n4027), .B(n3320), .Z(n4018)); - OR2 U3837 ( .A(n4028), .B(n3321), .Z(n4027)); - AN2 U3838 ( .A(po040), .B(n4029), .Z(n4010)); - OR2 U3839 ( .A(n4030), .B(n4031), .Z(n4029)); - OR2 U3840 ( .A(n4032), .B(n4033), .Z(n4031)); - AN2 U3841 ( .A(n4034), .B(n3261), .Z(n4032)); - OR2 U3842 ( .A(n4035), .B(n4036), .Z(n4034)); - OR2 U3843 ( .A(n4037), .B(n4038), .Z(n4036)); - AN2 U3844 ( .A(n4039), .B(n3951), .Z(n4038)); - AN2 U3845 ( .A(n4025), .B(n3314), .Z(n4039)); - AN2 U3846 ( .A(n4040), .B(n4041), .Z(n4037)); - AN2 U3847 ( .A(n4042), .B(n3320), .Z(n4035)); - OR2 U3848 ( .A(n4043), .B(n4044), .Z(n4042)); - AN2 U3849 ( .A(pi204), .B(n4045), .Z(n4044)); - AN2 U3850 ( .A(n4046), .B(n4041), .Z(n4043)); - OR2 U3851 ( .A(n4047), .B(n4048), .Z(n4030)); - AN2 U3852 ( .A(n4049), .B(n4050), .Z(n4048)); - OR2 U3853 ( .A(n4051), .B(n4052), .Z(n4050)); - AN2 U3854 ( .A(n3321), .B(n3265), .Z(n4052)); - AN2 U3855 ( .A(n3951), .B(n4053), .Z(n4051)); - AN2 U3856 ( .A(n3326), .B(n3314), .Z(n4049)); - AN2 U3857 ( .A(n4054), .B(n4055), .Z(n4047)); - AN2 U3858 ( .A(n4056), .B(n4057), .Z(n4055)); - AN2 U3859 ( .A(n3945), .B(pi204), .Z(n4054)); - OR2 U3860 ( .A(n4058), .B(n4059), .Z(po073)); - AN2 U3861 ( .A(n4060), .B(n4061), .Z(n4059)); - AN2 U3862 ( .A(n3457), .B(n4062), .Z(n4058)); - OR2 U3863 ( .A(n4063), .B(n4064), .Z(po068)); - AN2 U3864 ( .A(n4065), .B(n4066), .Z(n4064)); - OR2 U3865 ( .A(n4067), .B(n4068), .Z(n4065)); - OR2 U3866 ( .A(n4069), .B(n4070), .Z(n4068)); - AN2 U3867 ( .A(n4071), .B(n4072), .Z(n4070)); - OR2 U3868 ( .A(n4073), .B(po059), .Z(n4071)); - AN2 U3869 ( .A(n4074), .B(n2837), .Z(n4073)); - AN2 U3870 ( .A(n4075), .B(n4076), .Z(n4069)); - AN2 U3871 ( .A(n3780), .B(n4077), .Z(n4075)); - AN2 U3872 ( .A(n4078), .B(n4079), .Z(n4063)); - OR2 U3873 ( .A(n4080), .B(n4081), .Z(n4079)); - OR2 U3874 ( .A(n4082), .B(n4083), .Z(n4081)); - AN2 U3875 ( .A(n4084), .B(n2837), .Z(n4083)); - AN2 U3876 ( .A(n4085), .B(pi192), .Z(n4082)); - AN2 U3877 ( .A(n3778), .B(n3776), .Z(n4080)); - OR2 U3878 ( .A(n4086), .B(n4087), .Z(n3776)); - OR2 U3879 ( .A(n4088), .B(n4089), .Z(po061)); - AN2 U3880 ( .A(n2861), .B(n4090), .Z(n4089)); - OR2 U3881 ( .A(n4091), .B(n4092), .Z(n4090)); - OR2 U3882 ( .A(n4093), .B(n4094), .Z(n4092)); - AN2 U3883 ( .A(n4095), .B(n2901), .Z(n4094)); - AN2 U3884 ( .A(n2862), .B(n2990), .Z(n4093)); - OR2 U3885 ( .A(n4096), .B(n4097), .Z(n4091)); - AN2 U3886 ( .A(n2880), .B(n4098), .Z(n4097)); - AN2 U3887 ( .A(n4099), .B(n4100), .Z(n4096)); - OR2 U3888 ( .A(n4101), .B(n4102), .Z(n4100)); - OR2 U3889 ( .A(n2978), .B(n4103), .Z(n4102)); - AN2 U3890 ( .A(n3222), .B(n2957), .Z(n4103)); - AN2 U3891 ( .A(n2935), .B(po031), .Z(n4101)); - IV2 U3892 ( .A(n2938), .Z(n2935)); - AN2 U3893 ( .A(n4104), .B(n2998), .Z(n4088)); - OR2 U3894 ( .A(n4105), .B(n4106), .Z(n4104)); - OR2 U3895 ( .A(n4107), .B(n4108), .Z(n4106)); - AN2 U3896 ( .A(n2892), .B(pi192), .Z(n4108)); - AN2 U3897 ( .A(n2929), .B(n2837), .Z(n4107)); - AN2 U3898 ( .A(n2930), .B(n3787), .Z(n4105)); - OR2 U3899 ( .A(n4109), .B(n4110), .Z(n3787)); - OR2 U3900 ( .A(n4111), .B(n4112), .Z(n4110)); - AN2 U3901 ( .A(n4113), .B(n2837), .Z(n4112)); - AN2 U3902 ( .A(n2876), .B(pi192), .Z(n4111)); - AN2 U3903 ( .A(pi200), .B(n4114), .Z(n4109)); - OR2 U3904 ( .A(n4115), .B(n2999), .Z(n4114)); - OR2 U3905 ( .A(n4116), .B(n4117), .Z(n2999)); - AN2 U3906 ( .A(n2938), .B(n2962), .Z(n4117)); - AN2 U3907 ( .A(pi192), .B(n2878), .Z(n4116)); - AN2 U3908 ( .A(n2918), .B(n2837), .Z(n4115)); - AN2 U3909 ( .A(n2938), .B(pi082), .Z(n2918)); - OR2 U3910 ( .A(n4118), .B(n4119), .Z(po060)); - OR2 U3911 ( .A(n4120), .B(n4121), .Z(n4119)); - AN2 U3912 ( .A(n4122), .B(n4123), .Z(n4121)); - OR2 U3913 ( .A(n4124), .B(n4125), .Z(n4123)); - AN2 U3914 ( .A(n4126), .B(n4127), .Z(n4124)); - OR2 U3915 ( .A(n4128), .B(n4129), .Z(n4126)); - AN2 U3916 ( .A(n4130), .B(n4131), .Z(n4122)); - OR2 U3917 ( .A(n4132), .B(n4133), .Z(n4131)); - AN2 U3918 ( .A(pi052), .B(n4134), .Z(n4132)); - OR2 U3919 ( .A(po064), .B(n4135), .Z(n4130)); - AN2 U3920 ( .A(n4136), .B(n4137), .Z(n4120)); - OR2 U3921 ( .A(n4138), .B(n4139), .Z(n4137)); - AN2 U3922 ( .A(n4140), .B(n4141), .Z(n4139)); - OR2 U3923 ( .A(n4142), .B(n4143), .Z(n4140)); - OR2 U3924 ( .A(n4144), .B(n4145), .Z(n4143)); - AN2 U3925 ( .A(po040), .B(n3321), .Z(n4145)); - AN2 U3926 ( .A(po103), .B(n4146), .Z(n4144)); - OR2 U3927 ( .A(n4147), .B(n3321), .Z(n4146)); - AN2 U3928 ( .A(n4148), .B(n4149), .Z(n4147)); - OR2 U3929 ( .A(po004), .B(n4150), .Z(n4149)); - OR2 U3930 ( .A(n4151), .B(n4152), .Z(n4142)); - OR2 U3931 ( .A(n4153), .B(n4154), .Z(n4152)); - IV2 U3932 ( .A(n4155), .Z(n4154)); - OR2 U3933 ( .A(n4156), .B(n4157), .Z(n4155)); - AN2 U3934 ( .A(n4158), .B(n4159), .Z(n4153)); - AN2 U3935 ( .A(n4160), .B(po004), .Z(n4151)); - AN2 U3936 ( .A(n3951), .B(po040), .Z(n4160)); - AN2 U3937 ( .A(po004), .B(n4161), .Z(n4138)); - AN2 U3938 ( .A(n4162), .B(n4163), .Z(n4136)); - OR2 U3939 ( .A(n4164), .B(n4134), .Z(n4163)); - AN2 U3940 ( .A(n4165), .B(po064), .Z(n4164)); - IV2 U3941 ( .A(n4166), .Z(n4165)); - OR2 U3942 ( .A(n4167), .B(n4125), .Z(n4166)); - OR2 U3943 ( .A(n4135), .B(n4168), .Z(n4162)); - OR2 U3944 ( .A(n4169), .B(n4170), .Z(n4168)); - AN2 U3945 ( .A(pi054), .B(n4167), .Z(n4170)); - AN2 U3946 ( .A(n4171), .B(n4133), .Z(n4169)); - IV2 U3947 ( .A(n4172), .Z(n4171)); - OR2 U3948 ( .A(n4173), .B(n4174), .Z(n4118)); - AN2 U3949 ( .A(n4175), .B(pi054), .Z(n4174)); - AN2 U3950 ( .A(n4176), .B(n4177), .Z(n4175)); - OR2 U3951 ( .A(n4178), .B(n4179), .Z(n4176)); - AN2 U3952 ( .A(n4134), .B(n4133), .Z(n4179)); - AN2 U3953 ( .A(n4135), .B(po064), .Z(n4178)); - AN2 U3954 ( .A(n4180), .B(n4135), .Z(n4173)); - IV2 U3955 ( .A(n4134), .Z(n4135)); - OR2 U3956 ( .A(n4181), .B(n4182), .Z(n4134)); - AN2 U3957 ( .A(n4183), .B(n4184), .Z(n4182)); - OR2 U3958 ( .A(n4185), .B(n4186), .Z(n4183)); - AN2 U3959 ( .A(n4187), .B(n4188), .Z(n4186)); - IV2 U3960 ( .A(n4189), .Z(n4188)); - OR2 U3961 ( .A(n4190), .B(n4191), .Z(n4187)); - AN2 U3962 ( .A(n4192), .B(n4193), .Z(n4191)); - OR2 U3963 ( .A(n4194), .B(n4195), .Z(n4193)); - AN2 U3964 ( .A(n4196), .B(n3261), .Z(n4195)); - OR2 U3965 ( .A(n4197), .B(n4198), .Z(n4196)); - AN2 U3966 ( .A(n4199), .B(po103), .Z(n4198)); - AN2 U3967 ( .A(n4200), .B(n4201), .Z(n4199)); - AN2 U3968 ( .A(n4202), .B(n4025), .Z(n4197)); - AN2 U3969 ( .A(n4203), .B(po091), .Z(n4202)); - AN2 U3970 ( .A(n4204), .B(n4205), .Z(n4190)); - OR2 U3971 ( .A(n3317), .B(n4206), .Z(n4204)); - OR2 U3972 ( .A(n4207), .B(n4208), .Z(n4206)); - AN2 U3973 ( .A(n4209), .B(n3314), .Z(n4208)); - IV2 U3974 ( .A(n4210), .Z(n4209)); - AN2 U3975 ( .A(n4210), .B(n4057), .Z(n4207)); - AN2 U3976 ( .A(po103), .B(n4148), .Z(n4210)); - AN2 U3977 ( .A(n4189), .B(n4211), .Z(n4185)); - OR2 U3978 ( .A(n4212), .B(n4213), .Z(n4211)); - AN2 U3979 ( .A(n4214), .B(n4205), .Z(n4213)); - OR2 U3980 ( .A(n3325), .B(n4215), .Z(n4214)); - OR2 U3981 ( .A(n4216), .B(n3329), .Z(n4215)); - AN2 U3982 ( .A(n4040), .B(n4217), .Z(n3329)); - AN2 U3983 ( .A(n4192), .B(n4218), .Z(n4212)); - OR2 U3984 ( .A(n4219), .B(n4220), .Z(n4218)); - OR2 U3985 ( .A(n4221), .B(n4222), .Z(n4220)); - AN2 U3986 ( .A(n4025), .B(n4201), .Z(n4222)); - IV2 U3987 ( .A(n4223), .Z(n4025)); - AN2 U3988 ( .A(po091), .B(n4200), .Z(n4221)); - OR2 U3989 ( .A(n4224), .B(n4225), .Z(n4189)); - AN2 U3990 ( .A(n4226), .B(n4227), .Z(n4225)); - IV2 U3991 ( .A(n4228), .Z(n4224)); - OR2 U3992 ( .A(n4227), .B(n4226), .Z(n4228)); - AN2 U3993 ( .A(n4229), .B(n4230), .Z(n4181)); - OR2 U3994 ( .A(n4231), .B(n4232), .Z(n4230)); - OR2 U3995 ( .A(n4233), .B(n4234), .Z(n4232)); - AN2 U3996 ( .A(n4235), .B(n4236), .Z(n4234)); - OR2 U3997 ( .A(n4237), .B(n4238), .Z(n4235)); - AN2 U3998 ( .A(n4239), .B(n4240), .Z(n4238)); - OR2 U3999 ( .A(n3325), .B(n4216), .Z(n4240)); - AN2 U4000 ( .A(po103), .B(n4194), .Z(n4216)); - AN2 U4001 ( .A(n3265), .B(n4040), .Z(n3325)); - AN2 U4002 ( .A(n4241), .B(n4242), .Z(n4237)); - OR2 U4003 ( .A(n4243), .B(n4219), .Z(n4241)); - OR2 U4004 ( .A(n4244), .B(n3321), .Z(n4219)); - AN2 U4005 ( .A(n4203), .B(n4223), .Z(n4244)); - AN2 U4006 ( .A(n4245), .B(n3314), .Z(n4243)); - OR2 U4007 ( .A(n4246), .B(po091), .Z(n4245)); - AN2 U4008 ( .A(n4247), .B(n3265), .Z(n4246)); - AN2 U4009 ( .A(n4248), .B(n4249), .Z(n4233)); - OR2 U4010 ( .A(n4250), .B(n4251), .Z(n4249)); - OR2 U4011 ( .A(n4252), .B(n4253), .Z(n4251)); - AN2 U4012 ( .A(po103), .B(n4254), .Z(n4253)); - OR2 U4013 ( .A(n4255), .B(n3330), .Z(n4254)); - AN2 U4014 ( .A(n3311), .B(n4242), .Z(n4255)); - AN2 U4015 ( .A(n4194), .B(n3265), .Z(n4252)); - AN2 U4016 ( .A(n4148), .B(n3311), .Z(n4194)); - AN2 U4017 ( .A(n4239), .B(n4256), .Z(n4250)); - OR2 U4018 ( .A(n4257), .B(n4258), .Z(n4256)); - OR2 U4019 ( .A(n3926), .B(n4259), .Z(n4258)); - AN2 U4020 ( .A(n4260), .B(n3314), .Z(n4259)); - OR2 U4021 ( .A(n4261), .B(n4262), .Z(n4257)); - AN2 U4022 ( .A(pi058), .B(pi129), .Z(n4262)); - AN2 U4023 ( .A(n4056), .B(n3966), .Z(n4261)); - AN2 U4024 ( .A(n4263), .B(n4264), .Z(n4231)); - AN2 U4025 ( .A(n4265), .B(n4266), .Z(n4264)); - OR2 U4026 ( .A(n4267), .B(n4236), .Z(n4266)); - AN2 U4027 ( .A(n4268), .B(pi058), .Z(n4267)); - AN2 U4028 ( .A(n4242), .B(n3265), .Z(n4268)); - OR2 U4029 ( .A(n4269), .B(n4248), .Z(n4265)); - IV2 U4030 ( .A(n4236), .Z(n4248)); - AN2 U4031 ( .A(n4270), .B(n4271), .Z(n4236)); - IV2 U4032 ( .A(n4272), .Z(n4271)); - AN2 U4033 ( .A(n4226), .B(n4141), .Z(n4272)); - OR2 U4034 ( .A(n4226), .B(n4141), .Z(n4270)); - OR2 U4035 ( .A(n4273), .B(n4274), .Z(n4226)); - IV2 U4036 ( .A(n4275), .Z(n4274)); - OR2 U4037 ( .A(n4276), .B(n4277), .Z(n4275)); - AN2 U4038 ( .A(n4277), .B(n4276), .Z(n4273)); - AN2 U4039 ( .A(n4278), .B(n4279), .Z(n4276)); - OR2 U4040 ( .A(n4280), .B(n4281), .Z(n4279)); - IV2 U4041 ( .A(n4282), .Z(n4280)); - OR2 U4042 ( .A(n4283), .B(n4282), .Z(n4278)); - OR2 U4043 ( .A(n4284), .B(n4285), .Z(n4282)); - AN2 U4044 ( .A(po040), .B(n4286), .Z(n4285)); - OR2 U4045 ( .A(n4017), .B(n4287), .Z(n4286)); - OR2 U4046 ( .A(n4288), .B(n4289), .Z(n4287)); - AN2 U4047 ( .A(n4290), .B(n3314), .Z(n4289)); - OR2 U4048 ( .A(n4291), .B(n3321), .Z(n4290)); - IV2 U4049 ( .A(n4292), .Z(n4288)); - OR2 U4050 ( .A(n4293), .B(n3314), .Z(n4292)); - OR2 U4051 ( .A(n4294), .B(n3330), .Z(n4017)); - AN2 U4052 ( .A(n4201), .B(n3926), .Z(n3330)); - AN2 U4053 ( .A(n3311), .B(pi204), .Z(n4294)); - AN2 U4054 ( .A(n4295), .B(n4013), .Z(n4284)); - OR2 U4055 ( .A(n4033), .B(n4296), .Z(n4295)); - OR2 U4056 ( .A(n4297), .B(n4298), .Z(n4296)); - AN2 U4057 ( .A(n4299), .B(n3314), .Z(n4298)); - AN2 U4058 ( .A(n4300), .B(n3261), .Z(n4299)); - OR2 U4059 ( .A(n4301), .B(n4302), .Z(n4300)); - AN2 U4060 ( .A(pi204), .B(n4203), .Z(n4302)); - AN2 U4061 ( .A(po091), .B(n4041), .Z(n4301)); - AN2 U4062 ( .A(n4040), .B(n4293), .Z(n4297)); - AN2 U4063 ( .A(n3311), .B(n3951), .Z(n4033)); - IV2 U4064 ( .A(n4260), .Z(n3311)); - OR2 U4065 ( .A(n3321), .B(n4057), .Z(n4260)); - IV2 U4066 ( .A(n4281), .Z(n4283)); - OR2 U4067 ( .A(n4303), .B(n4304), .Z(n4281)); - AN2 U4068 ( .A(n4305), .B(n4306), .Z(n4304)); - AN2 U4069 ( .A(n4307), .B(n3261), .Z(n4305)); - OR2 U4070 ( .A(n4308), .B(n4309), .Z(n4307)); - AN2 U4071 ( .A(pi065), .B(n4148), .Z(n4309)); - AN2 U4072 ( .A(n4310), .B(pi058), .Z(n4308)); - AN2 U4073 ( .A(n4311), .B(n4312), .Z(n4303)); - OR2 U4074 ( .A(n3961), .B(n4313), .Z(n4311)); - IV2 U4075 ( .A(n3959), .Z(n3961)); - OR2 U4076 ( .A(n4314), .B(n4315), .Z(n3959)); - AN2 U4077 ( .A(pi058), .B(n4150), .Z(n4315)); - AN2 U4078 ( .A(pi065), .B(n4316), .Z(n4314)); - OR2 U4079 ( .A(n4317), .B(n4318), .Z(n4277)); - AN2 U4080 ( .A(po004), .B(n3265), .Z(n4318)); - AN2 U4081 ( .A(po103), .B(n4319), .Z(n4317)); - AN2 U4082 ( .A(n4239), .B(pi058), .Z(n4269)); - AN2 U4083 ( .A(n4040), .B(n3261), .Z(n4263)); - AN2 U4084 ( .A(n4320), .B(n4167), .Z(n4180)); - OR2 U4085 ( .A(n4129), .B(n4127), .Z(n4320)); - AN2 U4086 ( .A(po023), .B(pi183), .Z(po058)); - IV2 U4087 ( .A(n4321), .Z(po056)); - AN2 U4088 ( .A(n4322), .B(n4323), .Z(n4321)); - AN2 U4089 ( .A(pi063), .B(pi010), .Z(n4323)); - AN2 U4090 ( .A(pi203), .B(pi073), .Z(n4322)); - OR2 U4091 ( .A(n4324), .B(n4325), .Z(po055)); - AN2 U4092 ( .A(n3015), .B(n4326), .Z(n4325)); - AN2 U4093 ( .A(n3018), .B(n4327), .Z(n4324)); - AN2 U4094 ( .A(n4328), .B(n4329), .Z(po053)); - OR2 U4095 ( .A(n4306), .B(n4330), .Z(n4329)); - IV2 U4096 ( .A(n4312), .Z(n4306)); - OR2 U4097 ( .A(n4331), .B(n4312), .Z(n4328)); - AN2 U4098 ( .A(n4332), .B(n3780), .Z(po051)); - OR2 U4099 ( .A(n4333), .B(n4334), .Z(n4332)); - OR2 U4100 ( .A(n4335), .B(n4336), .Z(po050)); - AN2 U4101 ( .A(n4337), .B(n4338), .Z(n4336)); - OR2 U4102 ( .A(n4339), .B(n4340), .Z(n4338)); - AN2 U4103 ( .A(n4087), .B(n4341), .Z(n4339)); - AN2 U4104 ( .A(n4342), .B(n4343), .Z(n4335)); - OR2 U4105 ( .A(n4344), .B(n4345), .Z(n4343)); - OR2 U4106 ( .A(n4346), .B(n4347), .Z(n4345)); - AN2 U4107 ( .A(n4067), .B(n4348), .Z(n4346)); - OR2 U4108 ( .A(n4349), .B(n4350), .Z(n4067)); - AN2 U4109 ( .A(n4351), .B(pi192), .Z(n4350)); - AN2 U4110 ( .A(n4072), .B(n3880), .Z(n4351)); - AN2 U4111 ( .A(n4352), .B(n3890), .Z(n4349)); - AN2 U4112 ( .A(n4353), .B(n3780), .Z(n4352)); - OR2 U4113 ( .A(n4354), .B(n4355), .Z(n4344)); - AN2 U4114 ( .A(n4356), .B(n3780), .Z(n4355)); - AN2 U4115 ( .A(n4357), .B(n4076), .Z(n4354)); - AN2 U4116 ( .A(n4072), .B(n4358), .Z(n4357)); - OR2 U4117 ( .A(n4359), .B(n4360), .Z(po049)); - AN2 U4118 ( .A(n3361), .B(n4361), .Z(n4360)); - OR2 U4119 ( .A(n4362), .B(n4363), .Z(n4361)); - AN2 U4120 ( .A(n4364), .B(n3451), .Z(n4362)); - IV2 U4121 ( .A(n3401), .Z(n3361)); - AN2 U4122 ( .A(n4365), .B(n3401), .Z(n4359)); - OR2 U4123 ( .A(n4366), .B(n4367), .Z(n4365)); - AN2 U4124 ( .A(n3453), .B(n4368), .Z(n4366)); - OR2 U4125 ( .A(n4369), .B(n3253), .Z(po048)); - AN2 U4126 ( .A(n4370), .B(n3255), .Z(n4369)); - OR2 U4127 ( .A(n4371), .B(n4372), .Z(n4370)); - AN2 U4128 ( .A(n4373), .B(n3259), .Z(n4371)); - AN2 U4129 ( .A(n4374), .B(n4242), .Z(n4373)); - OR2 U4130 ( .A(n4375), .B(n4376), .Z(po047)); - OR2 U4131 ( .A(n4377), .B(n4378), .Z(n4376)); - AN2 U4132 ( .A(n4379), .B(n4380), .Z(n4378)); - AN2 U4133 ( .A(n4381), .B(n3259), .Z(n4377)); - AN2 U4134 ( .A(n4382), .B(n4383), .Z(n4381)); - OR2 U4135 ( .A(po004), .B(n4384), .Z(n4383)); - OR2 U4136 ( .A(n3926), .B(n4385), .Z(n4384)); - AN2 U4137 ( .A(n4386), .B(pi065), .Z(n4385)); - AN2 U4138 ( .A(n4387), .B(n4157), .Z(n4386)); - OR2 U4139 ( .A(n4319), .B(n4388), .Z(n4382)); - OR2 U4140 ( .A(n4389), .B(n4390), .Z(n4388)); - AN2 U4141 ( .A(n4391), .B(n3321), .Z(n4390)); - AN2 U4142 ( .A(n4392), .B(n4310), .Z(n4389)); - AN2 U4143 ( .A(pi204), .B(n4387), .Z(n4392)); - OR2 U4144 ( .A(n4393), .B(n4394), .Z(n4375)); - AN2 U4145 ( .A(n4395), .B(n4319), .Z(n4394)); - OR2 U4146 ( .A(n4396), .B(n4397), .Z(n4395)); - AN2 U4147 ( .A(n4227), .B(n4161), .Z(n4397)); - AN2 U4148 ( .A(po004), .B(n4398), .Z(n4393)); - OR2 U4149 ( .A(n4399), .B(n4400), .Z(n4398)); - OR2 U4150 ( .A(n4401), .B(n4402), .Z(n4400)); - AN2 U4151 ( .A(n4310), .B(n4403), .Z(n4402)); - AN2 U4152 ( .A(n4404), .B(n4227), .Z(n4401)); - AN2 U4153 ( .A(n4405), .B(n4406), .Z(n4399)); - AN2 U4154 ( .A(n4407), .B(n3261), .Z(n4405)); - OR2 U4155 ( .A(n4408), .B(n4409), .Z(n4407)); - AN2 U4156 ( .A(n4028), .B(pi065), .Z(n4409)); - AN2 U4157 ( .A(po040), .B(n4410), .Z(n4408)); - OR2 U4158 ( .A(n4411), .B(n4412), .Z(n4410)); - AN2 U4159 ( .A(pi065), .B(n4045), .Z(n4412)); - AN2 U4160 ( .A(n4046), .B(n4156), .Z(n4411)); - OR2 U4161 ( .A(n4413), .B(n4414), .Z(po046)); - OR2 U4162 ( .A(n4415), .B(n4416), .Z(n4414)); - AN2 U4163 ( .A(n3339), .B(n4417), .Z(n4416)); - AN2 U4164 ( .A(n3341), .B(n4418), .Z(n4415)); - OR2 U4165 ( .A(n4419), .B(n4420), .Z(n4413)); - AN2 U4166 ( .A(n4421), .B(pi192), .Z(n4420)); - OR2 U4167 ( .A(n4422), .B(n4423), .Z(n4421)); - AN2 U4168 ( .A(n4424), .B(pi098), .Z(n4423)); - AN2 U4169 ( .A(n4425), .B(n4426), .Z(n4424)); - OR2 U4170 ( .A(n3242), .B(n3657), .Z(n4425)); - IV2 U4171 ( .A(n3635), .Z(n3657)); - AN2 U4172 ( .A(n4427), .B(n3638), .Z(n4422)); - OR2 U4173 ( .A(n4428), .B(n4429), .Z(n4427)); - AN2 U4174 ( .A(n4430), .B(pi171), .Z(n4429)); - AN2 U4175 ( .A(n4431), .B(n4001), .Z(n4428)); - AN2 U4176 ( .A(n4432), .B(n2837), .Z(n4419)); - OR2 U4177 ( .A(n4433), .B(n4434), .Z(n4432)); - AN2 U4178 ( .A(n4435), .B(pi003), .Z(n4434)); - AN2 U4179 ( .A(n4436), .B(n4426), .Z(n4435)); - OR2 U4180 ( .A(n3244), .B(n3616), .Z(n4436)); - IV2 U4181 ( .A(n3593), .Z(n3616)); - AN2 U4182 ( .A(n4437), .B(n3597), .Z(n4433)); - OR2 U4183 ( .A(n4438), .B(n4439), .Z(n4437)); - AN2 U4184 ( .A(n4430), .B(pi142), .Z(n4439)); - AN2 U4185 ( .A(n4431), .B(n4440), .Z(n4438)); - AN2 U4186 ( .A(n3236), .B(n4441), .Z(n4431)); - OR2 U4187 ( .A(n4442), .B(n4443), .Z(po045)); - AN2 U4188 ( .A(n4444), .B(n4445), .Z(n4443)); - OR2 U4189 ( .A(n4446), .B(n3756), .Z(n4445)); - AN2 U4190 ( .A(n4006), .B(n4005), .Z(n4446)); - OR2 U4191 ( .A(n4447), .B(n4448), .Z(n4005)); - AN2 U4192 ( .A(n4449), .B(n3301), .Z(n4447)); - AN2 U4193 ( .A(n4450), .B(n3306), .Z(n4449)); - AN2 U4194 ( .A(n3757), .B(n4451), .Z(n4442)); - OR2 U4195 ( .A(n4452), .B(n4453), .Z(n4451)); - OR2 U4196 ( .A(n4454), .B(n4455), .Z(n4453)); - AN2 U4197 ( .A(po092), .B(n4456), .Z(n4455)); - OR2 U4198 ( .A(n4008), .B(n4004), .Z(n4456)); - AN2 U4199 ( .A(n4457), .B(n4458), .Z(n4008)); - AN2 U4200 ( .A(n4458), .B(n4459), .Z(n4454)); - OR2 U4201 ( .A(n4460), .B(n4461), .Z(n4459)); - AN2 U4202 ( .A(n4462), .B(n4463), .Z(n4461)); - AN2 U4203 ( .A(n4464), .B(n4465), .Z(n4462)); - AN2 U4204 ( .A(n4466), .B(n4467), .Z(n4460)); - AN2 U4205 ( .A(n4468), .B(n4469), .Z(n4466)); - OR2 U4206 ( .A(n4470), .B(n4471), .Z(po043)); - OR2 U4207 ( .A(n4472), .B(n4473), .Z(n4471)); - AN2 U4208 ( .A(n4474), .B(n4475), .Z(n4473)); - AN2 U4209 ( .A(n4476), .B(n4337), .Z(n4474)); - AN2 U4210 ( .A(n4477), .B(n4478), .Z(n4472)); - OR2 U4211 ( .A(n4479), .B(n4480), .Z(n4477)); - AN2 U4212 ( .A(n4337), .B(n4481), .Z(n4480)); - IV2 U4213 ( .A(n4342), .Z(n4337)); - AN2 U4214 ( .A(n4342), .B(n4476), .Z(n4479)); - IV2 U4215 ( .A(n4481), .Z(n4476)); - AN2 U4216 ( .A(n4482), .B(n4481), .Z(n4470)); - OR2 U4217 ( .A(n4483), .B(n4484), .Z(n4481)); - OR2 U4218 ( .A(n4485), .B(n4486), .Z(n4484)); - AN2 U4219 ( .A(n4487), .B(n4078), .Z(n4486)); - OR2 U4220 ( .A(n4488), .B(n4489), .Z(n4487)); - AN2 U4221 ( .A(n4490), .B(n3778), .Z(n4489)); - AN2 U4222 ( .A(n3773), .B(n4491), .Z(n4488)); - AN2 U4223 ( .A(n4492), .B(n4066), .Z(n4485)); - AN2 U4224 ( .A(n4490), .B(n3773), .Z(n4492)); - AN2 U4225 ( .A(n4491), .B(n4341), .Z(n4483)); - IV2 U4226 ( .A(n4490), .Z(n4491)); - OR2 U4227 ( .A(n4493), .B(n4494), .Z(n4490)); - IV2 U4228 ( .A(n4495), .Z(n4494)); - OR2 U4229 ( .A(n4496), .B(n4497), .Z(n4495)); - AN2 U4230 ( .A(n4497), .B(n4496), .Z(n4493)); - AN2 U4231 ( .A(n4498), .B(n4499), .Z(n4496)); - IV2 U4232 ( .A(n4500), .Z(n4499)); - AN2 U4233 ( .A(n4333), .B(n4501), .Z(n4500)); - OR2 U4234 ( .A(n4501), .B(n4333), .Z(n4498)); - OR2 U4235 ( .A(n4502), .B(n4503), .Z(n4501)); - OR2 U4236 ( .A(n4504), .B(n4505), .Z(n4503)); - OR2 U4237 ( .A(n4506), .B(n4507), .Z(n4505)); - AN2 U4238 ( .A(n4508), .B(n4509), .Z(n4507)); - AN2 U4239 ( .A(n4510), .B(n4511), .Z(n4506)); - AN2 U4240 ( .A(n4512), .B(n4513), .Z(n4504)); - OR2 U4241 ( .A(n4514), .B(n4515), .Z(n4502)); - AN2 U4242 ( .A(n4516), .B(n4517), .Z(n4515)); - AN2 U4243 ( .A(po102), .B(n4518), .Z(n4514)); - OR2 U4244 ( .A(n4519), .B(n4520), .Z(n4518)); - AN2 U4245 ( .A(n4513), .B(n4521), .Z(n4520)); - OR2 U4246 ( .A(n4522), .B(n4523), .Z(n4513)); - AN2 U4247 ( .A(n4508), .B(n3773), .Z(n4523)); - AN2 U4248 ( .A(po025), .B(n4516), .Z(n4522)); - AN2 U4249 ( .A(n4508), .B(n4524), .Z(n4519)); - IV2 U4250 ( .A(n4510), .Z(n4508)); - OR2 U4251 ( .A(n4525), .B(n4526), .Z(n4510)); - AN2 U4252 ( .A(n4527), .B(n4528), .Z(n4526)); - OR2 U4253 ( .A(n4529), .B(n4530), .Z(n4527)); - OR2 U4254 ( .A(n4531), .B(n4532), .Z(n4530)); - AN2 U4255 ( .A(po025), .B(n4533), .Z(n4532)); - OR2 U4256 ( .A(n4534), .B(n4535), .Z(n4533)); - OR2 U4257 ( .A(n4356), .B(n4536), .Z(n4535)); - AN2 U4258 ( .A(n4537), .B(n4538), .Z(n4536)); - AN2 U4259 ( .A(n4539), .B(n4540), .Z(n4537)); - AN2 U4260 ( .A(n3890), .B(n4541), .Z(n4534)); - OR2 U4261 ( .A(n4542), .B(n4543), .Z(n4541)); - AN2 U4262 ( .A(n4085), .B(n4544), .Z(n4542)); - AN2 U4263 ( .A(n3778), .B(n4545), .Z(n4531)); - OR2 U4264 ( .A(n4546), .B(n4547), .Z(n4545)); - OR2 U4265 ( .A(n4548), .B(n4549), .Z(n4547)); - AN2 U4266 ( .A(n3775), .B(n4550), .Z(n4549)); - AN2 U4267 ( .A(n4524), .B(n4333), .Z(n4548)); - AN2 U4268 ( .A(n4086), .B(n4551), .Z(n4546)); - OR2 U4269 ( .A(n4552), .B(n4553), .Z(n4529)); - AN2 U4270 ( .A(n4554), .B(n4555), .Z(n4553)); - OR2 U4271 ( .A(n4556), .B(n3888), .Z(n4555)); - AN2 U4272 ( .A(pi192), .B(n4557), .Z(n4556)); - AN2 U4273 ( .A(n4558), .B(n4559), .Z(n4554)); - OR2 U4274 ( .A(n4085), .B(n4560), .Z(n4558)); - AN2 U4275 ( .A(n4561), .B(n3773), .Z(n4560)); - AN2 U4276 ( .A(n4562), .B(n4563), .Z(n4552)); - OR2 U4277 ( .A(n4564), .B(n4565), .Z(n4563)); - AN2 U4278 ( .A(n4566), .B(n4567), .Z(n4564)); - AN2 U4279 ( .A(n3773), .B(n4076), .Z(n4566)); - OR2 U4280 ( .A(pi076), .B(n4557), .Z(n4562)); - AN2 U4281 ( .A(n4516), .B(n4568), .Z(n4525)); - OR2 U4282 ( .A(n4569), .B(n4570), .Z(n4568)); - OR2 U4283 ( .A(n4571), .B(n4572), .Z(n4570)); - OR2 U4284 ( .A(n4573), .B(n4574), .Z(n4572)); - AN2 U4285 ( .A(n4575), .B(n4576), .Z(n4574)); - AN2 U4286 ( .A(n4577), .B(n4076), .Z(n4575)); - AN2 U4287 ( .A(n3773), .B(n4578), .Z(n4577)); - AN2 U4288 ( .A(n4579), .B(n4580), .Z(n4573)); - OR2 U4289 ( .A(n4581), .B(n4565), .Z(n4579)); - AN2 U4290 ( .A(n4539), .B(n4582), .Z(n4565)); - AN2 U4291 ( .A(n2837), .B(n4550), .Z(n4582)); - IV2 U4292 ( .A(n4540), .Z(n4550)); - AN2 U4293 ( .A(n4567), .B(n4076), .Z(n4581)); - AN2 U4294 ( .A(n4086), .B(n4583), .Z(n4571)); - OR2 U4295 ( .A(n4584), .B(n4585), .Z(n4583)); - AN2 U4296 ( .A(n4543), .B(n3773), .Z(n4585)); - AN2 U4297 ( .A(n4586), .B(n4544), .Z(n4584)); - OR2 U4298 ( .A(n4085), .B(n3778), .Z(n4586)); - AN2 U4299 ( .A(n4557), .B(n3888), .Z(n4086)); - OR2 U4300 ( .A(n4587), .B(n4588), .Z(n4569)); - AN2 U4301 ( .A(n4589), .B(n4590), .Z(n4588)); - OR2 U4302 ( .A(n4591), .B(n3890), .Z(n4590)); - AN2 U4303 ( .A(po025), .B(pi192), .Z(n4591)); - AN2 U4304 ( .A(n4559), .B(n4592), .Z(n4589)); - OR2 U4305 ( .A(n4561), .B(n4085), .Z(n4592)); - OR2 U4306 ( .A(n4551), .B(n4353), .Z(n4559)); - AN2 U4307 ( .A(n4593), .B(n3775), .Z(n4587)); - AN2 U4308 ( .A(n2837), .B(n4576), .Z(n3775)); - AN2 U4309 ( .A(n4594), .B(n4540), .Z(n4593)); - OR2 U4310 ( .A(n4567), .B(n4066), .Z(n4540)); - OR2 U4311 ( .A(n4539), .B(n3778), .Z(n4594)); - IV2 U4312 ( .A(n4528), .Z(n4516)); - OR2 U4313 ( .A(n4595), .B(n4596), .Z(n4497)); - AN2 U4314 ( .A(n4597), .B(n4598), .Z(n4596)); - OR2 U4315 ( .A(n4599), .B(n4600), .Z(n4598)); - AN2 U4316 ( .A(n4601), .B(n4602), .Z(n4600)); - IV2 U4317 ( .A(n4603), .Z(n4599)); - OR2 U4318 ( .A(n4602), .B(n4601), .Z(n4603)); - OR2 U4319 ( .A(n4604), .B(n4605), .Z(n4601)); - AN2 U4320 ( .A(n3295), .B(n4606), .Z(n4605)); - AN2 U4321 ( .A(n4450), .B(n3301), .Z(n4604)); - AN2 U4322 ( .A(n4607), .B(n4608), .Z(n4602)); - OR2 U4323 ( .A(n4609), .B(n4610), .Z(n4608)); - IV2 U4324 ( .A(n4611), .Z(n4610)); - OR2 U4325 ( .A(n4611), .B(n4612), .Z(n4607)); - IV2 U4326 ( .A(n4609), .Z(n4612)); - OR2 U4327 ( .A(n4613), .B(n4614), .Z(n4609)); - OR2 U4328 ( .A(n4615), .B(n4616), .Z(n4614)); - AN2 U4329 ( .A(n4004), .B(n4617), .Z(n4616)); - OR2 U4330 ( .A(n4618), .B(n4619), .Z(n4617)); - AN2 U4331 ( .A(n4620), .B(n4463), .Z(n4619)); - AN2 U4332 ( .A(n4621), .B(n4464), .Z(n4620)); - AN2 U4333 ( .A(n4622), .B(n4467), .Z(n4618)); - AN2 U4334 ( .A(n4623), .B(n4468), .Z(n4622)); - AN2 U4335 ( .A(n4006), .B(n4624), .Z(n4615)); - OR2 U4336 ( .A(n4625), .B(n4626), .Z(n4613)); - AN2 U4337 ( .A(n4627), .B(n4628), .Z(n4626)); - OR2 U4338 ( .A(n4629), .B(n4630), .Z(n4627)); - AN2 U4339 ( .A(n4631), .B(pi192), .Z(n4630)); - AN2 U4340 ( .A(n4632), .B(pi158), .Z(n4631)); - AN2 U4341 ( .A(n4633), .B(n4634), .Z(n4632)); - OR2 U4342 ( .A(n4635), .B(n4465), .Z(n4634)); - OR2 U4343 ( .A(n4464), .B(n4636), .Z(n4633)); - OR2 U4344 ( .A(n4621), .B(n3301), .Z(n4636)); - AN2 U4345 ( .A(n4637), .B(n2837), .Z(n4629)); - AN2 U4346 ( .A(n4638), .B(pi151), .Z(n4637)); - AN2 U4347 ( .A(n4639), .B(n4640), .Z(n4638)); - OR2 U4348 ( .A(n4641), .B(n4469), .Z(n4640)); - OR2 U4349 ( .A(n4468), .B(n4642), .Z(n4639)); - OR2 U4350 ( .A(n4623), .B(n3301), .Z(n4642)); - AN2 U4351 ( .A(n4643), .B(po092), .Z(n4625)); - AN2 U4352 ( .A(n4644), .B(n3295), .Z(n4643)); - AN2 U4353 ( .A(n4645), .B(n4646), .Z(n4644)); - OR2 U4354 ( .A(pi192), .B(n4647), .Z(n4646)); - AN2 U4355 ( .A(n4641), .B(n4648), .Z(n4647)); - OR2 U4356 ( .A(n2837), .B(n4649), .Z(n4645)); - AN2 U4357 ( .A(n4635), .B(n3908), .Z(n4649)); - IV2 U4358 ( .A(n3761), .Z(n4597)); - AN2 U4359 ( .A(n4650), .B(n3761), .Z(n4595)); - OR2 U4360 ( .A(n4651), .B(n4652), .Z(n3761)); - AN2 U4361 ( .A(n4653), .B(n4654), .Z(n4651)); - AN2 U4362 ( .A(n4333), .B(n4528), .Z(n4654)); - OR2 U4363 ( .A(n4655), .B(n4656), .Z(n4528)); - AN2 U4364 ( .A(n4657), .B(n3083), .Z(n4655)); - AN2 U4365 ( .A(n3018), .B(n4658), .Z(n4657)); - OR2 U4366 ( .A(n4659), .B(n4660), .Z(n4658)); - OR2 U4367 ( .A(n4661), .B(n4662), .Z(n4660)); - AN2 U4368 ( .A(n4663), .B(n3010), .Z(n4662)); - AN2 U4369 ( .A(n4664), .B(n3049), .Z(n4661)); - OR2 U4370 ( .A(n4665), .B(n4663), .Z(n4664)); - AN2 U4371 ( .A(n4666), .B(n3010), .Z(n4665)); - OR2 U4372 ( .A(n3100), .B(n4667), .Z(n4659)); - AN2 U4373 ( .A(n4668), .B(n3012), .Z(n4667)); - OR2 U4374 ( .A(n4669), .B(n4670), .Z(n4668)); - AN2 U4375 ( .A(n4671), .B(pi201), .Z(n4670)); - AN2 U4376 ( .A(n4672), .B(n3115), .Z(n4671)); - OR2 U4377 ( .A(n4673), .B(n3173), .Z(n4672)); - AN2 U4378 ( .A(n2837), .B(n3049), .Z(n4673)); - AN2 U4379 ( .A(n4674), .B(pi088), .Z(n4669)); - AN2 U4380 ( .A(n4675), .B(n3108), .Z(n4674)); - OR2 U4381 ( .A(n4676), .B(n3064), .Z(n4675)); - AN2 U4382 ( .A(pi192), .B(n3049), .Z(n4676)); - AN2 U4383 ( .A(n4341), .B(n4482), .Z(n4653)); - OR2 U4384 ( .A(n4677), .B(n4678), .Z(n4650)); - OR2 U4385 ( .A(n4679), .B(n4680), .Z(n4678)); - OR2 U4386 ( .A(n4681), .B(n4682), .Z(n4680)); - AN2 U4387 ( .A(n4683), .B(n4684), .Z(n4682)); - AN2 U4388 ( .A(n4685), .B(n4648), .Z(n4683)); - AN2 U4389 ( .A(n4686), .B(n4687), .Z(n4681)); - OR2 U4390 ( .A(n4688), .B(n4689), .Z(n4687)); - OR2 U4391 ( .A(n4690), .B(n4691), .Z(n4689)); - AN2 U4392 ( .A(n4692), .B(n4621), .Z(n4691)); - AN2 U4393 ( .A(n4685), .B(n4623), .Z(n4690)); - AN2 U4394 ( .A(n4693), .B(n3300), .Z(n4688)); - IV2 U4395 ( .A(n4684), .Z(n4686)); - OR2 U4396 ( .A(n4694), .B(n4695), .Z(n4679)); - AN2 U4397 ( .A(n4696), .B(n3300), .Z(n4695)); - AN2 U4398 ( .A(po014), .B(n4684), .Z(n4696)); - OR2 U4399 ( .A(n4697), .B(n4698), .Z(n4684)); - AN2 U4400 ( .A(n4699), .B(n4450), .Z(n4697)); - AN2 U4401 ( .A(po039), .B(n4700), .Z(n4694)); - OR2 U4402 ( .A(n4701), .B(n4702), .Z(n4700)); - AN2 U4403 ( .A(n4698), .B(n4703), .Z(n4702)); - AN2 U4404 ( .A(n4704), .B(n4606), .Z(n4698)); - AN2 U4405 ( .A(n4705), .B(n4706), .Z(n4701)); - AN2 U4406 ( .A(n4707), .B(n4708), .Z(n4705)); - OR2 U4407 ( .A(n4704), .B(n3295), .Z(n4708)); - OR2 U4408 ( .A(n4699), .B(n3301), .Z(n4707)); - OR2 U4409 ( .A(n4709), .B(n4710), .Z(n4677)); - AN2 U4410 ( .A(n4711), .B(n4699), .Z(n4710)); - IV2 U4411 ( .A(n4704), .Z(n4699)); - AN2 U4412 ( .A(n4450), .B(n4712), .Z(n4711)); - OR2 U4413 ( .A(po014), .B(n3301), .Z(n4712)); - AN2 U4414 ( .A(n4713), .B(n4704), .Z(n4709)); - OR2 U4415 ( .A(n4714), .B(n4715), .Z(n4704)); - OR2 U4416 ( .A(n4716), .B(n4717), .Z(n4715)); - OR2 U4417 ( .A(n4718), .B(n4719), .Z(n4717)); - IV2 U4418 ( .A(n4720), .Z(n4719)); - OR2 U4419 ( .A(n4721), .B(n4006), .Z(n4720)); - OR2 U4420 ( .A(n4444), .B(n3756), .Z(n4721)); - AN2 U4421 ( .A(n4722), .B(n4006), .Z(n4718)); - AN2 U4422 ( .A(n4444), .B(n4452), .Z(n4722)); - OR2 U4423 ( .A(n4723), .B(n4724), .Z(n4452)); - OR2 U4424 ( .A(n4725), .B(n4726), .Z(n4724)); - AN2 U4425 ( .A(po092), .B(n4009), .Z(n4726)); - OR2 U4426 ( .A(n4727), .B(n4728), .Z(n4009)); - AN2 U4427 ( .A(n3295), .B(n4729), .Z(n4728)); - AN2 U4428 ( .A(n4606), .B(n4457), .Z(n4727)); - OR2 U4429 ( .A(n4730), .B(n4706), .Z(n4457)); - OR2 U4430 ( .A(n4731), .B(n4732), .Z(n4706)); - AN2 U4431 ( .A(n4733), .B(pi192), .Z(n4732)); - AN2 U4432 ( .A(n4465), .B(n3870), .Z(n4733)); - AN2 U4433 ( .A(n4734), .B(n2837), .Z(n4731)); - AN2 U4434 ( .A(n4469), .B(n4735), .Z(n4734)); - AN2 U4435 ( .A(po039), .B(n4729), .Z(n4730)); - OR2 U4436 ( .A(po014), .B(n4736), .Z(n4729)); - AN2 U4437 ( .A(n4737), .B(n4606), .Z(n4725)); - AN2 U4438 ( .A(po014), .B(n4738), .Z(n4737)); - OR2 U4439 ( .A(n4739), .B(n4740), .Z(n4738)); - AN2 U4440 ( .A(n4463), .B(n4464), .Z(n4740)); - AN2 U4441 ( .A(n4467), .B(n4468), .Z(n4739)); - OR2 U4442 ( .A(n4741), .B(n4742), .Z(n4723)); - AN2 U4443 ( .A(n4743), .B(n4463), .Z(n4742)); - AN2 U4444 ( .A(n3909), .B(pi192), .Z(n4463)); - IV2 U4445 ( .A(pi158), .Z(n3909)); - AN2 U4446 ( .A(n4744), .B(n3908), .Z(n4743)); - OR2 U4447 ( .A(n4745), .B(n3295), .Z(n4744)); - AN2 U4448 ( .A(n4606), .B(n4464), .Z(n4745)); - AN2 U4449 ( .A(n4746), .B(n4467), .Z(n4741)); - AN2 U4450 ( .A(n2837), .B(n4747), .Z(n4467)); - AN2 U4451 ( .A(n4748), .B(n4648), .Z(n4746)); - OR2 U4452 ( .A(n4749), .B(n3295), .Z(n4748)); - AN2 U4453 ( .A(n4606), .B(n4468), .Z(n4749)); - AN2 U4454 ( .A(n3756), .B(n4611), .Z(n4716)); - OR2 U4455 ( .A(n4750), .B(n4751), .Z(n4611)); - AN2 U4456 ( .A(n4004), .B(n4444), .Z(n4750)); - IV2 U4457 ( .A(n4006), .Z(n4004)); - AN2 U4458 ( .A(n4628), .B(n4752), .Z(n3756)); - OR2 U4459 ( .A(n3758), .B(n3760), .Z(n4714)); - AN2 U4460 ( .A(n4448), .B(n4751), .Z(n3758)); - OR2 U4461 ( .A(n4713), .B(n4693), .Z(n4448)); - OR2 U4462 ( .A(n4753), .B(n4754), .Z(n4693)); - AN2 U4463 ( .A(n4621), .B(pi192), .Z(n4754)); - AN2 U4464 ( .A(n4623), .B(n2837), .Z(n4753)); - AN2 U4465 ( .A(n3301), .B(n4624), .Z(n4713)); - OR2 U4466 ( .A(n4755), .B(n4756), .Z(po042)); - AN2 U4467 ( .A(n4757), .B(n2837), .Z(n4756)); - OR2 U4468 ( .A(n4758), .B(n4759), .Z(n4757)); - OR2 U4469 ( .A(n4760), .B(n4761), .Z(n4759)); - AN2 U4470 ( .A(n4762), .B(n4763), .Z(n4761)); - OR2 U4471 ( .A(n4764), .B(n4765), .Z(n4763)); - IV2 U4472 ( .A(n4766), .Z(n4762)); - AN2 U4473 ( .A(n4765), .B(n4764), .Z(n4766)); - OR2 U4474 ( .A(n4767), .B(n4768), .Z(n4764)); - AN2 U4475 ( .A(n4769), .B(n4770), .Z(n4768)); - AN2 U4476 ( .A(n4771), .B(pi028), .Z(n4767)); - AN2 U4477 ( .A(n4772), .B(n4773), .Z(n4765)); - OR2 U4478 ( .A(n4774), .B(pi094), .Z(n4773)); - IV2 U4479 ( .A(n4775), .Z(n4772)); - AN2 U4480 ( .A(n4774), .B(pi094), .Z(n4775)); - AN2 U4481 ( .A(n4776), .B(n4777), .Z(n4774)); - OR2 U4482 ( .A(n4778), .B(pi173), .Z(n4777)); - OR2 U4483 ( .A(n4779), .B(pi163), .Z(n4776)); - IV2 U4484 ( .A(pi173), .Z(n4779)); - AN2 U4485 ( .A(n4780), .B(n4781), .Z(n4760)); - IV2 U4486 ( .A(n4782), .Z(n4781)); - AN2 U4487 ( .A(n4783), .B(n4784), .Z(n4782)); - OR2 U4488 ( .A(n4784), .B(n4783), .Z(n4780)); - AN2 U4489 ( .A(n4785), .B(n4786), .Z(n4783)); - IV2 U4490 ( .A(n4787), .Z(n4786)); - AN2 U4491 ( .A(n4788), .B(n4789), .Z(n4787)); - OR2 U4492 ( .A(n4789), .B(n4788), .Z(n4785)); - OR2 U4493 ( .A(n4790), .B(n4791), .Z(n4788)); - AN2 U4494 ( .A(pi025), .B(n4792), .Z(n4791)); - IV2 U4495 ( .A(n4793), .Z(n4790)); - OR2 U4496 ( .A(n4792), .B(pi025), .Z(n4793)); - IV2 U4497 ( .A(pi035), .Z(n4792)); - AN2 U4498 ( .A(n4794), .B(n4795), .Z(n4789)); - IV2 U4499 ( .A(n4796), .Z(n4795)); - AN2 U4500 ( .A(pi056), .B(n4797), .Z(n4796)); - OR2 U4501 ( .A(n4797), .B(pi056), .Z(n4794)); - IV2 U4502 ( .A(pi100), .Z(n4797)); - OR2 U4503 ( .A(n4798), .B(n4799), .Z(n4784)); - IV2 U4504 ( .A(n4800), .Z(n4799)); - OR2 U4505 ( .A(n4801), .B(n4802), .Z(n4800)); - AN2 U4506 ( .A(n4802), .B(n4801), .Z(n4798)); - AN2 U4507 ( .A(n4803), .B(n4804), .Z(n4801)); - IV2 U4508 ( .A(n4805), .Z(n4804)); - AN2 U4509 ( .A(pi126), .B(n4806), .Z(n4805)); - OR2 U4510 ( .A(n4806), .B(pi126), .Z(n4803)); - IV2 U4511 ( .A(pi146), .Z(n4806)); - OR2 U4512 ( .A(n4807), .B(n4808), .Z(n4802)); - AN2 U4513 ( .A(pi190), .B(n4809), .Z(n4808)); - IV2 U4514 ( .A(pi202), .Z(n4809)); - AN2 U4515 ( .A(pi202), .B(n4810), .Z(n4807)); - IV2 U4516 ( .A(pi190), .Z(n4810)); - OR2 U4517 ( .A(n4811), .B(n4812), .Z(n4758)); - AN2 U4518 ( .A(n4813), .B(n4814), .Z(n4812)); - IV2 U4519 ( .A(n4815), .Z(n4814)); - AN2 U4520 ( .A(n4816), .B(n4817), .Z(n4815)); - OR2 U4521 ( .A(n4817), .B(n4816), .Z(n4813)); - AN2 U4522 ( .A(n4818), .B(n4819), .Z(n4816)); - OR2 U4523 ( .A(n4820), .B(pi019), .Z(n4819)); - OR2 U4524 ( .A(n4821), .B(n4822), .Z(n4818)); - IV2 U4525 ( .A(pi019), .Z(n4822)); - OR2 U4526 ( .A(n4823), .B(n4824), .Z(n4817)); - IV2 U4527 ( .A(n4825), .Z(n4824)); - OR2 U4528 ( .A(n4826), .B(pi085), .Z(n4825)); - AN2 U4529 ( .A(n4826), .B(pi085), .Z(n4823)); - AN2 U4530 ( .A(n4827), .B(n4828), .Z(n4826)); - OR2 U4531 ( .A(n4829), .B(pi167), .Z(n4828)); - IV2 U4532 ( .A(pi110), .Z(n4829)); - OR2 U4533 ( .A(n4830), .B(pi110), .Z(n4827)); - IV2 U4534 ( .A(pi167), .Z(n4830)); - AN2 U4535 ( .A(n4831), .B(n4832), .Z(n4811)); - IV2 U4536 ( .A(n4833), .Z(n4832)); - AN2 U4537 ( .A(n4834), .B(n4835), .Z(n4833)); - OR2 U4538 ( .A(n4835), .B(n4834), .Z(n4831)); - AN2 U4539 ( .A(n4836), .B(n4837), .Z(n4834)); - OR2 U4540 ( .A(n4838), .B(pi020), .Z(n4837)); - OR2 U4541 ( .A(n4839), .B(n4840), .Z(n4836)); - IV2 U4542 ( .A(pi020), .Z(n4840)); - OR2 U4543 ( .A(n4841), .B(n4842), .Z(n4835)); - IV2 U4544 ( .A(n4843), .Z(n4842)); - OR2 U4545 ( .A(n4844), .B(pi047), .Z(n4843)); - AN2 U4546 ( .A(n4844), .B(pi047), .Z(n4841)); - AN2 U4547 ( .A(n4845), .B(n4846), .Z(n4844)); - OR2 U4548 ( .A(n4847), .B(pi153), .Z(n4846)); - IV2 U4549 ( .A(pi075), .Z(n4847)); - OR2 U4550 ( .A(n4848), .B(pi075), .Z(n4845)); - IV2 U4551 ( .A(pi153), .Z(n4848)); - AN2 U4552 ( .A(pi192), .B(n4849), .Z(n4755)); - OR2 U4553 ( .A(n4850), .B(n4851), .Z(n4849)); - OR2 U4554 ( .A(n4852), .B(n4853), .Z(n4851)); - AN2 U4555 ( .A(n4854), .B(n4855), .Z(n4853)); - OR2 U4556 ( .A(n4856), .B(n4857), .Z(n4855)); - IV2 U4557 ( .A(n4858), .Z(n4854)); - AN2 U4558 ( .A(n4857), .B(n4856), .Z(n4858)); - OR2 U4559 ( .A(n4859), .B(n4860), .Z(n4856)); - AN2 U4560 ( .A(n4839), .B(n4861), .Z(n4860)); - AN2 U4561 ( .A(n4838), .B(po014), .Z(n4859)); - IV2 U4562 ( .A(n4839), .Z(n4838)); - OR2 U4563 ( .A(n4862), .B(n4863), .Z(n4839)); - AN2 U4564 ( .A(n4864), .B(pi192), .Z(n4863)); - OR2 U4565 ( .A(n4865), .B(n4866), .Z(n4864)); - IV2 U4566 ( .A(n4867), .Z(n4866)); - OR2 U4567 ( .A(n4868), .B(n4869), .Z(n4867)); - AN2 U4568 ( .A(n4869), .B(n4868), .Z(n4865)); - AN2 U4569 ( .A(n4870), .B(n4871), .Z(n4868)); - OR2 U4570 ( .A(n4872), .B(po024), .Z(n4871)); - IV2 U4571 ( .A(n4873), .Z(n4872)); - OR2 U4572 ( .A(n4873), .B(n4874), .Z(n4870)); - OR2 U4573 ( .A(n4875), .B(n4876), .Z(n4873)); - AN2 U4574 ( .A(po025), .B(n4877), .Z(n4876)); - AN2 U4575 ( .A(po059), .B(n4557), .Z(n4875)); - OR2 U4576 ( .A(n4878), .B(n4879), .Z(n4869)); - AN2 U4577 ( .A(n4880), .B(n4881), .Z(n4879)); - AN2 U4578 ( .A(n4882), .B(po072), .Z(n4878)); - IV2 U4579 ( .A(n4880), .Z(n4882)); - OR2 U4580 ( .A(n4883), .B(n4884), .Z(n4880)); - AN2 U4581 ( .A(po084), .B(n4885), .Z(n4884)); - AN2 U4582 ( .A(po102), .B(n4886), .Z(n4883)); - IV2 U4583 ( .A(po084), .Z(n4886)); - AN2 U4584 ( .A(n4887), .B(n2837), .Z(n4862)); - OR2 U4585 ( .A(n4888), .B(n4889), .Z(n4887)); - AN2 U4586 ( .A(n4890), .B(n4891), .Z(n4889)); - IV2 U4587 ( .A(n4892), .Z(n4888)); - OR2 U4588 ( .A(n4891), .B(n4890), .Z(n4892)); - OR2 U4589 ( .A(n4893), .B(n4894), .Z(n4890)); - IV2 U4590 ( .A(n4895), .Z(n4894)); - OR2 U4591 ( .A(n4896), .B(pi014), .Z(n4895)); - AN2 U4592 ( .A(n4896), .B(pi014), .Z(n4893)); - AN2 U4593 ( .A(n4897), .B(n4898), .Z(n4896)); - OR2 U4594 ( .A(n4899), .B(pi111), .Z(n4898)); - OR2 U4595 ( .A(n4900), .B(pi097), .Z(n4897)); - IV2 U4596 ( .A(pi111), .Z(n4900)); - AN2 U4597 ( .A(n4901), .B(n4902), .Z(n4891)); - OR2 U4598 ( .A(n4903), .B(pi143), .Z(n4902)); - IV2 U4599 ( .A(n4904), .Z(n4901)); - AN2 U4600 ( .A(n4903), .B(pi143), .Z(n4904)); - AN2 U4601 ( .A(n4905), .B(n4906), .Z(n4903)); - OR2 U4602 ( .A(n4907), .B(pi189), .Z(n4906)); - IV2 U4603 ( .A(n4908), .Z(n4905)); - AN2 U4604 ( .A(pi189), .B(n4907), .Z(n4908)); - IV2 U4605 ( .A(pi176), .Z(n4907)); - AN2 U4606 ( .A(n4909), .B(n4910), .Z(n4857)); - OR2 U4607 ( .A(n4911), .B(po039), .Z(n4910)); - IV2 U4608 ( .A(n4912), .Z(n4911)); - OR2 U4609 ( .A(n4912), .B(n3300), .Z(n4909)); - OR2 U4610 ( .A(n4913), .B(n4914), .Z(n4912)); - AN2 U4611 ( .A(po063), .B(n4628), .Z(n4914)); - AN2 U4612 ( .A(po092), .B(n4915), .Z(n4913)); - AN2 U4613 ( .A(n4916), .B(n4917), .Z(n4852)); - IV2 U4614 ( .A(n4918), .Z(n4917)); - AN2 U4615 ( .A(n4919), .B(n4920), .Z(n4918)); - OR2 U4616 ( .A(n4920), .B(n4919), .Z(n4916)); - IV2 U4617 ( .A(n4921), .Z(n4919)); - OR2 U4618 ( .A(n4922), .B(n4923), .Z(n4921)); - AN2 U4619 ( .A(n4821), .B(n3391), .Z(n4923)); - IV2 U4620 ( .A(n4924), .Z(n3391)); - AN2 U4621 ( .A(n4924), .B(n4820), .Z(n4922)); - IV2 U4622 ( .A(n4821), .Z(n4820)); - OR2 U4623 ( .A(n4925), .B(n4926), .Z(n4821)); - AN2 U4624 ( .A(n4927), .B(pi192), .Z(n4926)); - OR2 U4625 ( .A(n4928), .B(n4929), .Z(n4927)); - IV2 U4626 ( .A(n4930), .Z(n4929)); - OR2 U4627 ( .A(n4931), .B(n4932), .Z(n4930)); - AN2 U4628 ( .A(n4932), .B(n4931), .Z(n4928)); - AN2 U4629 ( .A(n4933), .B(n4934), .Z(n4931)); - OR2 U4630 ( .A(n4935), .B(po001), .Z(n4934)); - IV2 U4631 ( .A(n4936), .Z(n4935)); - OR2 U4632 ( .A(n4936), .B(n4937), .Z(n4933)); - OR2 U4633 ( .A(n4938), .B(n4939), .Z(n4936)); - AN2 U4634 ( .A(po011), .B(n4441), .Z(n4939)); - AN2 U4635 ( .A(po036), .B(n3688), .Z(n4938)); - OR2 U4636 ( .A(n4940), .B(n4941), .Z(n4932)); - AN2 U4637 ( .A(n4942), .B(n4943), .Z(n4941)); - AN2 U4638 ( .A(n4944), .B(po057), .Z(n4940)); - IV2 U4639 ( .A(n4942), .Z(n4944)); - OR2 U4640 ( .A(n4945), .B(n4946), .Z(n4942)); - AN2 U4641 ( .A(po069), .B(n4947), .Z(n4946)); - AN2 U4642 ( .A(po082), .B(n4948), .Z(n4945)); - IV2 U4643 ( .A(po069), .Z(n4948)); - AN2 U4644 ( .A(n4949), .B(n2837), .Z(n4925)); - OR2 U4645 ( .A(n4950), .B(n4951), .Z(n4949)); - AN2 U4646 ( .A(n4952), .B(n4953), .Z(n4951)); - IV2 U4647 ( .A(n4954), .Z(n4950)); - OR2 U4648 ( .A(n4953), .B(n4952), .Z(n4954)); - OR2 U4649 ( .A(n4955), .B(n4956), .Z(n4952)); - IV2 U4650 ( .A(n4957), .Z(n4956)); - OR2 U4651 ( .A(n4958), .B(pi024), .Z(n4957)); - AN2 U4652 ( .A(n4958), .B(pi024), .Z(n4955)); - AN2 U4653 ( .A(n4959), .B(n4960), .Z(n4958)); - OR2 U4654 ( .A(n4961), .B(pi078), .Z(n4960)); - OR2 U4655 ( .A(n4962), .B(pi030), .Z(n4959)); - IV2 U4656 ( .A(pi078), .Z(n4962)); - AN2 U4657 ( .A(n4963), .B(n4964), .Z(n4953)); - OR2 U4658 ( .A(n4965), .B(pi087), .Z(n4964)); - IV2 U4659 ( .A(n4966), .Z(n4963)); - AN2 U4660 ( .A(n4965), .B(pi087), .Z(n4966)); - AN2 U4661 ( .A(n4967), .B(n4968), .Z(n4965)); - OR2 U4662 ( .A(n4969), .B(pi164), .Z(n4968)); - OR2 U4663 ( .A(n4970), .B(pi159), .Z(n4967)); - IV2 U4664 ( .A(pi164), .Z(n4970)); - OR2 U4665 ( .A(n4971), .B(n4972), .Z(n4924)); - AN2 U4666 ( .A(po027), .B(n3512), .Z(n4972)); - AN2 U4667 ( .A(po104), .B(n3363), .Z(n4971)); - OR2 U4668 ( .A(n4973), .B(n4974), .Z(n4920)); - AN2 U4669 ( .A(po038), .B(n3380), .Z(n4974)); - AN2 U4670 ( .A(po071), .B(n4975), .Z(n4973)); - OR2 U4671 ( .A(n4976), .B(n4977), .Z(n4850)); - AN2 U4672 ( .A(n4978), .B(n4979), .Z(n4977)); - OR2 U4673 ( .A(n4980), .B(n4981), .Z(n4979)); - IV2 U4674 ( .A(n4982), .Z(n4978)); - AN2 U4675 ( .A(n4981), .B(n4980), .Z(n4982)); - OR2 U4676 ( .A(n4983), .B(n4984), .Z(n4980)); - AN2 U4677 ( .A(n4769), .B(n3049), .Z(n4984)); - AN2 U4678 ( .A(n4771), .B(po010), .Z(n4983)); - IV2 U4679 ( .A(n4769), .Z(n4771)); - OR2 U4680 ( .A(n4985), .B(n4986), .Z(n4769)); - AN2 U4681 ( .A(n4987), .B(pi192), .Z(n4986)); - OR2 U4682 ( .A(n4988), .B(n4989), .Z(n4987)); - IV2 U4683 ( .A(n4990), .Z(n4989)); - OR2 U4684 ( .A(n4991), .B(n4992), .Z(n4990)); - AN2 U4685 ( .A(n4992), .B(n4991), .Z(n4988)); - AN2 U4686 ( .A(n4993), .B(n4994), .Z(n4991)); - OR2 U4687 ( .A(n4995), .B(po031), .Z(n4994)); - IV2 U4688 ( .A(n4996), .Z(n4995)); - OR2 U4689 ( .A(n4996), .B(n2962), .Z(n4993)); - OR2 U4690 ( .A(n4997), .B(n4998), .Z(n4996)); - AN2 U4691 ( .A(po044), .B(n4999), .Z(n4998)); - IV2 U4692 ( .A(po052), .Z(n4999)); - AN2 U4693 ( .A(po052), .B(n5000), .Z(n4997)); - OR2 U4694 ( .A(n5001), .B(n5002), .Z(n4992)); - AN2 U4695 ( .A(n5003), .B(n5004), .Z(n5002)); - AN2 U4696 ( .A(n5005), .B(po079), .Z(n5001)); - IV2 U4697 ( .A(n5003), .Z(n5005)); - OR2 U4698 ( .A(n5006), .B(n5007), .Z(n5003)); - AN2 U4699 ( .A(po106), .B(n2931), .Z(n5007)); - AN2 U4700 ( .A(po107), .B(n5008), .Z(n5006)); - AN2 U4701 ( .A(n5009), .B(n2837), .Z(n4985)); - OR2 U4702 ( .A(n5010), .B(n5011), .Z(n5009)); - IV2 U4703 ( .A(n5012), .Z(n5011)); - OR2 U4704 ( .A(n5013), .B(n5014), .Z(n5012)); - AN2 U4705 ( .A(n5014), .B(n5013), .Z(n5010)); - AN2 U4706 ( .A(n5015), .B(n5016), .Z(n5013)); - OR2 U4707 ( .A(n5017), .B(pi011), .Z(n5016)); - IV2 U4708 ( .A(n5018), .Z(n5017)); - OR2 U4709 ( .A(n5018), .B(n5019), .Z(n5015)); - OR2 U4710 ( .A(n5020), .B(n5021), .Z(n5018)); - AN2 U4711 ( .A(pi021), .B(n5022), .Z(n5021)); - AN2 U4712 ( .A(pi032), .B(n5023), .Z(n5020)); - IV2 U4713 ( .A(pi021), .Z(n5023)); - OR2 U4714 ( .A(n5024), .B(n5025), .Z(n5014)); - AN2 U4715 ( .A(n5026), .B(n5027), .Z(n5025)); - AN2 U4716 ( .A(n5028), .B(pi086), .Z(n5024)); - IV2 U4717 ( .A(n5026), .Z(n5028)); - OR2 U4718 ( .A(n5029), .B(n5030), .Z(n5026)); - AN2 U4719 ( .A(pi115), .B(n5031), .Z(n5030)); - AN2 U4720 ( .A(pi165), .B(n5032), .Z(n5029)); - IV2 U4721 ( .A(pi115), .Z(n5032)); - AN2 U4722 ( .A(n5033), .B(n5034), .Z(n4981)); - OR2 U4723 ( .A(n5035), .B(po035), .Z(n5034)); - IV2 U4724 ( .A(n5036), .Z(n5035)); - OR2 U4725 ( .A(n5036), .B(n5037), .Z(n5033)); - OR2 U4726 ( .A(n5038), .B(n5039), .Z(n5036)); - AN2 U4727 ( .A(po070), .B(n3286), .Z(n5039)); - AN2 U4728 ( .A(po099), .B(n5040), .Z(n5038)); - AN2 U4729 ( .A(n5041), .B(n5042), .Z(n4976)); - OR2 U4730 ( .A(n5043), .B(n5044), .Z(n5042)); - IV2 U4731 ( .A(n5045), .Z(n5041)); - AN2 U4732 ( .A(n5044), .B(n5043), .Z(n5045)); - OR2 U4733 ( .A(n5046), .B(n5047), .Z(n5043)); - IV2 U4734 ( .A(n5048), .Z(n5047)); - OR2 U4735 ( .A(n5049), .B(n5050), .Z(n5048)); - AN2 U4736 ( .A(n5050), .B(n5049), .Z(n5046)); - AN2 U4737 ( .A(n5051), .B(n5052), .Z(n5049)); - OR2 U4738 ( .A(n4319), .B(po013), .Z(n5052)); - OR2 U4739 ( .A(n5053), .B(po004), .Z(n5051)); - IV2 U4740 ( .A(po013), .Z(n5053)); - OR2 U4741 ( .A(n5054), .B(n5055), .Z(n5050)); - AN2 U4742 ( .A(po028), .B(n4013), .Z(n5055)); - AN2 U4743 ( .A(po040), .B(n5056), .Z(n5054)); - AN2 U4744 ( .A(n5057), .B(n5058), .Z(n5044)); - OR2 U4745 ( .A(n5059), .B(n5060), .Z(n5058)); - IV2 U4746 ( .A(n5061), .Z(n5059)); - OR2 U4747 ( .A(n5062), .B(n5061), .Z(n5057)); - OR2 U4748 ( .A(n5063), .B(n5064), .Z(n5061)); - AN2 U4749 ( .A(po064), .B(n4128), .Z(n5064)); - AN2 U4750 ( .A(po085), .B(n4133), .Z(n5063)); - IV2 U4751 ( .A(n5060), .Z(n5062)); - OR2 U4752 ( .A(n5065), .B(n5066), .Z(n5060)); - AN2 U4753 ( .A(po091), .B(n3265), .Z(n5066)); - AN2 U4754 ( .A(po103), .B(n4201), .Z(n5065)); - IV2 U4755 ( .A(n5067), .Z(po041)); - AN2 U4756 ( .A(n5068), .B(pi193), .Z(n5067)); - AN2 U4757 ( .A(pi057), .B(n5069), .Z(n5068)); - IV2 U4758 ( .A(pi037), .Z(n5069)); - OR2 U4759 ( .A(n5070), .B(n5071), .Z(po037)); - AN2 U4760 ( .A(n3021), .B(n5072), .Z(n5071)); - OR2 U4761 ( .A(n5073), .B(n5074), .Z(n5072)); - AN2 U4762 ( .A(n3018), .B(n5075), .Z(n5073)); - OR2 U4763 ( .A(n5076), .B(n5077), .Z(n5075)); - AN2 U4764 ( .A(n4663), .B(n3284), .Z(n5076)); - OR2 U4765 ( .A(n5078), .B(n5079), .Z(n4663)); - AN2 U4766 ( .A(n3064), .B(n3108), .Z(n5079)); - AN2 U4767 ( .A(n3173), .B(n3115), .Z(n5078)); - AN2 U4768 ( .A(n3083), .B(n5080), .Z(n5070)); - OR2 U4769 ( .A(n5081), .B(n5082), .Z(n5080)); - OR2 U4770 ( .A(n5083), .B(n5084), .Z(n5082)); - AN2 U4771 ( .A(po070), .B(n4327), .Z(n5084)); - OR2 U4772 ( .A(n5085), .B(n5086), .Z(n4327)); - OR2 U4773 ( .A(n5087), .B(n5088), .Z(n5086)); - AN2 U4774 ( .A(n3273), .B(n5089), .Z(n5088)); - IV2 U4775 ( .A(n3284), .Z(n3273)); - AN2 U4776 ( .A(n5090), .B(n3274), .Z(n5087)); - OR2 U4777 ( .A(n5091), .B(n3282), .Z(n5085)); - IV2 U4778 ( .A(n4666), .Z(n3282)); - AN2 U4779 ( .A(n5092), .B(n3199), .Z(n5083)); - OR2 U4780 ( .A(n5093), .B(n5094), .Z(n5092)); - OR2 U4781 ( .A(n5095), .B(n5096), .Z(n5094)); - AN2 U4782 ( .A(n5090), .B(po010), .Z(n5096)); - AN2 U4783 ( .A(n3037), .B(n3061), .Z(n5090)); - AN2 U4784 ( .A(n5097), .B(n5098), .Z(n5095)); - AN2 U4785 ( .A(n3037), .B(n5099), .Z(n5098)); - AN2 U4786 ( .A(n5100), .B(n3120), .Z(n5097)); - OR2 U4787 ( .A(n5101), .B(n3061), .Z(n3120)); - AN2 U4788 ( .A(n3106), .B(pi192), .Z(n3061)); - AN2 U4789 ( .A(po010), .B(pi192), .Z(n5101)); - AN2 U4790 ( .A(n3082), .B(pi192), .Z(n5093)); - IV2 U4791 ( .A(n3108), .Z(n3082)); - OR2 U4792 ( .A(pi033), .B(n3286), .Z(n3108)); - OR2 U4793 ( .A(n5102), .B(n5103), .Z(n5081)); - AN2 U4794 ( .A(n3015), .B(n5104), .Z(n5103)); - IV2 U4795 ( .A(n3018), .Z(n3015)); - AN2 U4796 ( .A(n5105), .B(n3205), .Z(n5102)); - OR2 U4797 ( .A(n5106), .B(n5107), .Z(n5105)); - OR2 U4798 ( .A(n5091), .B(n5108), .Z(n5107)); - AN2 U4799 ( .A(n5100), .B(n5109), .Z(n5108)); - OR2 U4800 ( .A(n5110), .B(n5111), .Z(n5109)); - AN2 U4801 ( .A(n5112), .B(n2925), .Z(n5111)); - AN2 U4802 ( .A(po010), .B(n5089), .Z(n5112)); - IV2 U4803 ( .A(n3100), .Z(n5089)); - AN2 U4804 ( .A(n5113), .B(n3080), .Z(n5110)); - AN2 U4805 ( .A(n2837), .B(po010), .Z(n3080)); - AN2 U4806 ( .A(n3112), .B(n5099), .Z(n5113)); - AN2 U4807 ( .A(n3065), .B(n5114), .Z(n5091)); - AN2 U4808 ( .A(n3112), .B(n3274), .Z(n5114)); - IV2 U4809 ( .A(n3280), .Z(n3274)); - AN2 U4810 ( .A(n2837), .B(n5115), .Z(n3065)); - AN2 U4811 ( .A(n3073), .B(n2837), .Z(n5106)); - IV2 U4812 ( .A(n3115), .Z(n3073)); - OR2 U4813 ( .A(pi141), .B(n3286), .Z(n3115)); - OR2 U4814 ( .A(n5116), .B(n5117), .Z(po034)); - OR2 U4815 ( .A(n5118), .B(n5119), .Z(n5117)); - AN2 U4816 ( .A(pi054), .B(n5120), .Z(n5119)); - AN2 U4817 ( .A(n5121), .B(n5122), .Z(n5118)); - AN2 U4818 ( .A(n5123), .B(n5124), .Z(n5122)); - OR2 U4819 ( .A(po085), .B(po064), .Z(n5124)); - OR2 U4820 ( .A(n4125), .B(n4133), .Z(n5123)); - AN2 U4821 ( .A(n4129), .B(n4128), .Z(n4125)); - AN2 U4822 ( .A(pi052), .B(n5125), .Z(n5121)); - AN2 U4823 ( .A(n5126), .B(n5127), .Z(n5116)); - OR2 U4824 ( .A(n4167), .B(n5128), .Z(n5127)); - OR2 U4825 ( .A(n5129), .B(n5130), .Z(n5128)); - AN2 U4826 ( .A(n5131), .B(po064), .Z(n5130)); - AN2 U4827 ( .A(pi054), .B(po085), .Z(n5131)); - AN2 U4828 ( .A(n4129), .B(n4133), .Z(n5129)); - OR2 U4829 ( .A(n5132), .B(n5133), .Z(po033)); - AN2 U4830 ( .A(n3371), .B(n5134), .Z(n5133)); - OR2 U4831 ( .A(n5135), .B(n5136), .Z(n5134)); - AN2 U4832 ( .A(n5137), .B(n3412), .Z(n5132)); - OR2 U4833 ( .A(n5138), .B(n5139), .Z(n5137)); - OR2 U4834 ( .A(n5140), .B(n5141), .Z(po030)); - AN2 U4835 ( .A(n5142), .B(pi192), .Z(n5141)); - OR2 U4836 ( .A(n5143), .B(n5144), .Z(n5142)); - AN2 U4837 ( .A(n2834), .B(n5145), .Z(n5144)); - OR2 U4838 ( .A(n5146), .B(n5147), .Z(n5145)); - AN2 U4839 ( .A(n2998), .B(n3847), .Z(n5147)); - AN2 U4840 ( .A(n5148), .B(n5149), .Z(n5146)); - OR2 U4841 ( .A(n2862), .B(n5150), .Z(n5149)); - OR2 U4842 ( .A(n2880), .B(n5151), .Z(n5150)); - AN2 U4843 ( .A(n2887), .B(n2901), .Z(n5151)); - AN2 U4844 ( .A(n2891), .B(n5152), .Z(n5148)); - IV2 U4845 ( .A(n5153), .Z(n5152)); - AN2 U4846 ( .A(n5154), .B(n2833), .Z(n5143)); - OR2 U4847 ( .A(n5155), .B(n5156), .Z(n5154)); - AN2 U4848 ( .A(n5157), .B(n5158), .Z(n5155)); - AN2 U4849 ( .A(n2930), .B(n2878), .Z(n5158)); - AN2 U4850 ( .A(n5159), .B(n2837), .Z(n5140)); - OR2 U4851 ( .A(n5160), .B(n5161), .Z(n5159)); - AN2 U4852 ( .A(n2846), .B(n5162), .Z(n5161)); - OR2 U4853 ( .A(n5163), .B(n5164), .Z(n5162)); - AN2 U4854 ( .A(n2998), .B(n5165), .Z(n5164)); - AN2 U4855 ( .A(n5166), .B(n5167), .Z(n5163)); - OR2 U4856 ( .A(n5168), .B(n5169), .Z(n5167)); - AN2 U4857 ( .A(n3222), .B(n2946), .Z(n5168)); - OR2 U4858 ( .A(n5170), .B(n2959), .Z(n3222)); - AN2 U4859 ( .A(n2982), .B(n2901), .Z(n2959)); - AN2 U4860 ( .A(po107), .B(n5171), .Z(n5170)); - IV2 U4861 ( .A(n2981), .Z(n5171)); - AN2 U4862 ( .A(pi081), .B(pi200), .Z(n2981)); - AN2 U4863 ( .A(n2947), .B(n5172), .Z(n5166)); - AN2 U4864 ( .A(n5173), .B(n2845), .Z(n5160)); - OR2 U4865 ( .A(n5174), .B(n5175), .Z(n5173)); - AN2 U4866 ( .A(n5157), .B(n5176), .Z(n5174)); - AN2 U4867 ( .A(n2908), .B(n2938), .Z(n5176)); - OR2 U4868 ( .A(pi081), .B(n2931), .Z(n2938)); - IV2 U4869 ( .A(n5169), .Z(n2908)); - AN2 U4870 ( .A(n2861), .B(pi200), .Z(n5157)); - OR2 U4871 ( .A(n5177), .B(n5178), .Z(po029)); - OR2 U4872 ( .A(n5179), .B(n5180), .Z(n5178)); - AN2 U4873 ( .A(n5181), .B(n4313), .Z(n5180)); - AN2 U4874 ( .A(n3945), .B(n5182), .Z(n5179)); - OR2 U4875 ( .A(n5183), .B(n5184), .Z(n5182)); - OR2 U4876 ( .A(n5185), .B(n5186), .Z(n5184)); - AN2 U4877 ( .A(n5187), .B(pi186), .Z(n5186)); - OR2 U4878 ( .A(n5188), .B(n5189), .Z(n5187)); - AN2 U4879 ( .A(n5190), .B(n5191), .Z(n5189)); - AN2 U4880 ( .A(n5192), .B(pi124), .Z(n5188)); - IV2 U4881 ( .A(n5190), .Z(n5192)); - AN2 U4882 ( .A(n5193), .B(n5194), .Z(n5185)); - OR2 U4883 ( .A(n5195), .B(n5196), .Z(n5193)); - AN2 U4884 ( .A(n5190), .B(pi124), .Z(n5196)); - OR2 U4885 ( .A(n5197), .B(n5198), .Z(n5190)); - AN2 U4886 ( .A(n5199), .B(n5200), .Z(n5198)); - AN2 U4887 ( .A(n5201), .B(pi109), .Z(n5197)); - IV2 U4888 ( .A(n5199), .Z(n5201)); - AN2 U4889 ( .A(n5202), .B(n5191), .Z(n5195)); - OR2 U4890 ( .A(n5203), .B(n5204), .Z(n5202)); - AN2 U4891 ( .A(n5199), .B(pi109), .Z(n5204)); - OR2 U4892 ( .A(n5205), .B(n5206), .Z(n5199)); - AN2 U4893 ( .A(n5207), .B(n5208), .Z(n5206)); - AN2 U4894 ( .A(n5181), .B(pi055), .Z(n5205)); - AN2 U4895 ( .A(n5209), .B(n5200), .Z(n5203)); - AN2 U4896 ( .A(pi055), .B(n5207), .Z(n5209)); - AN2 U4897 ( .A(n5210), .B(n5211), .Z(n5183)); - OR2 U4898 ( .A(n5212), .B(n5213), .Z(n5211)); - IV2 U4899 ( .A(n5214), .Z(n5210)); - AN2 U4900 ( .A(n5213), .B(n5212), .Z(n5214)); - OR2 U4901 ( .A(n5215), .B(n5216), .Z(n5212)); - IV2 U4902 ( .A(n5217), .Z(n5216)); - OR2 U4903 ( .A(n5218), .B(pi006), .Z(n5217)); - AN2 U4904 ( .A(n5218), .B(pi006), .Z(n5215)); - AN2 U4905 ( .A(n5219), .B(n5220), .Z(n5218)); - OR2 U4906 ( .A(n5221), .B(pi061), .Z(n5220)); - IV2 U4907 ( .A(pi051), .Z(n5221)); - OR2 U4908 ( .A(n5222), .B(pi051), .Z(n5219)); - IV2 U4909 ( .A(pi061), .Z(n5222)); - AN2 U4910 ( .A(n5223), .B(n5224), .Z(n5213)); - IV2 U4911 ( .A(n5225), .Z(n5224)); - AN2 U4912 ( .A(n5226), .B(n5227), .Z(n5225)); - OR2 U4913 ( .A(n5227), .B(n5226), .Z(n5223)); - OR2 U4914 ( .A(n5228), .B(n5229), .Z(n5226)); - AN2 U4915 ( .A(pi093), .B(n5230), .Z(n5229)); - IV2 U4916 ( .A(n5231), .Z(n5228)); - OR2 U4917 ( .A(n5230), .B(pi093), .Z(n5231)); - IV2 U4918 ( .A(pi122), .Z(n5230)); - AN2 U4919 ( .A(n5232), .B(n5233), .Z(n5227)); - IV2 U4920 ( .A(n5234), .Z(n5233)); - AN2 U4921 ( .A(pi134), .B(n5235), .Z(n5234)); - OR2 U4922 ( .A(n5235), .B(pi134), .Z(n5232)); - IV2 U4923 ( .A(pi198), .Z(n5235)); - OR2 U4924 ( .A(n5236), .B(n5237), .Z(n5177)); - AN2 U4925 ( .A(n5238), .B(n2837), .Z(n5237)); - OR2 U4926 ( .A(n5239), .B(n5240), .Z(n5238)); - AN2 U4927 ( .A(n5241), .B(n5242), .Z(n5240)); - OR2 U4928 ( .A(n3809), .B(n5243), .Z(n5242)); - IV2 U4929 ( .A(n3812), .Z(n3809)); - OR2 U4930 ( .A(n5244), .B(n3812), .Z(n5241)); - AN2 U4931 ( .A(n5245), .B(n5246), .Z(n3812)); - IV2 U4932 ( .A(n5247), .Z(n5246)); - AN2 U4933 ( .A(n5248), .B(n5249), .Z(n5247)); - OR2 U4934 ( .A(n5249), .B(n5248), .Z(n5245)); - OR2 U4935 ( .A(n5250), .B(n5251), .Z(n5248)); - AN2 U4936 ( .A(pi040), .B(n5252), .Z(n5251)); - IV2 U4937 ( .A(pi095), .Z(n5252)); - AN2 U4938 ( .A(pi095), .B(n4735), .Z(n5250)); - AN2 U4939 ( .A(n5253), .B(n5254), .Z(n5249)); - OR2 U4940 ( .A(n4747), .B(pi156), .Z(n5254)); - IV2 U4941 ( .A(pi151), .Z(n4747)); - OR2 U4942 ( .A(n4648), .B(pi151), .Z(n5253)); - AN2 U4943 ( .A(n5255), .B(n5256), .Z(n5239)); - OR2 U4944 ( .A(n3815), .B(n5257), .Z(n5256)); - OR2 U4945 ( .A(n5258), .B(n3818), .Z(n5255)); - IV2 U4946 ( .A(n3815), .Z(n3818)); - OR2 U4947 ( .A(n5259), .B(n5260), .Z(n3815)); - AN2 U4948 ( .A(n5261), .B(n5262), .Z(n5260)); - IV2 U4949 ( .A(n5263), .Z(n5259)); - OR2 U4950 ( .A(n5262), .B(n5261), .Z(n5263)); - OR2 U4951 ( .A(n5264), .B(n5265), .Z(n5261)); - AN2 U4952 ( .A(pi128), .B(n3177), .Z(n5265)); - AN2 U4953 ( .A(pi141), .B(n3205), .Z(n5264)); - AN2 U4954 ( .A(n5266), .B(n5267), .Z(n5262)); - OR2 U4955 ( .A(n5115), .B(pi185), .Z(n5267)); - OR2 U4956 ( .A(n5268), .B(pi174), .Z(n5266)); - IV2 U4957 ( .A(pi185), .Z(n5268)); - AN2 U4958 ( .A(pi192), .B(n5269), .Z(n5236)); - OR2 U4959 ( .A(n5270), .B(n5271), .Z(n5269)); - OR2 U4960 ( .A(n5272), .B(n5273), .Z(n5271)); - AN2 U4961 ( .A(n5274), .B(n5275), .Z(n5273)); - IV2 U4962 ( .A(n5276), .Z(n5275)); - AN2 U4963 ( .A(n5277), .B(n5278), .Z(n5276)); - OR2 U4964 ( .A(n5278), .B(n5277), .Z(n5274)); - AN2 U4965 ( .A(n5279), .B(n5280), .Z(n5277)); - OR2 U4966 ( .A(n5243), .B(pi036), .Z(n5280)); - IV2 U4967 ( .A(n5244), .Z(n5243)); - OR2 U4968 ( .A(n5244), .B(n5281), .Z(n5279)); - IV2 U4969 ( .A(pi036), .Z(n5281)); - OR2 U4970 ( .A(n3871), .B(n5282), .Z(n5244)); - AN2 U4971 ( .A(n5283), .B(pi192), .Z(n5282)); - OR2 U4972 ( .A(n5284), .B(n5285), .Z(n5283)); - AN2 U4973 ( .A(n5286), .B(n5287), .Z(n5285)); - IV2 U4974 ( .A(n5288), .Z(n5284)); - OR2 U4975 ( .A(n5287), .B(n5286), .Z(n5288)); - OR2 U4976 ( .A(n5289), .B(n5290), .Z(n5286)); - IV2 U4977 ( .A(n5291), .Z(n5290)); - OR2 U4978 ( .A(n5292), .B(pi017), .Z(n5291)); - AN2 U4979 ( .A(pi017), .B(n5292), .Z(n5289)); - AN2 U4980 ( .A(n5293), .B(n5294), .Z(n5292)); - OR2 U4981 ( .A(n5295), .B(pi083), .Z(n5294)); - IV2 U4982 ( .A(pi027), .Z(n5295)); - OR2 U4983 ( .A(n5296), .B(pi027), .Z(n5293)); - IV2 U4984 ( .A(pi083), .Z(n5296)); - AN2 U4985 ( .A(n5297), .B(n5298), .Z(n5287)); - OR2 U4986 ( .A(n5299), .B(pi089), .Z(n5298)); - IV2 U4987 ( .A(n5300), .Z(n5297)); - AN2 U4988 ( .A(n5299), .B(pi089), .Z(n5300)); - AN2 U4989 ( .A(n5301), .B(n5302), .Z(n5299)); - OR2 U4990 ( .A(n5303), .B(pi162), .Z(n5302)); - OR2 U4991 ( .A(n5304), .B(pi140), .Z(n5301)); - IV2 U4992 ( .A(pi162), .Z(n5304)); - AN2 U4993 ( .A(n5305), .B(n2837), .Z(n3871)); - OR2 U4994 ( .A(n5306), .B(n5307), .Z(n5305)); - AN2 U4995 ( .A(n5308), .B(n5309), .Z(n5307)); - IV2 U4996 ( .A(n5310), .Z(n5306)); - OR2 U4997 ( .A(n5309), .B(n5308), .Z(n5310)); - OR2 U4998 ( .A(n5311), .B(n5312), .Z(n5308)); - IV2 U4999 ( .A(n5313), .Z(n5312)); - OR2 U5000 ( .A(n5314), .B(pi064), .Z(n5313)); - AN2 U5001 ( .A(pi064), .B(n5314), .Z(n5311)); - AN2 U5002 ( .A(n5315), .B(n5316), .Z(n5314)); - OR2 U5003 ( .A(n4077), .B(pi108), .Z(n5316)); - OR2 U5004 ( .A(n5317), .B(pi076), .Z(n5315)); - IV2 U5005 ( .A(pi108), .Z(n5317)); - AN2 U5006 ( .A(n5318), .B(n5319), .Z(n5309)); - OR2 U5007 ( .A(n5320), .B(pi114), .Z(n5319)); - IV2 U5008 ( .A(n5321), .Z(n5320)); - OR2 U5009 ( .A(n5321), .B(n5322), .Z(n5318)); - OR2 U5010 ( .A(n5323), .B(n5324), .Z(n5321)); - AN2 U5011 ( .A(pi160), .B(n4074), .Z(n5324)); - AN2 U5012 ( .A(pi170), .B(n4358), .Z(n5323)); - OR2 U5013 ( .A(n5325), .B(n5326), .Z(n5278)); - IV2 U5014 ( .A(n5327), .Z(n5326)); - OR2 U5015 ( .A(n5328), .B(pi101), .Z(n5327)); - AN2 U5016 ( .A(n5328), .B(pi101), .Z(n5325)); - AN2 U5017 ( .A(n5329), .B(n5330), .Z(n5328)); - OR2 U5018 ( .A(n5331), .B(pi205), .Z(n5330)); - OR2 U5019 ( .A(n5332), .B(pi168), .Z(n5329)); - IV2 U5020 ( .A(pi205), .Z(n5332)); - AN2 U5021 ( .A(n5333), .B(n5334), .Z(n5272)); - AN2 U5022 ( .A(n5335), .B(n5200), .Z(n5334)); - IV2 U5023 ( .A(pi109), .Z(n5200)); - AN2 U5024 ( .A(n5191), .B(n5194), .Z(n5335)); - IV2 U5025 ( .A(pi186), .Z(n5194)); - IV2 U5026 ( .A(pi124), .Z(n5191)); - AN2 U5027 ( .A(n5181), .B(n5208), .Z(n5333)); - IV2 U5028 ( .A(pi055), .Z(n5208)); - IV2 U5029 ( .A(n5207), .Z(n5181)); - OR2 U5030 ( .A(n3977), .B(n5336), .Z(n5207)); - AN2 U5031 ( .A(n5337), .B(pi192), .Z(n5336)); - OR2 U5032 ( .A(n5338), .B(n5339), .Z(n5337)); - AN2 U5033 ( .A(n5340), .B(n5341), .Z(n5339)); - IV2 U5034 ( .A(n5342), .Z(n5338)); - OR2 U5035 ( .A(n5341), .B(n5340), .Z(n5342)); - OR2 U5036 ( .A(n5343), .B(n5344), .Z(n5340)); - IV2 U5037 ( .A(n5345), .Z(n5344)); - OR2 U5038 ( .A(n5346), .B(n5347), .Z(n5345)); - AN2 U5039 ( .A(n5346), .B(n5347), .Z(n5343)); - AN2 U5040 ( .A(n5348), .B(n5349), .Z(n5346)); - OR2 U5041 ( .A(n5350), .B(pi099), .Z(n5349)); - OR2 U5042 ( .A(n5351), .B(pi018), .Z(n5348)); - IV2 U5043 ( .A(pi099), .Z(n5351)); - AN2 U5044 ( .A(n5352), .B(n5353), .Z(n5341)); - OR2 U5045 ( .A(n5354), .B(pi150), .Z(n5353)); - IV2 U5046 ( .A(n5355), .Z(n5352)); - AN2 U5047 ( .A(pi150), .B(n5354), .Z(n5355)); - AN2 U5048 ( .A(n5356), .B(n5357), .Z(n5354)); - OR2 U5049 ( .A(n5358), .B(pi180), .Z(n5357)); - OR2 U5050 ( .A(n5359), .B(pi172), .Z(n5356)); - IV2 U5051 ( .A(pi180), .Z(n5359)); - AN2 U5052 ( .A(n5360), .B(n2837), .Z(n3977)); - AN2 U5053 ( .A(n5361), .B(n5362), .Z(n5360)); - IV2 U5054 ( .A(n5363), .Z(n5362)); - AN2 U5055 ( .A(n5364), .B(n5365), .Z(n5363)); - OR2 U5056 ( .A(n5365), .B(n5364), .Z(n5361)); - OR2 U5057 ( .A(n5366), .B(n5367), .Z(n5364)); - AN2 U5058 ( .A(n5368), .B(n3261), .Z(n5367)); - AN2 U5059 ( .A(n5369), .B(n3321), .Z(n5366)); - IV2 U5060 ( .A(n5368), .Z(n5369)); - OR2 U5061 ( .A(n5370), .B(n5371), .Z(n5368)); - AN2 U5062 ( .A(pi003), .B(n5372), .Z(n5371)); - AN2 U5063 ( .A(pi130), .B(n3597), .Z(n5370)); - AN2 U5064 ( .A(n5373), .B(n5374), .Z(n5365)); - OR2 U5065 ( .A(n5375), .B(pi142), .Z(n5374)); - IV2 U5066 ( .A(n5376), .Z(n5375)); - OR2 U5067 ( .A(n5376), .B(n4440), .Z(n5373)); - OR2 U5068 ( .A(n5377), .B(n5378), .Z(n5376)); - AN2 U5069 ( .A(pi177), .B(n5379), .Z(n5378)); - AN2 U5070 ( .A(pi195), .B(n5380), .Z(n5377)); - IV2 U5071 ( .A(pi177), .Z(n5380)); - AN2 U5072 ( .A(n5381), .B(n5382), .Z(n5270)); - IV2 U5073 ( .A(n5383), .Z(n5382)); - AN2 U5074 ( .A(n5384), .B(n5385), .Z(n5383)); - OR2 U5075 ( .A(n5385), .B(n5384), .Z(n5381)); - AN2 U5076 ( .A(n5386), .B(n5387), .Z(n5384)); - OR2 U5077 ( .A(n5257), .B(pi001), .Z(n5387)); - IV2 U5078 ( .A(n5258), .Z(n5257)); - OR2 U5079 ( .A(n5258), .B(n5388), .Z(n5386)); - IV2 U5080 ( .A(pi001), .Z(n5388)); - OR2 U5081 ( .A(n3831), .B(n5389), .Z(n5258)); - AN2 U5082 ( .A(n5390), .B(pi192), .Z(n5389)); - OR2 U5083 ( .A(n5391), .B(n5392), .Z(n5390)); - AN2 U5084 ( .A(n5393), .B(n5394), .Z(n5392)); - IV2 U5085 ( .A(n5395), .Z(n5391)); - OR2 U5086 ( .A(n5394), .B(n5393), .Z(n5395)); - OR2 U5087 ( .A(n5396), .B(n5397), .Z(n5393)); - IV2 U5088 ( .A(n5398), .Z(n5397)); - OR2 U5089 ( .A(n5399), .B(pi038), .Z(n5398)); - AN2 U5090 ( .A(pi038), .B(n5399), .Z(n5396)); - AN2 U5091 ( .A(n5400), .B(n5401), .Z(n5399)); - OR2 U5092 ( .A(n5402), .B(pi103), .Z(n5401)); - IV2 U5093 ( .A(pi053), .Z(n5402)); - OR2 U5094 ( .A(n5403), .B(pi053), .Z(n5400)); - IV2 U5095 ( .A(pi103), .Z(n5403)); - AN2 U5096 ( .A(n5404), .B(n5405), .Z(n5394)); - OR2 U5097 ( .A(n5406), .B(pi121), .Z(n5405)); - IV2 U5098 ( .A(n5407), .Z(n5404)); - AN2 U5099 ( .A(n5406), .B(pi121), .Z(n5407)); - AN2 U5100 ( .A(n5408), .B(n5409), .Z(n5406)); - OR2 U5101 ( .A(n5410), .B(pi184), .Z(n5409)); - IV2 U5102 ( .A(pi149), .Z(n5410)); - OR2 U5103 ( .A(n5411), .B(pi149), .Z(n5408)); - IV2 U5104 ( .A(pi184), .Z(n5411)); - AN2 U5105 ( .A(n5412), .B(n2837), .Z(n3831)); - OR2 U5106 ( .A(n5413), .B(n5414), .Z(n5412)); - IV2 U5107 ( .A(n5415), .Z(n5414)); - OR2 U5108 ( .A(n5416), .B(n5417), .Z(n5415)); - AN2 U5109 ( .A(n5417), .B(n5416), .Z(n5413)); - AN2 U5110 ( .A(n5418), .B(n5419), .Z(n5416)); - OR2 U5111 ( .A(n5420), .B(pi081), .Z(n5419)); - IV2 U5112 ( .A(n5421), .Z(n5420)); - OR2 U5113 ( .A(n5421), .B(n2982), .Z(n5418)); - OR2 U5114 ( .A(n5422), .B(n5423), .Z(n5421)); - AN2 U5115 ( .A(pi082), .B(n5424), .Z(n5423)); - IV2 U5116 ( .A(pi092), .Z(n5424)); - AN2 U5117 ( .A(pi092), .B(n2957), .Z(n5422)); - OR2 U5118 ( .A(n5425), .B(n5426), .Z(n5417)); - AN2 U5119 ( .A(n5427), .B(n5165), .Z(n5426)); - AN2 U5120 ( .A(n5428), .B(pi107), .Z(n5425)); - IV2 U5121 ( .A(n5427), .Z(n5428)); - OR2 U5122 ( .A(n5429), .B(n5430), .Z(n5427)); - AN2 U5123 ( .A(pi201), .B(n5431), .Z(n5430)); - AN2 U5124 ( .A(pi206), .B(n3141), .Z(n5429)); - OR2 U5125 ( .A(n5432), .B(n5433), .Z(n5385)); - IV2 U5126 ( .A(n5434), .Z(n5433)); - OR2 U5127 ( .A(n5435), .B(pi059), .Z(n5434)); - AN2 U5128 ( .A(n5435), .B(pi059), .Z(n5432)); - AN2 U5129 ( .A(n5436), .B(n5437), .Z(n5435)); - OR2 U5130 ( .A(n5438), .B(pi197), .Z(n5437)); - IV2 U5131 ( .A(pi131), .Z(n5438)); - OR2 U5132 ( .A(n5439), .B(pi131), .Z(n5436)); - OR2 U5133 ( .A(n5440), .B(n5441), .Z(po026)); - AN2 U5134 ( .A(n3355), .B(n5442), .Z(n5441)); - OR2 U5135 ( .A(n5443), .B(n5444), .Z(n5442)); - OR2 U5136 ( .A(n5445), .B(n5446), .Z(n5444)); - AN2 U5137 ( .A(po036), .B(n5447), .Z(n5446)); - OR2 U5138 ( .A(n4418), .B(n5448), .Z(n5447)); - AN2 U5139 ( .A(n5449), .B(n3236), .Z(n5445)); - AN2 U5140 ( .A(n5450), .B(n5451), .Z(n5449)); - OR2 U5141 ( .A(n5452), .B(n2837), .Z(n5451)); - OR2 U5142 ( .A(pi192), .B(n5453), .Z(n5450)); - AN2 U5143 ( .A(n4418), .B(n5448), .Z(n5443)); - AN2 U5144 ( .A(n3352), .B(n5454), .Z(n5440)); - IV2 U5145 ( .A(n5455), .Z(po022)); - AN2 U5146 ( .A(n5456), .B(n5457), .Z(n5455)); - AN2 U5147 ( .A(pi074), .B(pi046), .Z(n5457)); - AN2 U5148 ( .A(pi178), .B(pi113), .Z(n5456)); - OR2 U5149 ( .A(n5458), .B(n5459), .Z(po019)); - AN2 U5150 ( .A(n4478), .B(n5460), .Z(n5459)); - OR2 U5151 ( .A(n5461), .B(n4511), .Z(n5460)); - OR2 U5152 ( .A(n5462), .B(n5463), .Z(n4511)); - OR2 U5153 ( .A(n5464), .B(n5465), .Z(n5463)); - AN2 U5154 ( .A(n5466), .B(pi192), .Z(n5465)); - AN2 U5155 ( .A(n5467), .B(n2837), .Z(n5464)); - AN2 U5156 ( .A(n4475), .B(n5468), .Z(n5458)); - OR2 U5157 ( .A(n5469), .B(n5470), .Z(n5468)); - OR2 U5158 ( .A(n5471), .B(n4509), .Z(n5470)); - OR2 U5159 ( .A(n5472), .B(n5473), .Z(n4509)); - OR2 U5160 ( .A(n5474), .B(n5475), .Z(n5473)); - AN2 U5161 ( .A(n5476), .B(n4078), .Z(n5475)); - AN2 U5162 ( .A(n5477), .B(n5322), .Z(n5476)); - AN2 U5163 ( .A(n5478), .B(n4551), .Z(n5472)); - IV2 U5164 ( .A(n4544), .Z(n4551)); - OR2 U5165 ( .A(n4561), .B(n4066), .Z(n4544)); - AN2 U5166 ( .A(pi192), .B(n3901), .Z(n5478)); - AN2 U5167 ( .A(po102), .B(n4347), .Z(n5471)); - OR2 U5168 ( .A(n5479), .B(n4524), .Z(n4347)); - AN2 U5169 ( .A(n5480), .B(n4078), .Z(n4524)); - IV2 U5170 ( .A(n4066), .Z(n4078)); - AN2 U5171 ( .A(n4521), .B(n4072), .Z(n5479)); - OR2 U5172 ( .A(n5481), .B(n5482), .Z(n4521)); - AN2 U5173 ( .A(po059), .B(n5480), .Z(n5482)); - OR2 U5174 ( .A(n5483), .B(po024), .Z(n5480)); - AN2 U5175 ( .A(n5477), .B(n4074), .Z(n5481)); - OR2 U5176 ( .A(n5484), .B(n5485), .Z(n5469)); - AN2 U5177 ( .A(n4517), .B(n3780), .Z(n5485)); - OR2 U5178 ( .A(n5486), .B(n5487), .Z(n4517)); - AN2 U5179 ( .A(n4356), .B(n5488), .Z(n5487)); - AN2 U5180 ( .A(n4076), .B(n5489), .Z(n4356)); - AN2 U5181 ( .A(n4077), .B(n4578), .Z(n5489)); - AN2 U5182 ( .A(n5490), .B(n4543), .Z(n5486)); - AN2 U5183 ( .A(n4348), .B(n4353), .Z(n4543)); - AN2 U5184 ( .A(n3890), .B(n5491), .Z(n5490)); - AN2 U5185 ( .A(n4512), .B(n4072), .Z(n5484)); - OR2 U5186 ( .A(n5492), .B(n3773), .Z(n4072)); - AN2 U5187 ( .A(po025), .B(n3780), .Z(n5492)); - IV2 U5188 ( .A(n4087), .Z(n3780)); - OR2 U5189 ( .A(n5493), .B(n5494), .Z(n4512)); - OR2 U5190 ( .A(n5495), .B(n5496), .Z(n5494)); - AN2 U5191 ( .A(n5497), .B(pi192), .Z(n5496)); - AN2 U5192 ( .A(n5498), .B(n4348), .Z(n5497)); - OR2 U5193 ( .A(n5499), .B(n5500), .Z(n5498)); - AN2 U5194 ( .A(po102), .B(n3880), .Z(n5500)); - AN2 U5195 ( .A(n4353), .B(n3901), .Z(n5499)); - AN2 U5196 ( .A(n5501), .B(n4076), .Z(n5495)); - AN2 U5197 ( .A(n5488), .B(n4358), .Z(n5501)); - AN2 U5198 ( .A(n5502), .B(n4076), .Z(n5493)); - AN2 U5199 ( .A(n2837), .B(n5503), .Z(n4076)); - AN2 U5200 ( .A(po024), .B(n5322), .Z(n5502)); - OR2 U5201 ( .A(n5504), .B(n5505), .Z(po074)); - AN2 U5202 ( .A(n5506), .B(n5507), .Z(n5505)); - OR2 U5203 ( .A(n4167), .B(n5508), .Z(n5507)); - OR2 U5204 ( .A(pi054), .B(n5509), .Z(n5508)); - AN2 U5205 ( .A(pi025), .B(pi146), .Z(n5509)); - OR2 U5206 ( .A(n5510), .B(n5511), .Z(n5506)); - OR2 U5207 ( .A(n5512), .B(n5513), .Z(n5511)); - AN2 U5208 ( .A(n3926), .B(n5514), .Z(n5513)); - OR2 U5209 ( .A(n5515), .B(n5516), .Z(n5514)); - OR2 U5210 ( .A(n5517), .B(n5518), .Z(n5516)); - OR2 U5211 ( .A(pi056), .B(pi035), .Z(n5518)); - OR2 U5212 ( .A(pi100), .B(n5519), .Z(n5515)); - OR2 U5213 ( .A(pi190), .B(pi126), .Z(n5519)); - AN2 U5214 ( .A(n5520), .B(n4319), .Z(n5512)); - OR2 U5215 ( .A(n5521), .B(n5522), .Z(n5520)); - AN2 U5216 ( .A(pi198), .B(n3945), .Z(n5522)); - AN2 U5217 ( .A(n5523), .B(n5524), .Z(n5521)); - AN2 U5218 ( .A(n5525), .B(n5517), .Z(n5524)); - AN2 U5219 ( .A(n5056), .B(n4201), .Z(n5525)); - AN2 U5220 ( .A(n4391), .B(pi192), .Z(n5523)); - OR2 U5221 ( .A(n5526), .B(n5527), .Z(n5510)); - AN2 U5222 ( .A(n5528), .B(n5529), .Z(n5527)); - OR2 U5223 ( .A(pi198), .B(n4319), .Z(n5529)); - OR2 U5224 ( .A(n5530), .B(n5531), .Z(n5528)); - AN2 U5225 ( .A(n3945), .B(n5532), .Z(n5531)); - OR2 U5226 ( .A(n5533), .B(n5534), .Z(n5532)); - AN2 U5227 ( .A(pi061), .B(n4013), .Z(n5534)); - AN2 U5228 ( .A(n5535), .B(pi134), .Z(n5533)); - AN2 U5229 ( .A(n5536), .B(n4201), .Z(n5535)); - AN2 U5230 ( .A(n5537), .B(n5538), .Z(n5530)); - AN2 U5231 ( .A(n5536), .B(n3261), .Z(n5538)); - OR2 U5232 ( .A(pi061), .B(n4013), .Z(n5536)); - AN2 U5233 ( .A(n5539), .B(n5540), .Z(n5537)); - OR2 U5234 ( .A(pi134), .B(n4201), .Z(n5540)); - OR2 U5235 ( .A(n5541), .B(n5542), .Z(n5539)); - AN2 U5236 ( .A(n5543), .B(n5517), .Z(n5542)); - AN2 U5237 ( .A(pi192), .B(n5544), .Z(n5541)); - OR2 U5238 ( .A(n5545), .B(n5546), .Z(n5544)); - AN2 U5239 ( .A(pi006), .B(n3265), .Z(n5546)); - AN2 U5240 ( .A(n5543), .B(n5056), .Z(n5545)); - OR2 U5241 ( .A(pi006), .B(n3265), .Z(n5543)); - AN2 U5242 ( .A(n5547), .B(n5548), .Z(n5526)); - AN2 U5243 ( .A(n5549), .B(n5550), .Z(n5548)); - AN2 U5244 ( .A(n5517), .B(n2837), .Z(n5550)); - OR2 U5245 ( .A(n5551), .B(n5552), .Z(n5517)); - OR2 U5246 ( .A(n5553), .B(n5554), .Z(n5552)); - AN2 U5247 ( .A(n3945), .B(n5555), .Z(n5554)); - OR2 U5248 ( .A(n5556), .B(n5557), .Z(n5555)); - OR2 U5249 ( .A(n5558), .B(n5559), .Z(n5557)); - AN2 U5250 ( .A(n5560), .B(n3380), .Z(n5559)); - AN2 U5251 ( .A(n5561), .B(n5562), .Z(n5558)); - OR2 U5252 ( .A(n5563), .B(n5564), .Z(n5561)); - AN2 U5253 ( .A(pi055), .B(n3512), .Z(n5564)); - AN2 U5254 ( .A(n5565), .B(pi124), .Z(n5563)); - AN2 U5255 ( .A(n5566), .B(n3363), .Z(n5565)); - AN2 U5256 ( .A(pi109), .B(n4975), .Z(n5556)); - AN2 U5257 ( .A(n5567), .B(n5568), .Z(n5553)); - OR2 U5258 ( .A(n5569), .B(n5570), .Z(n5568)); - OR2 U5259 ( .A(n5571), .B(n5572), .Z(n5570)); - AN2 U5260 ( .A(n5573), .B(n5566), .Z(n5572)); - OR2 U5261 ( .A(pi055), .B(n3512), .Z(n5566)); - AN2 U5262 ( .A(n5574), .B(n3261), .Z(n5573)); - OR2 U5263 ( .A(n5575), .B(n5576), .Z(n5574)); - AN2 U5264 ( .A(pi124), .B(n5562), .Z(n5576)); - OR2 U5265 ( .A(n5577), .B(n5560), .Z(n5562)); - AN2 U5266 ( .A(n5578), .B(n3380), .Z(n5577)); - AN2 U5267 ( .A(n5579), .B(n3363), .Z(n5575)); - OR2 U5268 ( .A(n5580), .B(n5560), .Z(n5579)); - AN2 U5269 ( .A(n5578), .B(pi186), .Z(n5560)); - OR2 U5270 ( .A(pi109), .B(n4975), .Z(n5578)); - AN2 U5271 ( .A(pi109), .B(n3380), .Z(n5580)); - AN2 U5272 ( .A(n5581), .B(n5582), .Z(n5571)); - AN2 U5273 ( .A(n4975), .B(n3380), .Z(n5582)); - AN2 U5274 ( .A(n5583), .B(n3363), .Z(n5581)); - OR2 U5275 ( .A(n5584), .B(n5585), .Z(n5583)); - AN2 U5276 ( .A(pi192), .B(n3512), .Z(n5585)); - AN2 U5277 ( .A(pi055), .B(n3261), .Z(n5584)); - OR2 U5278 ( .A(n3926), .B(n5586), .Z(n5569)); - AN2 U5279 ( .A(n5587), .B(n5588), .Z(n5586)); - AN2 U5280 ( .A(n5589), .B(pi110), .Z(n5588)); - AN2 U5281 ( .A(pi167), .B(n2837), .Z(n5589)); - AN2 U5282 ( .A(pi019), .B(pi085), .Z(n5587)); - AN2 U5283 ( .A(n5590), .B(n5591), .Z(n5567)); - OR2 U5284 ( .A(pi192), .B(n5592), .Z(n5591)); - AN2 U5285 ( .A(n5593), .B(n5594), .Z(n5592)); - OR2 U5286 ( .A(pi164), .B(n3261), .Z(n5594)); - OR2 U5287 ( .A(n5595), .B(n5596), .Z(n5593)); - OR2 U5288 ( .A(n5597), .B(n5598), .Z(n5596)); - AN2 U5289 ( .A(n5599), .B(pi024), .Z(n5598)); - AN2 U5290 ( .A(pi195), .B(n5600), .Z(n5597)); - OR2 U5291 ( .A(n5601), .B(n5599), .Z(n5600)); - AN2 U5292 ( .A(n5602), .B(n5603), .Z(n5599)); - IV2 U5293 ( .A(n5604), .Z(n5603)); - AN2 U5294 ( .A(n5605), .B(n5606), .Z(n5604)); - OR2 U5295 ( .A(n5607), .B(n5608), .Z(n5606)); - AN2 U5296 ( .A(n5609), .B(n5610), .Z(n5608)); - OR2 U5297 ( .A(n5611), .B(n4961), .Z(n5610)); - IV2 U5298 ( .A(pi030), .Z(n4961)); - AN2 U5299 ( .A(n5612), .B(n3597), .Z(n5611)); - OR2 U5300 ( .A(n5612), .B(n3597), .Z(n5609)); - AN2 U5301 ( .A(n4969), .B(n4440), .Z(n5607)); - OR2 U5302 ( .A(n4440), .B(n4969), .Z(n5605)); - IV2 U5303 ( .A(pi159), .Z(n4969)); - AN2 U5304 ( .A(pi024), .B(n5602), .Z(n5601)); - OR2 U5305 ( .A(pi087), .B(pi130), .Z(n5602)); - AN2 U5306 ( .A(pi087), .B(pi130), .Z(n5595)); - OR2 U5307 ( .A(n2837), .B(n5613), .Z(n5590)); - OR2 U5308 ( .A(n5614), .B(n5615), .Z(n5613)); - AN2 U5309 ( .A(n5347), .B(n5616), .Z(n5615)); - AN2 U5310 ( .A(n5617), .B(n4943), .Z(n5614)); - OR2 U5311 ( .A(n5347), .B(n5616), .Z(n5617)); - OR2 U5312 ( .A(n5618), .B(n5619), .Z(n5616)); - OR2 U5313 ( .A(n5620), .B(n5621), .Z(n5619)); - AN2 U5314 ( .A(n5622), .B(pi099), .Z(n5621)); - AN2 U5315 ( .A(n5623), .B(n4937), .Z(n5620)); - OR2 U5316 ( .A(n5624), .B(n5622), .Z(n5623)); - AN2 U5317 ( .A(n5625), .B(n5626), .Z(n5622)); - IV2 U5318 ( .A(n5627), .Z(n5626)); - AN2 U5319 ( .A(n5628), .B(n5629), .Z(n5627)); - OR2 U5320 ( .A(n5630), .B(n5631), .Z(n5629)); - AN2 U5321 ( .A(n5632), .B(n5633), .Z(n5631)); - OR2 U5322 ( .A(po011), .B(n5634), .Z(n5633)); - AN2 U5323 ( .A(n5612), .B(n5358), .Z(n5634)); - OR2 U5324 ( .A(n5612), .B(n5358), .Z(n5632)); - IV2 U5325 ( .A(pi172), .Z(n5358)); - IV2 U5326 ( .A(po062), .Z(n5612)); - OR2 U5327 ( .A(n5635), .B(n5636), .Z(po062)); - AN2 U5328 ( .A(n5637), .B(n2837), .Z(n5636)); - OR2 U5329 ( .A(n5638), .B(n5639), .Z(n5637)); - AN2 U5330 ( .A(pi020), .B(pi095), .Z(n5639)); - AN2 U5331 ( .A(n5640), .B(n5641), .Z(n5638)); - OR2 U5332 ( .A(pi020), .B(pi095), .Z(n5641)); - OR2 U5333 ( .A(n5642), .B(n5643), .Z(n5640)); - AN2 U5334 ( .A(pi151), .B(n5644), .Z(n5643)); - AN2 U5335 ( .A(pi153), .B(n5645), .Z(n5642)); - OR2 U5336 ( .A(pi151), .B(n5644), .Z(n5645)); - OR2 U5337 ( .A(n5646), .B(n5647), .Z(n5644)); - AN2 U5338 ( .A(pi075), .B(pi156), .Z(n5647)); - AN2 U5339 ( .A(n5648), .B(n5649), .Z(n5646)); - OR2 U5340 ( .A(pi075), .B(pi156), .Z(n5649)); - OR2 U5341 ( .A(n5650), .B(n5651), .Z(n5648)); - AN2 U5342 ( .A(pi040), .B(n5652), .Z(n5651)); - AN2 U5343 ( .A(pi047), .B(n5653), .Z(n5650)); - OR2 U5344 ( .A(pi040), .B(n5652), .Z(n5653)); - AN2 U5345 ( .A(pi192), .B(n5654), .Z(n5635)); - OR2 U5346 ( .A(n5655), .B(n5656), .Z(n5654)); - OR2 U5347 ( .A(n5657), .B(n5658), .Z(n5656)); - AN2 U5348 ( .A(pi101), .B(n5659), .Z(n5658)); - AN2 U5349 ( .A(n5660), .B(n4628), .Z(n5657)); - OR2 U5350 ( .A(n5661), .B(n5659), .Z(n5660)); - OR2 U5351 ( .A(n5662), .B(n5663), .Z(n5659)); - AN2 U5352 ( .A(n5664), .B(pi036), .Z(n5663)); - AN2 U5353 ( .A(n5665), .B(n4861), .Z(n5662)); - OR2 U5354 ( .A(n5666), .B(n5664), .Z(n5665)); - AN2 U5355 ( .A(n5667), .B(n5668), .Z(n5664)); - IV2 U5356 ( .A(n5669), .Z(n5668)); - AN2 U5357 ( .A(n5670), .B(n5671), .Z(n5669)); - OR2 U5358 ( .A(po039), .B(n5672), .Z(n5671)); - AN2 U5359 ( .A(n5673), .B(n5331), .Z(n5672)); - OR2 U5360 ( .A(n5673), .B(n5331), .Z(n5670)); - IV2 U5361 ( .A(pi168), .Z(n5331)); - IV2 U5362 ( .A(n5652), .Z(n5673)); - OR2 U5363 ( .A(n5674), .B(n5675), .Z(n5652)); - AN2 U5364 ( .A(n5676), .B(n2837), .Z(n5675)); - OR2 U5365 ( .A(n5677), .B(n5678), .Z(n5676)); - AN2 U5366 ( .A(pi143), .B(pi108), .Z(n5678)); - AN2 U5367 ( .A(n5679), .B(n5680), .Z(n5677)); - OR2 U5368 ( .A(pi108), .B(pi143), .Z(n5680)); - OR2 U5369 ( .A(n5681), .B(n5682), .Z(n5679)); - AN2 U5370 ( .A(pi014), .B(pi114), .Z(n5682)); - AN2 U5371 ( .A(n5683), .B(n5684), .Z(n5681)); - OR2 U5372 ( .A(pi014), .B(pi114), .Z(n5684)); - OR2 U5373 ( .A(n5685), .B(n5686), .Z(n5683)); - OR2 U5374 ( .A(n5687), .B(n5688), .Z(n5686)); - AN2 U5375 ( .A(n5689), .B(pi170), .Z(n5688)); - AN2 U5376 ( .A(pi176), .B(n5690), .Z(n5687)); - OR2 U5377 ( .A(n5691), .B(n5689), .Z(n5690)); - AN2 U5378 ( .A(n5692), .B(n5693), .Z(n5689)); - IV2 U5379 ( .A(n5694), .Z(n5693)); - AN2 U5380 ( .A(n5695), .B(n5696), .Z(n5694)); - OR2 U5381 ( .A(n5697), .B(n4899), .Z(n5696)); - IV2 U5382 ( .A(pi097), .Z(n4899)); - AN2 U5383 ( .A(n5698), .B(n4077), .Z(n5697)); - OR2 U5384 ( .A(n5698), .B(n4077), .Z(n5695)); - AN2 U5385 ( .A(pi170), .B(n5692), .Z(n5691)); - OR2 U5386 ( .A(pi160), .B(pi189), .Z(n5692)); - AN2 U5387 ( .A(pi189), .B(pi160), .Z(n5685)); - AN2 U5388 ( .A(pi192), .B(n5699), .Z(n5674)); - OR2 U5389 ( .A(n5700), .B(n5701), .Z(n5699)); - AN2 U5390 ( .A(pi089), .B(n4881), .Z(n5701)); - AN2 U5391 ( .A(n5702), .B(n5703), .Z(n5700)); - OR2 U5392 ( .A(pi089), .B(n4881), .Z(n5703)); - OR2 U5393 ( .A(n5704), .B(n5705), .Z(n5702)); - AN2 U5394 ( .A(pi027), .B(n4885), .Z(n5705)); - AN2 U5395 ( .A(n5706), .B(n5707), .Z(n5704)); - OR2 U5396 ( .A(pi027), .B(n4885), .Z(n5707)); - OR2 U5397 ( .A(n5708), .B(n5709), .Z(n5706)); - OR2 U5398 ( .A(n5710), .B(n5711), .Z(n5709)); - AN2 U5399 ( .A(n5712), .B(pi083), .Z(n5711)); - AN2 U5400 ( .A(n5713), .B(n4877), .Z(n5710)); - OR2 U5401 ( .A(n5714), .B(n5712), .Z(n5713)); - AN2 U5402 ( .A(n5715), .B(n5716), .Z(n5712)); - IV2 U5403 ( .A(n5717), .Z(n5716)); - AN2 U5404 ( .A(n5718), .B(n5719), .Z(n5717)); - OR2 U5405 ( .A(po025), .B(n5720), .Z(n5719)); - AN2 U5406 ( .A(n5698), .B(n5303), .Z(n5720)); - OR2 U5407 ( .A(n5698), .B(n5303), .Z(n5718)); - IV2 U5408 ( .A(pi140), .Z(n5303)); - IV2 U5409 ( .A(n5721), .Z(n5698)); - OR2 U5410 ( .A(n5722), .B(n5723), .Z(n5721)); - AN2 U5411 ( .A(n5724), .B(n2837), .Z(n5723)); - OR2 U5412 ( .A(n5725), .B(n5726), .Z(n5724)); - OR2 U5413 ( .A(n5727), .B(n5728), .Z(n5726)); - AN2 U5414 ( .A(n5729), .B(pi094), .Z(n5728)); - AN2 U5415 ( .A(pi128), .B(n5730), .Z(n5727)); - OR2 U5416 ( .A(n5731), .B(n5729), .Z(n5730)); - AN2 U5417 ( .A(n5732), .B(n5733), .Z(n5729)); - IV2 U5418 ( .A(n5734), .Z(n5733)); - AN2 U5419 ( .A(n5735), .B(n5736), .Z(n5734)); - OR2 U5420 ( .A(n5737), .B(n5738), .Z(n5736)); - AN2 U5421 ( .A(n5739), .B(n5740), .Z(n5738)); - OR2 U5422 ( .A(n5741), .B(n5115), .Z(n5740)); - AN2 U5423 ( .A(n5742), .B(n4778), .Z(n5741)); - OR2 U5424 ( .A(n5742), .B(n4778), .Z(n5739)); - IV2 U5425 ( .A(pi163), .Z(n4778)); - AN2 U5426 ( .A(n3177), .B(n4770), .Z(n5737)); - OR2 U5427 ( .A(n3177), .B(n4770), .Z(n5735)); - IV2 U5428 ( .A(pi028), .Z(n4770)); - AN2 U5429 ( .A(pi094), .B(n5732), .Z(n5731)); - OR2 U5430 ( .A(pi173), .B(pi185), .Z(n5732)); - AN2 U5431 ( .A(pi173), .B(pi185), .Z(n5725)); - AN2 U5432 ( .A(pi192), .B(n5743), .Z(n5722)); - OR2 U5433 ( .A(n5744), .B(n5745), .Z(n5743)); - OR2 U5434 ( .A(n5746), .B(n5747), .Z(n5745)); - AN2 U5435 ( .A(pi131), .B(n5748), .Z(n5747)); - AN2 U5436 ( .A(n5749), .B(n5040), .Z(n5746)); - OR2 U5437 ( .A(n5750), .B(n5748), .Z(n5749)); - OR2 U5438 ( .A(n5751), .B(n5752), .Z(n5748)); - AN2 U5439 ( .A(n5753), .B(pi059), .Z(n5752)); - AN2 U5440 ( .A(n5754), .B(n3286), .Z(n5751)); - OR2 U5441 ( .A(n5755), .B(n5753), .Z(n5754)); - AN2 U5442 ( .A(n5756), .B(n5757), .Z(n5753)); - IV2 U5443 ( .A(n5758), .Z(n5757)); - AN2 U5444 ( .A(n5759), .B(n5760), .Z(n5758)); - OR2 U5445 ( .A(po010), .B(n5761), .Z(n5760)); - AN2 U5446 ( .A(n5742), .B(n5439), .Z(n5761)); - OR2 U5447 ( .A(n5742), .B(n5439), .Z(n5759)); - IV2 U5448 ( .A(pi197), .Z(n5439)); - IV2 U5449 ( .A(n5762), .Z(n5742)); - OR2 U5450 ( .A(n5763), .B(n5764), .Z(n5762)); - AN2 U5451 ( .A(n5765), .B(n2837), .Z(n5764)); - OR2 U5452 ( .A(n5766), .B(n5767), .Z(n5765)); - AN2 U5453 ( .A(pi021), .B(pi201), .Z(n5767)); - AN2 U5454 ( .A(n5768), .B(n5769), .Z(n5766)); - OR2 U5455 ( .A(pi021), .B(pi201), .Z(n5769)); - OR2 U5456 ( .A(n5770), .B(n5771), .Z(n5768)); - IV2 U5457 ( .A(n5772), .Z(n5771)); - AN2 U5458 ( .A(n5773), .B(n5774), .Z(n5772)); - OR2 U5459 ( .A(n5775), .B(n5022), .Z(n5774)); - OR2 U5460 ( .A(n5431), .B(n5776), .Z(n5773)); - AN2 U5461 ( .A(n5777), .B(n5775), .Z(n5776)); - OR2 U5462 ( .A(n5778), .B(n5779), .Z(n5775)); - AN2 U5463 ( .A(n5780), .B(n5781), .Z(n5779)); - OR2 U5464 ( .A(n5782), .B(n5783), .Z(n5781)); - AN2 U5465 ( .A(n5784), .B(n5785), .Z(n5783)); - OR2 U5466 ( .A(n5786), .B(n5787), .Z(n5785)); - IV2 U5467 ( .A(pi181), .Z(n5787)); - AN2 U5468 ( .A(n2982), .B(n5019), .Z(n5786)); - OR2 U5469 ( .A(n2982), .B(n5019), .Z(n5784)); - IV2 U5470 ( .A(pi011), .Z(n5019)); - AN2 U5471 ( .A(n5027), .B(n2957), .Z(n5782)); - OR2 U5472 ( .A(n2957), .B(n5027), .Z(n5780)); - IV2 U5473 ( .A(pi086), .Z(n5027)); - OR2 U5474 ( .A(n5022), .B(n5778), .Z(n5777)); - AN2 U5475 ( .A(n5165), .B(n5031), .Z(n5778)); - IV2 U5476 ( .A(pi165), .Z(n5031)); - IV2 U5477 ( .A(pi032), .Z(n5022)); - AN2 U5478 ( .A(pi165), .B(pi107), .Z(n5770)); - AN2 U5479 ( .A(pi192), .B(n5788), .Z(n5763)); - OR2 U5480 ( .A(n5789), .B(n5790), .Z(n5788)); - AN2 U5481 ( .A(pi121), .B(n5000), .Z(n5790)); - AN2 U5482 ( .A(n5791), .B(n5792), .Z(n5789)); - OR2 U5483 ( .A(pi121), .B(n5000), .Z(n5792)); - OR2 U5484 ( .A(n5793), .B(n5794), .Z(n5791)); - AN2 U5485 ( .A(pi053), .B(n5795), .Z(n5794)); - AN2 U5486 ( .A(n5796), .B(n5004), .Z(n5793)); - OR2 U5487 ( .A(pi053), .B(n5795), .Z(n5796)); - OR2 U5488 ( .A(n5797), .B(n5798), .Z(n5795)); - AN2 U5489 ( .A(pi184), .B(n5008), .Z(n5798)); - AN2 U5490 ( .A(n5799), .B(n5800), .Z(n5797)); - OR2 U5491 ( .A(pi184), .B(n5008), .Z(n5800)); - OR2 U5492 ( .A(n5801), .B(n5802), .Z(n5799)); - AN2 U5493 ( .A(pi181), .B(pi103), .Z(n5802)); - AN2 U5494 ( .A(n5803), .B(n2962), .Z(n5801)); - OR2 U5495 ( .A(pi103), .B(pi181), .Z(n5803)); - AN2 U5496 ( .A(pi059), .B(n5756), .Z(n5755)); - AN2 U5497 ( .A(pi131), .B(n5756), .Z(n5750)); - OR2 U5498 ( .A(pi001), .B(n5037), .Z(n5756)); - AN2 U5499 ( .A(pi001), .B(n5037), .Z(n5744)); - AN2 U5500 ( .A(pi083), .B(n5715), .Z(n5714)); - OR2 U5501 ( .A(pi162), .B(n4874), .Z(n5715)); - AN2 U5502 ( .A(pi162), .B(n4874), .Z(n5708)); - AN2 U5503 ( .A(pi036), .B(n5667), .Z(n5666)); - AN2 U5504 ( .A(pi101), .B(n5667), .Z(n5661)); - OR2 U5505 ( .A(pi205), .B(n4915), .Z(n5667)); - AN2 U5506 ( .A(pi205), .B(n4915), .Z(n5655)); - AN2 U5507 ( .A(po036), .B(n5350), .Z(n5630)); - OR2 U5508 ( .A(po036), .B(n5350), .Z(n5628)); - IV2 U5509 ( .A(pi018), .Z(n5350)); - AN2 U5510 ( .A(pi099), .B(n5625), .Z(n5624)); - OR2 U5511 ( .A(pi180), .B(n4947), .Z(n5625)); - AN2 U5512 ( .A(pi180), .B(n4947), .Z(n5618)); - AN2 U5513 ( .A(n3261), .B(pi049), .Z(n5347)); - AN2 U5514 ( .A(n3926), .B(n5804), .Z(n5551)); - OR2 U5515 ( .A(n5805), .B(n5806), .Z(n5804)); - OR2 U5516 ( .A(pi085), .B(pi019), .Z(n5806)); - OR2 U5517 ( .A(pi110), .B(n5807), .Z(n5805)); - OR2 U5518 ( .A(pi167), .B(pi164), .Z(n5807)); - AN2 U5519 ( .A(pi126), .B(pi190), .Z(n5549)); - AN2 U5520 ( .A(n5808), .B(pi035), .Z(n5547)); - AN2 U5521 ( .A(pi056), .B(pi100), .Z(n5808)); - AN2 U5522 ( .A(pi054), .B(n5809), .Z(n5504)); - OR2 U5523 ( .A(n4167), .B(n5810), .Z(n5809)); - OR2 U5524 ( .A(pi146), .B(pi025), .Z(n5810)); - AN2 U5525 ( .A(n5811), .B(n2882), .Z(po017)); - OR2 U5526 ( .A(pi200), .B(n3003), .Z(n5811)); - OR2 U5527 ( .A(n5812), .B(n5813), .Z(po016)); - OR2 U5528 ( .A(n5814), .B(n5815), .Z(n5813)); - AN2 U5529 ( .A(n3280), .B(n3064), .Z(n5815)); - AN2 U5530 ( .A(n5100), .B(n5816), .Z(n5814)); - OR2 U5531 ( .A(n5817), .B(n5818), .Z(n5816)); - AN2 U5532 ( .A(n3055), .B(n5819), .Z(n5818)); - OR2 U5533 ( .A(n2845), .B(n3143), .Z(n5819)); - OR2 U5534 ( .A(n2978), .B(n3147), .Z(n3143)); - AN2 U5535 ( .A(n3127), .B(n5820), .Z(n5817)); - OR2 U5536 ( .A(n2833), .B(n3138), .Z(n5820)); - OR2 U5537 ( .A(n2880), .B(n3147), .Z(n3138)); - OR2 U5538 ( .A(n2998), .B(n5821), .Z(n3147)); - OR2 U5539 ( .A(n2882), .B(n2862), .Z(n5821)); - OR2 U5540 ( .A(n2925), .B(n2901), .Z(n2882)); - AN2 U5541 ( .A(pi192), .B(n3036), .Z(n3127)); - IV2 U5542 ( .A(n5822), .Z(n5100)); - OR2 U5543 ( .A(n5823), .B(n5824), .Z(n5812)); - AN2 U5544 ( .A(n5825), .B(pi192), .Z(n5824)); - AN2 U5545 ( .A(n5826), .B(po010), .Z(n5825)); - AN2 U5546 ( .A(n5827), .B(n2837), .Z(n5823)); - AN2 U5547 ( .A(n5828), .B(n5829), .Z(n5827)); - OR2 U5548 ( .A(n5830), .B(n5831), .Z(po008)); - AN2 U5549 ( .A(n3344), .B(n3251), .Z(n5831)); - OR2 U5550 ( .A(n5832), .B(n5833), .Z(n3251)); - AN2 U5551 ( .A(n3355), .B(n5454), .Z(n5832)); - OR2 U5552 ( .A(n5834), .B(n5835), .Z(n5454)); - AN2 U5553 ( .A(n5836), .B(n4426), .Z(n5834)); - IV2 U5554 ( .A(n3352), .Z(n3355)); - AN2 U5555 ( .A(n3250), .B(n5837), .Z(n5830)); - OR2 U5556 ( .A(n5838), .B(n5839), .Z(n5837)); - OR2 U5557 ( .A(n5840), .B(n3245), .Z(n5839)); - OR2 U5558 ( .A(n5841), .B(n5842), .Z(n3245)); - AN2 U5559 ( .A(n3244), .B(n3699), .Z(n5842)); - AN2 U5560 ( .A(n3242), .B(n3700), .Z(n5841)); - IV2 U5561 ( .A(n5843), .Z(n3242)); - AN2 U5562 ( .A(n3352), .B(n3701), .Z(n5840)); - OR2 U5563 ( .A(n5844), .B(n5845), .Z(n5838)); - AN2 U5564 ( .A(n4418), .B(n3762), .Z(n5845)); - AN2 U5565 ( .A(n5846), .B(n3236), .Z(n5844)); - OR2 U5566 ( .A(pi037), .B(n5847), .Z(po007)); - IV2 U5567 ( .A(pi116), .Z(n5847)); - OR2 U5568 ( .A(n5848), .B(n5849), .Z(po006)); - AN2 U5569 ( .A(n3370), .B(n5850), .Z(n5849)); - OR2 U5570 ( .A(n5851), .B(n5852), .Z(n5850)); - OR2 U5571 ( .A(n5853), .B(n5138), .Z(n5852)); - OR2 U5572 ( .A(n5854), .B(n3566), .Z(n5138)); - AN2 U5573 ( .A(n3512), .B(n3926), .Z(n3566)); - AN2 U5574 ( .A(n3926), .B(n4368), .Z(n5854)); - OR2 U5575 ( .A(n5855), .B(n5856), .Z(n5851)); - AN2 U5576 ( .A(n5139), .B(n3380), .Z(n5856)); - OR2 U5577 ( .A(n5857), .B(n5858), .Z(n5139)); - AN2 U5578 ( .A(n5859), .B(n3261), .Z(n5857)); - AN2 U5579 ( .A(n5860), .B(pi118), .Z(n5855)); - AN2 U5580 ( .A(n5861), .B(n3261), .Z(n5860)); - OR2 U5581 ( .A(n5858), .B(n5859), .Z(n5861)); - OR2 U5582 ( .A(n5862), .B(n5863), .Z(n5859)); - OR2 U5583 ( .A(n3404), .B(n5864), .Z(n5863)); - AN2 U5584 ( .A(n5865), .B(pi060), .Z(n5864)); - AN2 U5585 ( .A(n4368), .B(n5866), .Z(n5865)); - IV2 U5586 ( .A(n3446), .Z(n3404)); - AN2 U5587 ( .A(n4367), .B(pi196), .Z(n5862)); - IV2 U5588 ( .A(n4364), .Z(n4367)); - IV2 U5589 ( .A(n5867), .Z(n5858)); - IV2 U5590 ( .A(n3393), .Z(n3370)); - AN2 U5591 ( .A(n3393), .B(n5868), .Z(n5848)); - OR2 U5592 ( .A(n5869), .B(n5870), .Z(n5868)); - OR2 U5593 ( .A(n5135), .B(n5871), .Z(n5870)); - AN2 U5594 ( .A(n3480), .B(n5872), .Z(n5871)); - AN2 U5595 ( .A(n5867), .B(n3321), .Z(n5135)); - OR2 U5596 ( .A(po104), .B(n4364), .Z(n5867)); - OR2 U5597 ( .A(n5873), .B(n5874), .Z(n5869)); - OR2 U5598 ( .A(n5875), .B(n5876), .Z(n5874)); - AN2 U5599 ( .A(n5877), .B(po071), .Z(n5876)); - OR2 U5600 ( .A(n5136), .B(n5878), .Z(n5877)); - OR2 U5601 ( .A(n5879), .B(n5880), .Z(n5136)); - OR2 U5602 ( .A(n5881), .B(n5882), .Z(n5880)); - AN2 U5603 ( .A(n3398), .B(n4364), .Z(n5882)); - AN2 U5604 ( .A(n4363), .B(n3419), .Z(n5879)); - AN2 U5605 ( .A(n5883), .B(n3398), .Z(n5875)); - AN2 U5606 ( .A(n3446), .B(n3533), .Z(n3398)); - AN2 U5607 ( .A(n4364), .B(n3913), .Z(n5883)); - OR2 U5608 ( .A(n4062), .B(po027), .Z(n4364)); - IV2 U5609 ( .A(n4061), .Z(n4062)); - AN2 U5610 ( .A(n3416), .B(n4363), .Z(n5873)); - IV2 U5611 ( .A(n4368), .Z(n4363)); - OR2 U5612 ( .A(n3363), .B(n4061), .Z(n4368)); - OR2 U5613 ( .A(n5884), .B(n5885), .Z(n4061)); - OR2 U5614 ( .A(n5886), .B(n5887), .Z(n5885)); - AN2 U5615 ( .A(n5888), .B(n4943), .Z(n5887)); - AN2 U5616 ( .A(n5889), .B(n3989), .Z(n5886)); - OR2 U5617 ( .A(n5890), .B(n5891), .Z(n5884)); - OR2 U5618 ( .A(n5892), .B(n3490), .Z(n5891)); - AN2 U5619 ( .A(n5893), .B(n5894), .Z(n5890)); - AN2 U5620 ( .A(n3495), .B(n5895), .Z(n5893)); - AN2 U5621 ( .A(n3446), .B(n3480), .Z(n3416)); - OR2 U5622 ( .A(po104), .B(n3942), .Z(n3446)); - OR2 U5623 ( .A(n5896), .B(n3253), .Z(po012)); - AN2 U5624 ( .A(n5897), .B(pi054), .Z(n3253)); - OR2 U5625 ( .A(n4133), .B(n5898), .Z(n5897)); - AN2 U5626 ( .A(n4127), .B(n3255), .Z(n5896)); - OR2 U5627 ( .A(pi054), .B(n5120), .Z(n3255)); - OR2 U5628 ( .A(n5899), .B(n4167), .Z(n5120)); - AN2 U5629 ( .A(n4133), .B(n4128), .Z(n5899)); - IV2 U5630 ( .A(po064), .Z(n4133)); - OR2 U5631 ( .A(n5900), .B(n4372), .Z(n4127)); - OR2 U5632 ( .A(n5901), .B(n5902), .Z(n4372)); - AN2 U5633 ( .A(n4380), .B(n4319), .Z(n5901)); - AN2 U5634 ( .A(n5903), .B(n4374), .Z(n5900)); - OR2 U5635 ( .A(n5904), .B(n5905), .Z(n4374)); - AN2 U5636 ( .A(n5906), .B(n3261), .Z(n5905)); - OR2 U5637 ( .A(n5907), .B(n5908), .Z(n5906)); - OR2 U5638 ( .A(n5909), .B(n5910), .Z(n5908)); - AN2 U5639 ( .A(n5911), .B(po103), .Z(n5910)); - AN2 U5640 ( .A(n5912), .B(pi058), .Z(n5911)); - AN2 U5641 ( .A(n5913), .B(n5914), .Z(n5912)); - AN2 U5642 ( .A(n5915), .B(n5916), .Z(n5913)); - OR2 U5643 ( .A(pi204), .B(n5917), .Z(n5916)); - AN2 U5644 ( .A(n4057), .B(n4013), .Z(n5917)); - OR2 U5645 ( .A(n5918), .B(n5919), .Z(n5915)); - AN2 U5646 ( .A(po040), .B(n3966), .Z(n5918)); - AN2 U5647 ( .A(n5920), .B(n3265), .Z(n5909)); - AN2 U5648 ( .A(n5921), .B(n5922), .Z(n5920)); - AN2 U5649 ( .A(n4057), .B(n4316), .Z(n5922)); - AN2 U5650 ( .A(n4157), .B(n5914), .Z(n5921)); - OR2 U5651 ( .A(n5923), .B(n4319), .Z(n5914)); - AN2 U5652 ( .A(pi065), .B(pi192), .Z(n5923)); - OR2 U5653 ( .A(pi204), .B(n4013), .Z(n4157)); - AN2 U5654 ( .A(n5924), .B(n4046), .Z(n5907)); - AN2 U5655 ( .A(po040), .B(n3263), .Z(n5924)); - OR2 U5656 ( .A(n5925), .B(n2837), .Z(n3263)); - AN2 U5657 ( .A(n3264), .B(pi058), .Z(n5925)); - AN2 U5658 ( .A(n4391), .B(n4319), .Z(n5904)); - AN2 U5659 ( .A(n3265), .B(n4013), .Z(n4391)); - IV2 U5660 ( .A(n4158), .Z(n5903)); - OR2 U5661 ( .A(n4312), .B(n5926), .Z(n4158)); - OR2 U5662 ( .A(n4040), .B(n4229), .Z(n5926)); - IV2 U5663 ( .A(n4184), .Z(n4229)); - OR2 U5664 ( .A(n5927), .B(n5928), .Z(n4184)); - OR2 U5665 ( .A(n5929), .B(n5930), .Z(n5928)); - AN2 U5666 ( .A(n5931), .B(n5932), .Z(n5929)); - OR2 U5667 ( .A(n5933), .B(n5934), .Z(n5932)); - AN2 U5668 ( .A(n3457), .B(n3493), .Z(n5934)); - IV2 U5669 ( .A(n3661), .Z(n3493)); - OR2 U5670 ( .A(n5935), .B(n5936), .Z(n3661)); - OR2 U5671 ( .A(n3229), .B(n3235), .Z(n5936)); - OR2 U5672 ( .A(n5937), .B(n5938), .Z(n3235)); - OR2 U5673 ( .A(n5939), .B(n5940), .Z(n5938)); - AN2 U5674 ( .A(n5452), .B(n3241), .Z(n5940)); - AN2 U5675 ( .A(n5453), .B(n3243), .Z(n5939)); - AN2 U5676 ( .A(po082), .B(n5846), .Z(n5937)); - OR2 U5677 ( .A(n5941), .B(n5942), .Z(n5846)); - AN2 U5678 ( .A(n5452), .B(n3700), .Z(n5942)); - AN2 U5679 ( .A(n3638), .B(n3635), .Z(n5452)); - IV2 U5680 ( .A(pi098), .Z(n3638)); - AN2 U5681 ( .A(n5453), .B(n3699), .Z(n5941)); - AN2 U5682 ( .A(n3597), .B(n3593), .Z(n5453)); - OR2 U5683 ( .A(n5943), .B(n5944), .Z(n3229)); - AN2 U5684 ( .A(po082), .B(n3344), .Z(n5944)); - AN2 U5685 ( .A(n3352), .B(n5945), .Z(n5943)); - OR2 U5686 ( .A(n5946), .B(n5947), .Z(n5945)); - OR2 U5687 ( .A(n3241), .B(n3243), .Z(n5947)); - AN2 U5688 ( .A(po082), .B(n3701), .Z(n5946)); - IV2 U5689 ( .A(n5833), .Z(n3701)); - OR2 U5690 ( .A(n3233), .B(n5948), .Z(n5935)); - AN2 U5691 ( .A(n3339), .B(n5949), .Z(n5948)); - AN2 U5692 ( .A(n5949), .B(po011), .Z(n3233)); - OR2 U5693 ( .A(n5950), .B(n5951), .Z(n5949)); - OR2 U5694 ( .A(n5952), .B(n5953), .Z(n5951)); - AN2 U5695 ( .A(n3241), .B(n3635), .Z(n5953)); - AN2 U5696 ( .A(n3992), .B(n3700), .Z(n3241)); - AN2 U5697 ( .A(n3632), .B(pi192), .Z(n3700)); - IV2 U5698 ( .A(pi004), .Z(n3992)); - AN2 U5699 ( .A(n3243), .B(n3593), .Z(n5952)); - OR2 U5700 ( .A(po036), .B(n4440), .Z(n3593)); - AN2 U5701 ( .A(n5372), .B(n3699), .Z(n3243)); - AN2 U5702 ( .A(po082), .B(n3762), .Z(n5950)); - OR2 U5703 ( .A(n5954), .B(n5955), .Z(n3762)); - OR2 U5704 ( .A(n5956), .B(n5957), .Z(n5955)); - AN2 U5705 ( .A(po036), .B(n5958), .Z(n5957)); - OR2 U5706 ( .A(n5959), .B(po001), .Z(n5958)); - AN2 U5707 ( .A(pi192), .B(n5960), .Z(n5956)); - OR2 U5708 ( .A(n5961), .B(n5962), .Z(n5960)); - AN2 U5709 ( .A(po001), .B(n4001), .Z(n5962)); - AN2 U5710 ( .A(n3635), .B(n3998), .Z(n5961)); - OR2 U5711 ( .A(po036), .B(n4001), .Z(n3635)); - IV2 U5712 ( .A(pi171), .Z(n4001)); - AN2 U5713 ( .A(n3699), .B(n4440), .Z(n5954)); - AN2 U5714 ( .A(n2837), .B(n3590), .Z(n3699)); - AN2 U5715 ( .A(n5963), .B(n3667), .Z(n5933)); - AN2 U5716 ( .A(n3291), .B(n3341), .Z(n3667)); - IV2 U5717 ( .A(n3339), .Z(n3341)); - OR2 U5718 ( .A(n5964), .B(n5965), .Z(n3339)); - AN2 U5719 ( .A(n5966), .B(n4441), .Z(n5965)); - AN2 U5720 ( .A(n5448), .B(po036), .Z(n5964)); - IV2 U5721 ( .A(n5966), .Z(n5448)); - OR2 U5722 ( .A(n5967), .B(n5968), .Z(n3291)); - AN2 U5723 ( .A(n5969), .B(n3688), .Z(n5968)); - IV2 U5724 ( .A(n3746), .Z(n5969)); - AN2 U5725 ( .A(po011), .B(n3746), .Z(n5967)); - OR2 U5726 ( .A(n3717), .B(n3705), .Z(n3746)); - AN2 U5727 ( .A(n3495), .B(n5970), .Z(n5963)); - OR2 U5728 ( .A(n5971), .B(n5972), .Z(n5970)); - OR2 U5729 ( .A(n5973), .B(n5974), .Z(n5972)); - AN2 U5730 ( .A(n5975), .B(pi192), .Z(n5974)); - AN2 U5731 ( .A(n3567), .B(n5976), .Z(n5975)); - OR2 U5732 ( .A(n5977), .B(n5978), .Z(n5976)); - OR2 U5733 ( .A(n5979), .B(n5980), .Z(n5978)); - AN2 U5734 ( .A(n4635), .B(n5981), .Z(n5979)); - IV2 U5735 ( .A(n4464), .Z(n4635)); - OR2 U5736 ( .A(po039), .B(n3870), .Z(n4464)); - IV2 U5737 ( .A(pi016), .Z(n3870)); - OR2 U5738 ( .A(n5982), .B(n5983), .Z(n5977)); - AN2 U5739 ( .A(n5984), .B(n3033), .Z(n5983)); - IV2 U5740 ( .A(n3038), .Z(n3033)); - OR2 U5741 ( .A(po070), .B(n3199), .Z(n3038)); - IV2 U5742 ( .A(pi096), .Z(n3199)); - AN2 U5743 ( .A(n5985), .B(n5986), .Z(n5982)); - OR2 U5744 ( .A(n5987), .B(n3042), .Z(n5986)); - IV2 U5745 ( .A(n3037), .Z(n3042)); - OR2 U5746 ( .A(po099), .B(n3171), .Z(n3037)); - AN2 U5747 ( .A(n3063), .B(n5988), .Z(n5987)); - OR2 U5748 ( .A(n5989), .B(n5990), .Z(n5988)); - AN2 U5749 ( .A(n3036), .B(n5991), .Z(n5989)); - OR2 U5750 ( .A(n5992), .B(n3010), .Z(n5991)); - OR2 U5751 ( .A(n5993), .B(n5994), .Z(n3010)); - AN2 U5752 ( .A(pi088), .B(n3012), .Z(n5992)); - IV2 U5753 ( .A(n5995), .Z(n3036)); - OR2 U5754 ( .A(n5996), .B(n5990), .Z(n5995)); - AN2 U5755 ( .A(pi166), .B(n3049), .Z(n5990)); - AN2 U5756 ( .A(po010), .B(n3106), .Z(n5996)); - OR2 U5757 ( .A(n3534), .B(n3363), .Z(n3567)); - AN2 U5758 ( .A(n5997), .B(n3457), .Z(n5973)); - IV2 U5759 ( .A(n4060), .Z(n3457)); - OR2 U5760 ( .A(n5998), .B(n5999), .Z(n4060)); - AN2 U5761 ( .A(po027), .B(n3451), .Z(n5998)); - AN2 U5762 ( .A(n3760), .B(n4652), .Z(n5997)); - AN2 U5763 ( .A(n6000), .B(n6001), .Z(n5971)); - OR2 U5764 ( .A(n3261), .B(n3525), .Z(n6001)); - AN2 U5765 ( .A(n3363), .B(n3321), .Z(n3525)); - OR2 U5766 ( .A(n6002), .B(n6003), .Z(n6000)); - AN2 U5767 ( .A(n6004), .B(n2837), .Z(n6003)); - OR2 U5768 ( .A(n6005), .B(n6006), .Z(n6004)); - OR2 U5769 ( .A(n6007), .B(n6008), .Z(n6006)); - AN2 U5770 ( .A(n4641), .B(n5981), .Z(n6007)); - IV2 U5771 ( .A(n4468), .Z(n4641)); - OR2 U5772 ( .A(po039), .B(n4735), .Z(n4468)); - IV2 U5773 ( .A(pi040), .Z(n4735)); - OR2 U5774 ( .A(n6009), .B(n6010), .Z(n6005)); - AN2 U5775 ( .A(n5985), .B(n6011), .Z(n6010)); - OR2 U5776 ( .A(n6012), .B(n6013), .Z(n6011)); - OR2 U5777 ( .A(n3066), .B(n6014), .Z(n6013)); - AN2 U5778 ( .A(n6015), .B(n6016), .Z(n6014)); - IV2 U5779 ( .A(n3112), .Z(n3066)); - OR2 U5780 ( .A(po099), .B(n3177), .Z(n3112)); - AN2 U5781 ( .A(n6017), .B(n6018), .Z(n6012)); - OR2 U5782 ( .A(n6019), .B(n6020), .Z(n6018)); - AN2 U5783 ( .A(n6021), .B(n3119), .Z(n6019)); - OR2 U5784 ( .A(n6022), .B(n5993), .Z(n6021)); - AN2 U5785 ( .A(n2890), .B(n5000), .Z(n5993)); - AN2 U5786 ( .A(pi201), .B(n3012), .Z(n6022)); - OR2 U5787 ( .A(n2890), .B(n5000), .Z(n3012)); - IV2 U5788 ( .A(n2886), .Z(n2890)); - OR2 U5789 ( .A(n6023), .B(n6024), .Z(n2886)); - OR2 U5790 ( .A(n6025), .B(n6026), .Z(n6024)); - AN2 U5791 ( .A(n6027), .B(n2998), .Z(n6026)); - AN2 U5792 ( .A(po079), .B(n6028), .Z(n6025)); - OR2 U5793 ( .A(n6029), .B(n4095), .Z(n6028)); - OR2 U5794 ( .A(n6030), .B(n6031), .Z(n4095)); - AN2 U5795 ( .A(n4098), .B(n2887), .Z(n6031)); - AN2 U5796 ( .A(n6032), .B(po031), .Z(n6030)); - AN2 U5797 ( .A(n2990), .B(n2974), .Z(n6032)); - AN2 U5798 ( .A(n2990), .B(n5169), .Z(n6029)); - OR2 U5799 ( .A(n6033), .B(po106), .Z(n2990)); - AN2 U5800 ( .A(n2837), .B(n5431), .Z(n6033)); - OR2 U5801 ( .A(n6034), .B(n6035), .Z(n6023)); - AN2 U5802 ( .A(n4099), .B(n6036), .Z(n6035)); - OR2 U5803 ( .A(n6037), .B(n6038), .Z(n6036)); - AN2 U5804 ( .A(n6039), .B(n5165), .Z(n6038)); - OR2 U5805 ( .A(n6040), .B(n5169), .Z(n6039)); - OR2 U5806 ( .A(n2978), .B(n2862), .Z(n5169)); - AN2 U5807 ( .A(po031), .B(n2974), .Z(n6040)); - AN2 U5808 ( .A(n6041), .B(n2974), .Z(n6037)); - AN2 U5809 ( .A(n5172), .B(n2957), .Z(n6041)); - AN2 U5810 ( .A(n2947), .B(n2837), .Z(n4099)); - AN2 U5811 ( .A(n6042), .B(n4098), .Z(n6034)); - AN2 U5812 ( .A(n2891), .B(pi192), .Z(n4098)); - IV2 U5813 ( .A(n2892), .Z(n2891)); - AN2 U5814 ( .A(n6043), .B(n3847), .Z(n6042)); - IV2 U5815 ( .A(n2885), .Z(n6043)); - AN2 U5816 ( .A(n5984), .B(n3076), .Z(n6009)); - IV2 U5817 ( .A(n3109), .Z(n3076)); - OR2 U5818 ( .A(po070), .B(n3205), .Z(n3109)); - IV2 U5819 ( .A(pi128), .Z(n3205)); - AN2 U5820 ( .A(n5985), .B(n6044), .Z(n6002)); - OR2 U5821 ( .A(n6045), .B(n6046), .Z(n5927)); - AN2 U5822 ( .A(n6047), .B(n3945), .Z(n6046)); - IV2 U5823 ( .A(n4313), .Z(n3945)); - OR2 U5824 ( .A(n3321), .B(n2837), .Z(n4313)); - AN2 U5825 ( .A(pi050), .B(n4975), .Z(n6047)); - AN2 U5826 ( .A(n6048), .B(n6049), .Z(n6045)); - AN2 U5827 ( .A(n6050), .B(n6051), .Z(n6049)); - OR2 U5828 ( .A(n3363), .B(n6052), .Z(n6051)); - OR2 U5829 ( .A(po027), .B(n3989), .Z(n6050)); - AN2 U5830 ( .A(n6053), .B(n4943), .Z(n6048)); - OR2 U5831 ( .A(n4239), .B(n4192), .Z(n4312)); - OR2 U5832 ( .A(n6054), .B(n6055), .Z(po003)); - OR2 U5833 ( .A(n6056), .B(n6057), .Z(n6055)); - AN2 U5834 ( .A(n6058), .B(pi054), .Z(n6057)); - OR2 U5835 ( .A(n6059), .B(n6060), .Z(n6058)); - AN2 U5836 ( .A(n4177), .B(n5126), .Z(n6060)); - AN2 U5837 ( .A(n5125), .B(n5898), .Z(n6059)); - AN2 U5838 ( .A(n6061), .B(n4129), .Z(n6056)); - AN2 U5839 ( .A(n4177), .B(n5125), .Z(n6061)); - OR2 U5840 ( .A(n6062), .B(n3257), .Z(n5125)); - OR2 U5841 ( .A(n5902), .B(n6063), .Z(n3257)); - OR2 U5842 ( .A(n6064), .B(n6065), .Z(n6063)); - AN2 U5843 ( .A(n4403), .B(n4319), .Z(n6065)); - IV2 U5844 ( .A(po004), .Z(n4319)); - OR2 U5845 ( .A(n6066), .B(n4380), .Z(n4403)); - AN2 U5846 ( .A(n6067), .B(n3259), .Z(n6066)); - AN2 U5847 ( .A(n4053), .B(n4013), .Z(n6067)); - OR2 U5848 ( .A(n6068), .B(n3265), .Z(n4053)); - AN2 U5849 ( .A(pi058), .B(n3261), .Z(n6068)); - AN2 U5850 ( .A(n6069), .B(n6070), .Z(n6064)); - AN2 U5851 ( .A(n4387), .B(n4013), .Z(n6070)); - IV2 U5852 ( .A(po040), .Z(n4013)); - AN2 U5853 ( .A(pi065), .B(n3259), .Z(n6069)); - OR2 U5854 ( .A(n6071), .B(n4379), .Z(n5902)); - IV2 U5855 ( .A(n4159), .Z(n4379)); - AN2 U5856 ( .A(n4380), .B(n4404), .Z(n6071)); - IV2 U5857 ( .A(n4161), .Z(n4404)); - IV2 U5858 ( .A(n4141), .Z(n4380)); - OR2 U5859 ( .A(n4016), .B(n6072), .Z(n4141)); - OR2 U5860 ( .A(n6073), .B(n6074), .Z(n6072)); - AN2 U5861 ( .A(n6075), .B(n4242), .Z(n6074)); - OR2 U5862 ( .A(n6076), .B(n6077), .Z(n4016)); - AN2 U5863 ( .A(n4040), .B(n3951), .Z(n6076)); - AN2 U5864 ( .A(n3259), .B(n6078), .Z(n6062)); - OR2 U5865 ( .A(n6079), .B(n3926), .Z(n6078)); - AN2 U5866 ( .A(n3264), .B(n4387), .Z(n6079)); - AN2 U5867 ( .A(n3261), .B(n4026), .Z(n4387)); - IV2 U5868 ( .A(n6080), .Z(n3264)); - OR2 U5869 ( .A(n6081), .B(n5919), .Z(n6080)); - AN2 U5870 ( .A(n4330), .B(n6082), .Z(n3259)); - AN2 U5871 ( .A(n4205), .B(n3314), .Z(n6082)); - IV2 U5872 ( .A(n5898), .Z(n4177)); - AN2 U5873 ( .A(n4172), .B(n5126), .Z(n6054)); - OR2 U5874 ( .A(n6083), .B(n6084), .Z(n5126)); - OR2 U5875 ( .A(n6085), .B(n6086), .Z(n6084)); - AN2 U5876 ( .A(n4227), .B(n4159), .Z(n6086)); - OR2 U5877 ( .A(po004), .B(n4161), .Z(n4159)); - OR2 U5878 ( .A(n4310), .B(n3321), .Z(n4161)); - OR2 U5879 ( .A(n6087), .B(n6088), .Z(n4227)); - OR2 U5880 ( .A(n6089), .B(n6077), .Z(n6088)); - OR2 U5881 ( .A(n6090), .B(n6091), .Z(n6077)); - OR2 U5882 ( .A(n3317), .B(n6092), .Z(n6091)); - AN2 U5883 ( .A(n4291), .B(n4056), .Z(n6092)); - AN2 U5884 ( .A(n3321), .B(po103), .Z(n3317)); - AN2 U5885 ( .A(n4040), .B(n3321), .Z(n6090)); - AN2 U5886 ( .A(n4192), .B(n6075), .Z(n6089)); - OR2 U5887 ( .A(n3321), .B(n6093), .Z(n6075)); - OR2 U5888 ( .A(n6073), .B(n6094), .Z(n6087)); - AN2 U5889 ( .A(n4040), .B(n4291), .Z(n6094)); - AN2 U5890 ( .A(po040), .B(n6095), .Z(n6073)); - OR2 U5891 ( .A(n4040), .B(n6096), .Z(n6095)); - OR2 U5892 ( .A(n3318), .B(n4293), .Z(n6096)); - OR2 U5893 ( .A(n3951), .B(n3321), .Z(n4293)); - AN2 U5894 ( .A(n4056), .B(n6097), .Z(n3318)); - AN2 U5895 ( .A(n4057), .B(pi192), .Z(n6097)); - IV2 U5896 ( .A(n4026), .Z(n4056)); - OR2 U5897 ( .A(pi058), .B(n3265), .Z(n4026)); - IV2 U5898 ( .A(n3314), .Z(n4040)); - OR2 U5899 ( .A(n6098), .B(n4201), .Z(n3314)); - IV2 U5900 ( .A(po091), .Z(n4201)); - AN2 U5901 ( .A(n3261), .B(n4200), .Z(n6098)); - AN2 U5902 ( .A(n6081), .B(pi192), .Z(n6085)); - AN2 U5903 ( .A(n4150), .B(po004), .Z(n6081)); - IV2 U5904 ( .A(pi065), .Z(n4150)); - OR2 U5905 ( .A(n6099), .B(n4396), .Z(n6083)); - AN2 U5906 ( .A(n4406), .B(n6100), .Z(n4396)); - OR2 U5907 ( .A(n6101), .B(n3321), .Z(n6100)); - AN2 U5908 ( .A(n6102), .B(n6103), .Z(n6101)); - AN2 U5909 ( .A(n4223), .B(n4057), .Z(n6103)); - AN2 U5910 ( .A(n4310), .B(n6104), .Z(n6102)); - OR2 U5911 ( .A(po040), .B(n5919), .Z(n6104)); - IV2 U5912 ( .A(pi204), .Z(n5919)); - IV2 U5913 ( .A(n4156), .Z(n4310)); - OR2 U5914 ( .A(pi065), .B(n2837), .Z(n4156)); - AN2 U5915 ( .A(po004), .B(n6105), .Z(n6099)); - OR2 U5916 ( .A(n6106), .B(n3321), .Z(n6105)); - AN2 U5917 ( .A(n4406), .B(n6093), .Z(n6106)); - OR2 U5918 ( .A(n6107), .B(n4028), .Z(n6093)); - AN2 U5919 ( .A(n4223), .B(n4291), .Z(n4028)); - AN2 U5920 ( .A(n4057), .B(n3951), .Z(n4291)); - IV2 U5921 ( .A(n4041), .Z(n3951)); - OR2 U5922 ( .A(pi204), .B(n2837), .Z(n4041)); - OR2 U5923 ( .A(po103), .B(n4316), .Z(n4223)); - IV2 U5924 ( .A(pi058), .Z(n4316)); - AN2 U5925 ( .A(po040), .B(n3322), .Z(n6107)); - OR2 U5926 ( .A(n4046), .B(n4045), .Z(n3322)); - OR2 U5927 ( .A(n6108), .B(n6109), .Z(n4045)); - AN2 U5928 ( .A(n4148), .B(n4057), .Z(n6109)); - OR2 U5929 ( .A(po091), .B(n3966), .Z(n4057)); - IV2 U5930 ( .A(pi129), .Z(n3966)); - AN2 U5931 ( .A(n4203), .B(po103), .Z(n6108)); - IV2 U5932 ( .A(n4200), .Z(n4203)); - OR2 U5933 ( .A(pi129), .B(n2837), .Z(n4200)); - AN2 U5934 ( .A(po103), .B(po091), .Z(n4046)); - AN2 U5935 ( .A(n5898), .B(n4129), .Z(n4172)); - IV2 U5936 ( .A(pi054), .Z(n4129)); - OR2 U5937 ( .A(n4167), .B(n4128), .Z(n5898)); - IV2 U5938 ( .A(po085), .Z(n4128)); - IV2 U5939 ( .A(pi052), .Z(n4167)); - AN2 U5940 ( .A(n6110), .B(n6111), .Z(po002)); - OR2 U5941 ( .A(n3306), .B(n4450), .Z(n6111)); - OR2 U5942 ( .A(n4458), .B(n4606), .Z(n6110)); - IV2 U5943 ( .A(n3306), .Z(n4458)); - OR2 U5944 ( .A(n6112), .B(n4652), .Z(n3306)); - OR2 U5945 ( .A(n6113), .B(n6114), .Z(n4652)); - AN2 U5946 ( .A(n6115), .B(n2837), .Z(n6114)); - OR2 U5947 ( .A(n6116), .B(n6117), .Z(n6115)); - AN2 U5948 ( .A(pi108), .B(n4881), .Z(n6117)); - AN2 U5949 ( .A(n4475), .B(n6118), .Z(n6116)); - OR2 U5950 ( .A(n5467), .B(n6119), .Z(n6118)); - IV2 U5951 ( .A(n5488), .Z(n6119)); - OR2 U5952 ( .A(po102), .B(n5322), .Z(n5488)); - IV2 U5953 ( .A(pi114), .Z(n5322)); - AN2 U5954 ( .A(n6120), .B(n6121), .Z(n5467)); - OR2 U5955 ( .A(pi114), .B(n4885), .Z(n6120)); - AN2 U5956 ( .A(pi192), .B(n6122), .Z(n6113)); - OR2 U5957 ( .A(n6123), .B(n6124), .Z(n6122)); - AN2 U5958 ( .A(pi148), .B(n4881), .Z(n6124)); - AN2 U5959 ( .A(n4475), .B(n6125), .Z(n6123)); - OR2 U5960 ( .A(n5466), .B(n6126), .Z(n6125)); - IV2 U5961 ( .A(n5491), .Z(n6126)); - OR2 U5962 ( .A(po102), .B(n3901), .Z(n5491)); - IV2 U5963 ( .A(pi069), .Z(n3901)); - AN2 U5964 ( .A(n6127), .B(n6128), .Z(n5466)); - OR2 U5965 ( .A(pi069), .B(n4885), .Z(n6127)); - AN2 U5966 ( .A(n5461), .B(n4475), .Z(n6112)); - AN2 U5967 ( .A(n4087), .B(n6129), .Z(n5461)); - AN2 U5968 ( .A(n6130), .B(n4341), .Z(n6129)); - IV2 U5969 ( .A(n5474), .Z(n6130)); - AN2 U5970 ( .A(n6131), .B(po102), .Z(n5474)); - AN2 U5971 ( .A(n4334), .B(n4333), .Z(n4087)); - OR2 U5972 ( .A(n6132), .B(n4656), .Z(n4334)); - OR2 U5973 ( .A(n6133), .B(n6134), .Z(n4656)); - AN2 U5974 ( .A(n5074), .B(n3083), .Z(n6133)); - AN2 U5975 ( .A(n6135), .B(n3083), .Z(n6132)); - AN2 U5976 ( .A(n3018), .B(n4326), .Z(n6135)); - OR2 U5977 ( .A(n6136), .B(n5077), .Z(n4326)); - OR2 U5978 ( .A(n6137), .B(n3100), .Z(n5077)); - AN2 U5979 ( .A(n3280), .B(n4666), .Z(n6137)); - OR2 U5980 ( .A(n3286), .B(n6138), .Z(n4666)); - AN2 U5981 ( .A(n5829), .B(n3049), .Z(n3280)); - AN2 U5982 ( .A(n6139), .B(n3284), .Z(n6136)); - OR2 U5983 ( .A(n3049), .B(n5829), .Z(n3284)); - OR2 U5984 ( .A(n6140), .B(n3287), .Z(n6139)); - OR2 U5985 ( .A(n6141), .B(n6142), .Z(n3287)); - AN2 U5986 ( .A(pi141), .B(n3173), .Z(n6141)); - AN2 U5987 ( .A(n6143), .B(n3286), .Z(n6140)); - OR2 U5988 ( .A(n3173), .B(n3064), .Z(n6143)); - OR2 U5989 ( .A(n6144), .B(n6145), .Z(po000)); - AN2 U5990 ( .A(n6146), .B(po103), .Z(n6145)); - OR2 U5991 ( .A(n6147), .B(n6148), .Z(n6146)); - AN2 U5992 ( .A(n6149), .B(n3326), .Z(n6148)); - AN2 U5993 ( .A(n4217), .B(n3320), .Z(n6147)); - AN2 U5994 ( .A(n6150), .B(n3265), .Z(n6144)); - IV2 U5995 ( .A(po103), .Z(n3265)); - OR2 U5996 ( .A(n6151), .B(n6152), .Z(n6150)); - AN2 U5997 ( .A(n6149), .B(n3320), .Z(n6152)); - OR2 U5998 ( .A(n4406), .B(n4192), .Z(n3320)); - IV2 U5999 ( .A(n4205), .Z(n4192)); - AN2 U6000 ( .A(n4242), .B(n4331), .Z(n4406)); - IV2 U6001 ( .A(n4330), .Z(n4331)); - AN2 U6002 ( .A(n4217), .B(n3326), .Z(n6151)); - OR2 U6003 ( .A(n6153), .B(n4239), .Z(n3326)); - IV2 U6004 ( .A(n4242), .Z(n4239)); - OR2 U6005 ( .A(po028), .B(n6154), .Z(n4242)); - AN2 U6006 ( .A(n6155), .B(n6156), .Z(n6154)); - OR2 U6007 ( .A(n3321), .B(n3969), .Z(n6156)); - IV2 U6008 ( .A(pi169), .Z(n3969)); - AN2 U6009 ( .A(n4330), .B(n4205), .Z(n6153)); - OR2 U6010 ( .A(n6157), .B(n5056), .Z(n4205)); - IV2 U6011 ( .A(po028), .Z(n5056)); - AN2 U6012 ( .A(n3261), .B(n6158), .Z(n6157)); - OR2 U6013 ( .A(pi169), .B(n2837), .Z(n6158)); - OR2 U6014 ( .A(n6159), .B(n6160), .Z(n4330)); - OR2 U6015 ( .A(n6161), .B(n5930), .Z(n6160)); - OR2 U6016 ( .A(n6162), .B(n6163), .Z(n5930)); - OR2 U6017 ( .A(n6164), .B(n6165), .Z(n6163)); - AN2 U6018 ( .A(n3393), .B(n6166), .Z(n6165)); - OR2 U6019 ( .A(n6167), .B(n5853), .Z(n6166)); - AN2 U6020 ( .A(n6168), .B(n3371), .Z(n6167)); - IV2 U6021 ( .A(n3412), .Z(n3371)); - AN2 U6022 ( .A(n5999), .B(n6053), .Z(n6164)); - AN2 U6023 ( .A(n3453), .B(n3363), .Z(n5999)); - AN2 U6024 ( .A(n3926), .B(n4975), .Z(n6162)); - AN2 U6025 ( .A(n3940), .B(n4975), .Z(n6161)); - OR2 U6026 ( .A(n6169), .B(n6170), .Z(n6159)); - AN2 U6027 ( .A(n5931), .B(n6171), .Z(n6170)); - OR2 U6028 ( .A(n6172), .B(n6173), .Z(n6171)); - OR2 U6029 ( .A(n6174), .B(n6175), .Z(n6173)); - AN2 U6030 ( .A(n5888), .B(n3363), .Z(n6175)); - OR2 U6031 ( .A(n6176), .B(n6177), .Z(n5888)); - OR2 U6032 ( .A(n3248), .B(n6178), .Z(n6177)); - AN2 U6033 ( .A(n5833), .B(n3250), .Z(n6178)); - AN2 U6034 ( .A(n4937), .B(n6179), .Z(n5833)); - OR2 U6035 ( .A(n6180), .B(n6181), .Z(n6176)); - AN2 U6036 ( .A(n3495), .B(n5835), .Z(n6181)); - OR2 U6037 ( .A(n6182), .B(n5894), .Z(n5835)); - AN2 U6038 ( .A(n5966), .B(n6183), .Z(n6182)); - OR2 U6039 ( .A(n6184), .B(n6185), .Z(n5966)); - AN2 U6040 ( .A(pi171), .B(pi192), .Z(n6185)); - AN2 U6041 ( .A(pi142), .B(n2837), .Z(n6184)); - AN2 U6042 ( .A(n6186), .B(n5836), .Z(n6180)); - OR2 U6043 ( .A(n6187), .B(n6188), .Z(n5836)); - AN2 U6044 ( .A(n3705), .B(n5843), .Z(n6188)); - AN2 U6045 ( .A(pi192), .B(pi098), .Z(n3705)); - AN2 U6046 ( .A(n3717), .B(n6189), .Z(n6187)); - AN2 U6047 ( .A(n2837), .B(pi003), .Z(n3717)); - AN2 U6048 ( .A(n5889), .B(n3534), .Z(n6174)); - AN2 U6049 ( .A(n3261), .B(pi060), .Z(n3534)); - AN2 U6050 ( .A(pi192), .B(n6190), .Z(n5889)); - OR2 U6051 ( .A(n6191), .B(n6192), .Z(n6190)); - OR2 U6052 ( .A(n6193), .B(n6194), .Z(n6192)); - AN2 U6053 ( .A(pi004), .B(n4947), .Z(n6194)); - AN2 U6054 ( .A(n3640), .B(n3250), .Z(n6193)); - IV2 U6055 ( .A(n3344), .Z(n3250)); - IV2 U6056 ( .A(n3632), .Z(n3640)); - OR2 U6057 ( .A(po001), .B(n3998), .Z(n3632)); - OR2 U6058 ( .A(n6195), .B(n6196), .Z(n6191)); - AN2 U6059 ( .A(n6197), .B(n3495), .Z(n6196)); - AN2 U6060 ( .A(pi171), .B(n6183), .Z(n6197)); - AN2 U6061 ( .A(n6198), .B(n6186), .Z(n6195)); - IV2 U6062 ( .A(n6199), .Z(n6186)); - AN2 U6063 ( .A(pi098), .B(n5843), .Z(n6198)); - OR2 U6064 ( .A(pi171), .B(n4441), .Z(n5843)); - OR2 U6065 ( .A(n5892), .B(n6200), .Z(n6172)); - AN2 U6066 ( .A(n6201), .B(n5894), .Z(n6200)); - AN2 U6067 ( .A(n4441), .B(n4417), .Z(n5894)); - AN2 U6068 ( .A(n3495), .B(n3453), .Z(n6201)); - IV2 U6069 ( .A(n3451), .Z(n3453)); - OR2 U6070 ( .A(n3533), .B(n3321), .Z(n3451)); - IV2 U6071 ( .A(n3477), .Z(n3533)); - OR2 U6072 ( .A(pi060), .B(n2837), .Z(n3477)); - IV2 U6073 ( .A(n6202), .Z(n3495)); - IV2 U6074 ( .A(n6203), .Z(n5892)); - OR2 U6075 ( .A(n6204), .B(n6155), .Z(n6203)); - AN2 U6076 ( .A(n6205), .B(n6206), .Z(n6204)); - AN2 U6077 ( .A(n6207), .B(n6208), .Z(n6206)); - OR2 U6078 ( .A(n6199), .B(n6209), .Z(n6208)); - OR2 U6079 ( .A(n3244), .B(n3597), .Z(n6209)); - IV2 U6080 ( .A(pi003), .Z(n3597)); - IV2 U6081 ( .A(n6189), .Z(n3244)); - OR2 U6082 ( .A(pi142), .B(n4441), .Z(n6189)); - OR2 U6083 ( .A(n4418), .B(n6202), .Z(n6199)); - IV2 U6084 ( .A(n4426), .Z(n4418)); - OR2 U6085 ( .A(n3688), .B(n3290), .Z(n4426)); - IV2 U6086 ( .A(po011), .Z(n3688)); - OR2 U6087 ( .A(n6202), .B(n6210), .Z(n6207)); - OR2 U6088 ( .A(n4430), .B(n4440), .Z(n6210)); - IV2 U6089 ( .A(pi142), .Z(n4440)); - IV2 U6090 ( .A(n6183), .Z(n4430)); - OR2 U6091 ( .A(n4417), .B(n4441), .Z(n6183)); - IV2 U6092 ( .A(po036), .Z(n4441)); - IV2 U6093 ( .A(n3236), .Z(n4417)); - OR2 U6094 ( .A(n3234), .B(po011), .Z(n3236)); - IV2 U6095 ( .A(n3290), .Z(n3234)); - OR2 U6096 ( .A(n6211), .B(n6212), .Z(n3290)); - OR2 U6097 ( .A(n6213), .B(n6214), .Z(n6212)); - OR2 U6098 ( .A(n6215), .B(n6216), .Z(n6214)); - AN2 U6099 ( .A(pi192), .B(n5980), .Z(n6216)); - OR2 U6100 ( .A(n6217), .B(n6218), .Z(n5980)); - OR2 U6101 ( .A(n6219), .B(n6220), .Z(n6218)); - AN2 U6102 ( .A(pi045), .B(n4915), .Z(n6220)); - AN2 U6103 ( .A(n4621), .B(n4751), .Z(n6219)); - IV2 U6104 ( .A(n4465), .Z(n4621)); - OR2 U6105 ( .A(po014), .B(n3908), .Z(n4465)); - IV2 U6106 ( .A(pi079), .Z(n3908)); - OR2 U6107 ( .A(n6221), .B(n6222), .Z(n6217)); - AN2 U6108 ( .A(n6223), .B(n3757), .Z(n6222)); - AN2 U6109 ( .A(pi158), .B(n4628), .Z(n6223)); - AN2 U6110 ( .A(n6224), .B(n6225), .Z(n6221)); - AN2 U6111 ( .A(pi175), .B(n5037), .Z(n6224)); - AN2 U6112 ( .A(n6008), .B(n2837), .Z(n6215)); - OR2 U6113 ( .A(n6226), .B(n6227), .Z(n6008)); - OR2 U6114 ( .A(n6228), .B(n6229), .Z(n6227)); - AN2 U6115 ( .A(pi095), .B(n4915), .Z(n6229)); - AN2 U6116 ( .A(n4623), .B(n4751), .Z(n6228)); - IV2 U6117 ( .A(n4469), .Z(n4623)); - OR2 U6118 ( .A(po014), .B(n4648), .Z(n4469)); - IV2 U6119 ( .A(pi156), .Z(n4648)); - OR2 U6120 ( .A(n6230), .B(n6231), .Z(n6226)); - AN2 U6121 ( .A(n6232), .B(n3757), .Z(n6231)); - AN2 U6122 ( .A(pi151), .B(n4628), .Z(n6232)); - AN2 U6123 ( .A(n6233), .B(n6225), .Z(n6230)); - AN2 U6124 ( .A(pi185), .B(n5037), .Z(n6233)); - AN2 U6125 ( .A(n5985), .B(n6234), .Z(n6213)); - OR2 U6126 ( .A(n6235), .B(n6236), .Z(n6234)); - OR2 U6127 ( .A(n6237), .B(n6238), .Z(n6236)); - OR2 U6128 ( .A(n6239), .B(n6240), .Z(n6238)); - AN2 U6129 ( .A(n6241), .B(n3055), .Z(n6240)); - AN2 U6130 ( .A(n5822), .B(n3119), .Z(n6241)); - OR2 U6131 ( .A(n6242), .B(n6016), .Z(n3119)); - AN2 U6132 ( .A(pi141), .B(po099), .Z(n6242)); - AN2 U6133 ( .A(n5994), .B(n6243), .Z(n6239)); - AN2 U6134 ( .A(n6244), .B(n3049), .Z(n6237)); - OR2 U6135 ( .A(n6243), .B(n6245), .Z(n6244)); - OR2 U6136 ( .A(n6020), .B(n6246), .Z(n6245)); - AN2 U6137 ( .A(n6247), .B(n5826), .Z(n6246)); - AN2 U6138 ( .A(n3106), .B(n5829), .Z(n5826)); - OR2 U6139 ( .A(n5994), .B(n5822), .Z(n5829)); - IV2 U6140 ( .A(pi166), .Z(n3106)); - AN2 U6141 ( .A(n3063), .B(pi192), .Z(n6247)); - AN2 U6142 ( .A(n6016), .B(n5994), .Z(n6020)); - AN2 U6143 ( .A(n3286), .B(n3177), .Z(n6016)); - OR2 U6144 ( .A(n6142), .B(n6248), .Z(n6243)); - AN2 U6145 ( .A(n3207), .B(n3286), .Z(n6248)); - OR2 U6146 ( .A(n6249), .B(n6250), .Z(n3207)); - AN2 U6147 ( .A(n3064), .B(n3171), .Z(n6250)); - AN2 U6148 ( .A(n3173), .B(n3177), .Z(n6249)); - IV2 U6149 ( .A(pi141), .Z(n3177)); - AN2 U6150 ( .A(pi033), .B(n3064), .Z(n6142)); - OR2 U6151 ( .A(n6251), .B(n6252), .Z(n6235)); - OR2 U6152 ( .A(n6044), .B(n3100), .Z(n6252)); - AN2 U6153 ( .A(n3286), .B(n6138), .Z(n3100)); - OR2 U6154 ( .A(n6253), .B(n6254), .Z(n6138)); - AN2 U6155 ( .A(pi033), .B(pi192), .Z(n6254)); - AN2 U6156 ( .A(pi141), .B(n2837), .Z(n6253)); - AN2 U6157 ( .A(n6255), .B(pi141), .Z(n6044)); - OR2 U6158 ( .A(n3071), .B(n6256), .Z(n6255)); - AN2 U6159 ( .A(n3055), .B(n5994), .Z(n6256)); - IV2 U6160 ( .A(n6257), .Z(n5994)); - OR2 U6161 ( .A(n2925), .B(n5099), .Z(n6257)); - OR2 U6162 ( .A(n6258), .B(n6259), .Z(n5099)); - OR2 U6163 ( .A(n3146), .B(n6260), .Z(n6259)); - OR2 U6164 ( .A(n6261), .B(n6262), .Z(n6260)); - AN2 U6165 ( .A(n2845), .B(n2837), .Z(n6262)); - IV2 U6166 ( .A(n2846), .Z(n2845)); - AN2 U6167 ( .A(n6263), .B(n6264), .Z(n2846)); - OR2 U6168 ( .A(n3141), .B(po044), .Z(n6263)); - IV2 U6169 ( .A(pi201), .Z(n3141)); - AN2 U6170 ( .A(pi192), .B(n2833), .Z(n6261)); - IV2 U6171 ( .A(n2834), .Z(n2833)); - AN2 U6172 ( .A(n6265), .B(n6266), .Z(n2834)); - OR2 U6173 ( .A(n3136), .B(po044), .Z(n6265)); - IV2 U6174 ( .A(pi088), .Z(n3136)); - OR2 U6175 ( .A(n6267), .B(n6268), .Z(n3146)); - AN2 U6176 ( .A(n2880), .B(pi192), .Z(n6268)); - IV2 U6177 ( .A(n2878), .Z(n2880)); - OR2 U6178 ( .A(pi077), .B(n2962), .Z(n2878)); - AN2 U6179 ( .A(n2978), .B(n2837), .Z(n6267)); - IV2 U6180 ( .A(n2939), .Z(n2978)); - OR2 U6181 ( .A(n2998), .B(n6269), .Z(n6258)); - OR2 U6182 ( .A(n2901), .B(n2862), .Z(n6269)); - IV2 U6183 ( .A(pi200), .Z(n2901)); - IV2 U6184 ( .A(n3003), .Z(n2925)); - OR2 U6185 ( .A(pi192), .B(n2960), .Z(n3003)); - IV2 U6186 ( .A(n6270), .Z(n2960)); - OR2 U6187 ( .A(n6271), .B(n6272), .Z(n6270)); - AN2 U6188 ( .A(pi081), .B(n2931), .Z(n6272)); - IV2 U6189 ( .A(po107), .Z(n2931)); - AN2 U6190 ( .A(po107), .B(n2982), .Z(n6271)); - AN2 U6191 ( .A(n2837), .B(n6017), .Z(n3055)); - IV2 U6192 ( .A(n5828), .Z(n6017)); - OR2 U6193 ( .A(n6273), .B(n6015), .Z(n5828)); - AN2 U6194 ( .A(pi174), .B(n3049), .Z(n6015)); - AN2 U6195 ( .A(po010), .B(n5115), .Z(n6273)); - IV2 U6196 ( .A(pi174), .Z(n5115)); - AN2 U6197 ( .A(n3049), .B(n3173), .Z(n3071)); - AN2 U6198 ( .A(n2837), .B(pi174), .Z(n3173)); - IV2 U6199 ( .A(po010), .Z(n3049)); - AN2 U6200 ( .A(n6274), .B(n3063), .Z(n6251)); - IV2 U6201 ( .A(n6275), .Z(n3063)); - OR2 U6202 ( .A(n6276), .B(n6277), .Z(n6275)); - AN2 U6203 ( .A(pi033), .B(n3286), .Z(n6277)); - IV2 U6204 ( .A(po099), .Z(n3286)); - AN2 U6205 ( .A(po099), .B(n3171), .Z(n6276)); - IV2 U6206 ( .A(pi033), .Z(n3171)); - AN2 U6207 ( .A(n3064), .B(n5822), .Z(n6274)); - OR2 U6208 ( .A(n6278), .B(n6279), .Z(n5822)); - OR2 U6209 ( .A(n6280), .B(n6281), .Z(n6279)); - AN2 U6210 ( .A(n6282), .B(pi192), .Z(n6281)); - AN2 U6211 ( .A(n5156), .B(n6266), .Z(n6282)); - OR2 U6212 ( .A(pi088), .B(n5000), .Z(n6266)); - OR2 U6213 ( .A(n6283), .B(n5153), .Z(n5156)); - AN2 U6214 ( .A(n2861), .B(n6284), .Z(n6283)); - OR2 U6215 ( .A(n2885), .B(n2892), .Z(n6284)); - AN2 U6216 ( .A(n5008), .B(pi157), .Z(n2892)); - AN2 U6217 ( .A(n2930), .B(n2876), .Z(n2885)); - IV2 U6218 ( .A(n2887), .Z(n2876)); - OR2 U6219 ( .A(po031), .B(n3846), .Z(n2887)); - IV2 U6220 ( .A(pi077), .Z(n3846)); - AN2 U6221 ( .A(n6285), .B(n2837), .Z(n6280)); - AN2 U6222 ( .A(n5175), .B(n6264), .Z(n6285)); - OR2 U6223 ( .A(pi201), .B(n5000), .Z(n6264)); - OR2 U6224 ( .A(n6286), .B(n6287), .Z(n5175)); - AN2 U6225 ( .A(n2861), .B(n6288), .Z(n6286)); - OR2 U6226 ( .A(n6289), .B(n2929), .Z(n6288)); - IV2 U6227 ( .A(n2947), .Z(n2929)); - OR2 U6228 ( .A(po106), .B(n5431), .Z(n2947)); - IV2 U6229 ( .A(pi206), .Z(n5431)); - AN2 U6230 ( .A(n2930), .B(n4113), .Z(n6289)); - OR2 U6231 ( .A(n2919), .B(n2936), .Z(n4113)); - IV2 U6232 ( .A(n2946), .Z(n2936)); - OR2 U6233 ( .A(po031), .B(n2957), .Z(n2946)); - IV2 U6234 ( .A(pi082), .Z(n2957)); - AN2 U6235 ( .A(n2902), .B(n2939), .Z(n2919)); - OR2 U6236 ( .A(pi082), .B(n2962), .Z(n2939)); - IV2 U6237 ( .A(po031), .Z(n2962)); - IV2 U6238 ( .A(n2974), .Z(n2902)); - OR2 U6239 ( .A(po107), .B(n2982), .Z(n2974)); - IV2 U6240 ( .A(pi081), .Z(n2982)); - IV2 U6241 ( .A(n2862), .Z(n2930)); - OR2 U6242 ( .A(n6290), .B(n6291), .Z(n2862)); - AN2 U6243 ( .A(n6292), .B(n5008), .Z(n6291)); - IV2 U6244 ( .A(po106), .Z(n5008)); - AN2 U6245 ( .A(n6293), .B(po106), .Z(n6290)); - IV2 U6246 ( .A(n6292), .Z(n6293)); - OR2 U6247 ( .A(n6294), .B(n6295), .Z(n6292)); - AN2 U6248 ( .A(pi192), .B(pi157), .Z(n6295)); - AN2 U6249 ( .A(pi206), .B(n2837), .Z(n6294)); - IV2 U6250 ( .A(n2998), .Z(n2861)); - OR2 U6251 ( .A(n6296), .B(n6297), .Z(n2998)); - OR2 U6252 ( .A(n6298), .B(n6299), .Z(n6297)); - AN2 U6253 ( .A(n5153), .B(pi192), .Z(n6299)); - AN2 U6254 ( .A(n5004), .B(pi026), .Z(n5153)); - IV2 U6255 ( .A(po079), .Z(n5004)); - AN2 U6256 ( .A(n6287), .B(n2837), .Z(n6298)); - IV2 U6257 ( .A(n5172), .Z(n6287)); - OR2 U6258 ( .A(po079), .B(n5165), .Z(n5172)); - AN2 U6259 ( .A(po079), .B(n6027), .Z(n6296)); - OR2 U6260 ( .A(n6300), .B(n6301), .Z(n6027)); - AN2 U6261 ( .A(pi192), .B(n3847), .Z(n6301)); - IV2 U6262 ( .A(pi026), .Z(n3847)); - AN2 U6263 ( .A(n5165), .B(n2837), .Z(n6300)); - IV2 U6264 ( .A(pi107), .Z(n5165)); - AN2 U6265 ( .A(n3011), .B(n5000), .Z(n6278)); - IV2 U6266 ( .A(po044), .Z(n5000)); - OR2 U6267 ( .A(n6302), .B(n6303), .Z(n3011)); - AN2 U6268 ( .A(pi088), .B(pi192), .Z(n6303)); - AN2 U6269 ( .A(pi201), .B(n2837), .Z(n6302)); - AN2 U6270 ( .A(pi192), .B(pi166), .Z(n3064)); - AN2 U6271 ( .A(n3018), .B(n5984), .Z(n5985)); - AN2 U6272 ( .A(n6304), .B(n5104), .Z(n3018)); - IV2 U6273 ( .A(n5074), .Z(n5104)); - OR2 U6274 ( .A(n6305), .B(n5040), .Z(n6304)); - OR2 U6275 ( .A(n6306), .B(n6307), .Z(n6211)); - OR2 U6276 ( .A(n6308), .B(n6309), .Z(n6307)); - AN2 U6277 ( .A(n4624), .B(n5981), .Z(n6309)); - AN2 U6278 ( .A(n3300), .B(n3305), .Z(n4624)); - AN2 U6279 ( .A(n5984), .B(n5074), .Z(n6308)); - AN2 U6280 ( .A(n5040), .B(n6305), .Z(n5074)); - OR2 U6281 ( .A(n6310), .B(n6311), .Z(n6305)); - AN2 U6282 ( .A(pi096), .B(pi192), .Z(n6311)); - AN2 U6283 ( .A(pi128), .B(n2837), .Z(n6310)); - IV2 U6284 ( .A(po070), .Z(n5040)); - AN2 U6285 ( .A(n3083), .B(n6225), .Z(n5984)); - AN2 U6286 ( .A(n6312), .B(n6313), .Z(n6225)); - AN2 U6287 ( .A(n3760), .B(n4341), .Z(n6313)); - AN2 U6288 ( .A(n4333), .B(n4482), .Z(n6312)); - OR2 U6289 ( .A(n6314), .B(n6315), .Z(n4333)); - AN2 U6290 ( .A(po025), .B(n6316), .Z(n6315)); - OR2 U6291 ( .A(n6317), .B(n3888), .Z(n6316)); - AN2 U6292 ( .A(pi192), .B(pi191), .Z(n3888)); - AN2 U6293 ( .A(pi076), .B(n2837), .Z(n6317)); - AN2 U6294 ( .A(n3781), .B(n4557), .Z(n6314)); - OR2 U6295 ( .A(n4538), .B(n3890), .Z(n3781)); - IV2 U6296 ( .A(n6318), .Z(n3890)); - OR2 U6297 ( .A(pi191), .B(n2837), .Z(n6318)); - AN2 U6298 ( .A(n4077), .B(n2837), .Z(n4538)); - IV2 U6299 ( .A(n3021), .Z(n3083)); - OR2 U6300 ( .A(n6319), .B(n6134), .Z(n3021)); - AN2 U6301 ( .A(n6320), .B(n5037), .Z(n6134)); - IV2 U6302 ( .A(po035), .Z(n5037)); - AN2 U6303 ( .A(n6321), .B(po035), .Z(n6319)); - IV2 U6304 ( .A(n6320), .Z(n6321)); - OR2 U6305 ( .A(n6322), .B(n6323), .Z(n6320)); - AN2 U6306 ( .A(pi175), .B(pi192), .Z(n6323)); - AN2 U6307 ( .A(pi185), .B(n2837), .Z(n6322)); - AN2 U6308 ( .A(n3760), .B(n6324), .Z(n6306)); - OR2 U6309 ( .A(n6325), .B(n6326), .Z(n6324)); - OR2 U6310 ( .A(n6327), .B(n6328), .Z(n6326)); - AN2 U6311 ( .A(n4482), .B(n4340), .Z(n6328)); - OR2 U6312 ( .A(n6329), .B(n6330), .Z(n4340)); - AN2 U6313 ( .A(n6121), .B(n2837), .Z(n6330)); - OR2 U6314 ( .A(n6331), .B(n4567), .Z(n6121)); - IV2 U6315 ( .A(n4578), .Z(n4567)); - OR2 U6316 ( .A(po024), .B(n4358), .Z(n4578)); - AN2 U6317 ( .A(n4084), .B(n4066), .Z(n6331)); - OR2 U6318 ( .A(n6332), .B(n4539), .Z(n4084)); - IV2 U6319 ( .A(n5503), .Z(n4539)); - OR2 U6320 ( .A(po059), .B(n4074), .Z(n5503)); - IV2 U6321 ( .A(pi170), .Z(n4074)); - AN2 U6322 ( .A(n4576), .B(n3778), .Z(n6332)); - IV2 U6323 ( .A(n4580), .Z(n4576)); - OR2 U6324 ( .A(po025), .B(n4077), .Z(n4580)); - IV2 U6325 ( .A(pi076), .Z(n4077)); - AN2 U6326 ( .A(pi192), .B(n6128), .Z(n6329)); - OR2 U6327 ( .A(n6333), .B(n6334), .Z(n6128)); - OR2 U6328 ( .A(n4561), .B(n6335), .Z(n6334)); - AN2 U6329 ( .A(n6336), .B(n4341), .Z(n6335)); - AN2 U6330 ( .A(n4066), .B(n3778), .Z(n4341)); - IV2 U6331 ( .A(n3773), .Z(n3778)); - OR2 U6332 ( .A(n6337), .B(n6338), .Z(n3773)); - AN2 U6333 ( .A(n6339), .B(n4877), .Z(n6338)); - IV2 U6334 ( .A(po059), .Z(n4877)); - AN2 U6335 ( .A(n6340), .B(po059), .Z(n6337)); - IV2 U6336 ( .A(n6339), .Z(n6340)); - OR2 U6337 ( .A(n6341), .B(n6342), .Z(n6339)); - AN2 U6338 ( .A(pi135), .B(pi192), .Z(n6342)); - AN2 U6339 ( .A(pi170), .B(n2837), .Z(n6341)); - AN2 U6340 ( .A(pi191), .B(n4557), .Z(n6336)); - IV2 U6341 ( .A(po025), .Z(n4557)); - IV2 U6342 ( .A(n4348), .Z(n4561)); - OR2 U6343 ( .A(po024), .B(n3896), .Z(n4348)); - AN2 U6344 ( .A(n4085), .B(n4066), .Z(n6333)); - OR2 U6345 ( .A(n6343), .B(n6344), .Z(n4066)); - OR2 U6346 ( .A(n6345), .B(n6346), .Z(n6344)); - AN2 U6347 ( .A(n6347), .B(po024), .Z(n6346)); - AN2 U6348 ( .A(pi005), .B(pi192), .Z(n6347)); - AN2 U6349 ( .A(n6348), .B(n4874), .Z(n6345)); - IV2 U6350 ( .A(po024), .Z(n4874)); - OR2 U6351 ( .A(n6349), .B(n5483), .Z(n6348)); - AN2 U6352 ( .A(pi192), .B(n3896), .Z(n5483)); - IV2 U6353 ( .A(pi005), .Z(n3896)); - AN2 U6354 ( .A(n4358), .B(n2837), .Z(n6349)); - IV2 U6355 ( .A(pi160), .Z(n4358)); - AN2 U6356 ( .A(pi160), .B(n5477), .Z(n6343)); - AN2 U6357 ( .A(n2837), .B(po024), .Z(n5477)); - IV2 U6358 ( .A(n4353), .Z(n4085)); - OR2 U6359 ( .A(po059), .B(n3880), .Z(n4353)); - IV2 U6360 ( .A(pi135), .Z(n3880)); - AN2 U6361 ( .A(n4342), .B(n4475), .Z(n4482)); - AN2 U6362 ( .A(n6350), .B(n6351), .Z(n4342)); - OR2 U6363 ( .A(n6131), .B(po102), .Z(n6351)); - IV2 U6364 ( .A(n6352), .Z(n6131)); - OR2 U6365 ( .A(n6352), .B(n4885), .Z(n6350)); - AN2 U6366 ( .A(n5462), .B(n4475), .Z(n6327)); - IV2 U6367 ( .A(n4478), .Z(n4475)); - OR2 U6368 ( .A(n6353), .B(n6325), .Z(n4478)); - AN2 U6369 ( .A(n6354), .B(po072), .Z(n6353)); - IV2 U6370 ( .A(n6355), .Z(n6354)); - AN2 U6371 ( .A(n6352), .B(n4885), .Z(n5462)); - IV2 U6372 ( .A(po102), .Z(n4885)); - OR2 U6373 ( .A(n6356), .B(n6357), .Z(n6352)); - AN2 U6374 ( .A(pi069), .B(pi192), .Z(n6357)); - AN2 U6375 ( .A(pi114), .B(n2837), .Z(n6356)); - AN2 U6376 ( .A(n6355), .B(n4881), .Z(n6325)); - IV2 U6377 ( .A(po072), .Z(n4881)); - OR2 U6378 ( .A(n6358), .B(n6359), .Z(n6355)); - AN2 U6379 ( .A(pi148), .B(pi192), .Z(n6359)); - AN2 U6380 ( .A(pi108), .B(n2837), .Z(n6358)); - AN2 U6381 ( .A(n4450), .B(n5981), .Z(n3760)); - AN2 U6382 ( .A(n3301), .B(n4751), .Z(n5981)); - AN2 U6383 ( .A(n4006), .B(n3757), .Z(n4751)); - IV2 U6384 ( .A(n4444), .Z(n3757)); - OR2 U6385 ( .A(n6360), .B(n3754), .Z(n4444)); - AN2 U6386 ( .A(n6361), .B(n4915), .Z(n3754)); - IV2 U6387 ( .A(po063), .Z(n4915)); - AN2 U6388 ( .A(n6362), .B(po063), .Z(n6360)); - IV2 U6389 ( .A(n6361), .Z(n6362)); - OR2 U6390 ( .A(n6363), .B(n6364), .Z(n6361)); - AN2 U6391 ( .A(pi045), .B(pi192), .Z(n6364)); - AN2 U6392 ( .A(pi095), .B(n2837), .Z(n6363)); - AN2 U6393 ( .A(n6365), .B(n6366), .Z(n4006)); - OR2 U6394 ( .A(n6367), .B(po092), .Z(n6366)); - IV2 U6395 ( .A(n4752), .Z(n6367)); - OR2 U6396 ( .A(n4752), .B(n4628), .Z(n6365)); - IV2 U6397 ( .A(po092), .Z(n4628)); - OR2 U6398 ( .A(n6368), .B(n6369), .Z(n4752)); - AN2 U6399 ( .A(pi158), .B(pi192), .Z(n6369)); - AN2 U6400 ( .A(pi151), .B(n2837), .Z(n6368)); - IV2 U6401 ( .A(n3295), .Z(n3301)); - OR2 U6402 ( .A(n6370), .B(n6371), .Z(n3295)); - AN2 U6403 ( .A(n4703), .B(n4861), .Z(n6371)); - IV2 U6404 ( .A(po014), .Z(n4861)); - AN2 U6405 ( .A(n4736), .B(po014), .Z(n6370)); - IV2 U6406 ( .A(n4703), .Z(n4736)); - OR2 U6407 ( .A(n6372), .B(n6373), .Z(n4703)); - AN2 U6408 ( .A(pi079), .B(pi192), .Z(n6373)); - AN2 U6409 ( .A(pi156), .B(n2837), .Z(n6372)); - IV2 U6410 ( .A(n4606), .Z(n4450)); - AN2 U6411 ( .A(n6374), .B(n6375), .Z(n4606)); - OR2 U6412 ( .A(n3305), .B(po039), .Z(n6375)); - OR2 U6413 ( .A(n3300), .B(n6376), .Z(n6374)); - IV2 U6414 ( .A(n3305), .Z(n6376)); - OR2 U6415 ( .A(n4685), .B(n4692), .Z(n3305)); - AN2 U6416 ( .A(pi192), .B(pi016), .Z(n4692)); - AN2 U6417 ( .A(n2837), .B(pi040), .Z(n4685)); - IV2 U6418 ( .A(po039), .Z(n3300)); - OR2 U6419 ( .A(n3352), .B(n3344), .Z(n6202)); - AN2 U6420 ( .A(n6377), .B(n6378), .Z(n3352)); - OR2 U6421 ( .A(n6179), .B(po001), .Z(n6378)); - IV2 U6422 ( .A(n6379), .Z(n6179)); - OR2 U6423 ( .A(n6379), .B(n4937), .Z(n6377)); - IV2 U6424 ( .A(po001), .Z(n4937)); - OR2 U6425 ( .A(n5959), .B(n6380), .Z(n6379)); - AN2 U6426 ( .A(pi192), .B(n3998), .Z(n6380)); - IV2 U6427 ( .A(pi068), .Z(n3998)); - AN2 U6428 ( .A(n2837), .B(n5379), .Z(n5959)); - AN2 U6429 ( .A(n6381), .B(n6382), .Z(n6205)); - OR2 U6430 ( .A(n3344), .B(n3590), .Z(n6382)); - OR2 U6431 ( .A(po001), .B(n5379), .Z(n3590)); - IV2 U6432 ( .A(pi195), .Z(n5379)); - OR2 U6433 ( .A(n6383), .B(n3248), .Z(n3344)); - AN2 U6434 ( .A(n6384), .B(n4947), .Z(n3248)); - IV2 U6435 ( .A(po082), .Z(n4947)); - AN2 U6436 ( .A(n6385), .B(po082), .Z(n6383)); - IV2 U6437 ( .A(n6384), .Z(n6385)); - OR2 U6438 ( .A(n6386), .B(n6387), .Z(n6384)); - AN2 U6439 ( .A(pi004), .B(pi192), .Z(n6387)); - AN2 U6440 ( .A(pi130), .B(n2837), .Z(n6386)); - OR2 U6441 ( .A(po082), .B(n5372), .Z(n6381)); - IV2 U6442 ( .A(pi130), .Z(n5372)); - AN2 U6443 ( .A(n3225), .B(n6053), .Z(n5931)); - IV2 U6444 ( .A(n3247), .Z(n3225)); - OR2 U6445 ( .A(n6388), .B(n3490), .Z(n3247)); - AN2 U6446 ( .A(n4943), .B(n5895), .Z(n3490)); - OR2 U6447 ( .A(n3926), .B(n3989), .Z(n5895)); - IV2 U6448 ( .A(n6389), .Z(n6388)); - OR2 U6449 ( .A(n4943), .B(n6390), .Z(n6389)); - AN2 U6450 ( .A(n6391), .B(n3261), .Z(n6390)); - OR2 U6451 ( .A(n2837), .B(pi133), .Z(n6391)); - AN2 U6452 ( .A(n6392), .B(n6053), .Z(n6169)); - AN2 U6453 ( .A(n3393), .B(n6393), .Z(n6053)); - IV2 U6454 ( .A(n3461), .Z(n6393)); - OR2 U6455 ( .A(n3401), .B(n3412), .Z(n3461)); - OR2 U6456 ( .A(n6394), .B(n5853), .Z(n3412)); - OR2 U6457 ( .A(n3466), .B(n3392), .Z(n5853)); - AN2 U6458 ( .A(n3380), .B(n3926), .Z(n3392)); - IV2 U6459 ( .A(po071), .Z(n3380)); - AN2 U6460 ( .A(n3261), .B(n3381), .Z(n3466)); - IV2 U6461 ( .A(n3399), .Z(n3381)); - OR2 U6462 ( .A(po071), .B(n3913), .Z(n3399)); - AN2 U6463 ( .A(po071), .B(n5878), .Z(n6394)); - OR2 U6464 ( .A(n3480), .B(n3321), .Z(n5878)); - AN2 U6465 ( .A(n3913), .B(pi192), .Z(n3480)); - IV2 U6466 ( .A(pi118), .Z(n3913)); - OR2 U6467 ( .A(n5881), .B(n6395), .Z(n3401)); - OR2 U6468 ( .A(n6168), .B(n6396), .Z(n6395)); - AN2 U6469 ( .A(po104), .B(n3321), .Z(n6396)); - AN2 U6470 ( .A(n3485), .B(n3261), .Z(n6168)); - IV2 U6471 ( .A(n3419), .Z(n3485)); - OR2 U6472 ( .A(n6397), .B(po104), .Z(n3419)); - AN2 U6473 ( .A(pi192), .B(n3942), .Z(n6397)); - IV2 U6474 ( .A(pi196), .Z(n3942)); - AN2 U6475 ( .A(pi192), .B(n5872), .Z(n5881)); - IV2 U6476 ( .A(n5866), .Z(n5872)); - OR2 U6477 ( .A(pi196), .B(n3512), .Z(n5866)); - IV2 U6478 ( .A(po104), .Z(n3512)); - OR2 U6479 ( .A(n6398), .B(n6399), .Z(n3393)); - AN2 U6480 ( .A(n6400), .B(n4975), .Z(n6399)); - IV2 U6481 ( .A(po038), .Z(n4975)); - OR2 U6482 ( .A(n6401), .B(n3321), .Z(n6400)); - AN2 U6483 ( .A(pi192), .B(n3943), .Z(n6401)); - IV2 U6484 ( .A(pi050), .Z(n3943)); - AN2 U6485 ( .A(po038), .B(n6402), .Z(n6398)); - OR2 U6486 ( .A(n3940), .B(n3926), .Z(n6402)); - AN2 U6487 ( .A(n3261), .B(pi050), .Z(n3940)); - AN2 U6488 ( .A(n6403), .B(n4943), .Z(n6392)); - IV2 U6489 ( .A(po057), .Z(n4943)); - OR2 U6490 ( .A(n6404), .B(n6052), .Z(n6403)); - OR2 U6491 ( .A(n6405), .B(n3926), .Z(n6052)); - IV2 U6492 ( .A(n6155), .Z(n3926)); - OR2 U6493 ( .A(pi192), .B(n3321), .Z(n6155)); - AN2 U6494 ( .A(pi060), .B(n3989), .Z(n6405)); - AN2 U6495 ( .A(n3989), .B(n3363), .Z(n6404)); - IV2 U6496 ( .A(po027), .Z(n3363)); - AN2 U6497 ( .A(n3261), .B(pi133), .Z(n3989)); - IV2 U6498 ( .A(n3321), .Z(n3261)); - IV2 U6499 ( .A(n6149), .Z(n4217)); - OR2 U6500 ( .A(n4148), .B(n3321), .Z(n6149)); - AN2 U6501 ( .A(pi161), .B(pi012), .Z(n3321)); - IV2 U6502 ( .A(n4247), .Z(n4148)); - OR2 U6503 ( .A(pi058), .B(n2837), .Z(n4247)); - IV2 U6504 ( .A(pi192), .Z(n2837)); - -endmodule - -module IV2(A, Z); - input A; - output Z; - - assign Z = ~A; -endmodule - -module AN2(A, B, Z); - input A, B; - output Z; - - assign Z = A & B; -endmodule - -module OR2(A, B, Z); - input A, B; - output Z; - - assign Z = A | B; -endmodule diff --git a/yosys/examples/smtbmc/glift/C7552.ys b/yosys/examples/smtbmc/glift/C7552.ys deleted file mode 100644 index a9a1f5dc26c..00000000000 --- a/yosys/examples/smtbmc/glift/C7552.ys +++ /dev/null @@ -1,41 +0,0 @@ -read_verilog C7552.v -techmap -flatten -select C7552_lev2 -glift -create-instrumented-model -techmap -opt -rename C7552_lev2 uut -cd .. -delete [AIONX][NVXR]2 -read_verilog C7552.v -techmap -flatten -select C7552_lev2 -glift -create-precise-model -techmap -opt -rename C7552_lev2 spec -cd .. -delete [AIONX][NVXR]2 - -design -push-copy -miter -equiv spec uut miter -flatten -delete uut spec -techmap -opt -stat miter -qbfsat -O2 -write-solution C7552.soln -solver yices -timeout 3600 -nocleanup -assume-outputs -assume-negative-polarity miter -design -pop -stat - -copy uut solved -qbfsat -specialize-from-file C7552.soln solved -opt solved -miter -equiv spec solved satmiter -flatten -sat -prove trigger 0 satmiter -delete satmiter -stat -shell diff --git a/yosys/examples/smtbmc/glift/C880.v b/yosys/examples/smtbmc/glift/C880.v deleted file mode 100755 index 20e665f4a91..00000000000 --- a/yosys/examples/smtbmc/glift/C880.v +++ /dev/null @@ -1,451 +0,0 @@ -module C880_lev2(pi00, pi01, pi02, pi03, pi04, pi05, pi06, pi07, pi08, pi09, - pi10, pi11, pi12, pi13, pi14, pi15, pi16, pi17, pi18, pi19, - pi20, pi21, pi22, pi23, pi24, pi25, pi26, pi27, pi28, pi29, - pi30, pi31, pi32, pi33, pi34, pi35, pi36, pi37, pi38, pi39, - pi40, pi41, pi42, pi43, pi44, pi45, pi46, pi47, pi48, pi49, - pi50, pi51, pi52, pi53, pi54, pi55, pi56, pi57, pi58, pi59, - po00, po01, po02, po03, po04, po05, po06, po07, po08, po09, - po10, po11, po12, po13, po14, po15, po16, po17, po18, po19, - po20, po21, po22, po23, po24, po25); - -input pi00, pi01, pi02, pi03, pi04, pi05, pi06, pi07, pi08, pi09, - pi10, pi11, pi12, pi13, pi14, pi15, pi16, pi17, pi18, pi19, - pi20, pi21, pi22, pi23, pi24, pi25, pi26, pi27, pi28, pi29, - pi30, pi31, pi32, pi33, pi34, pi35, pi36, pi37, pi38, pi39, - pi40, pi41, pi42, pi43, pi44, pi45, pi46, pi47, pi48, pi49, - pi50, pi51, pi52, pi53, pi54, pi55, pi56, pi57, pi58, pi59; - -output po00, po01, po02, po03, po04, po05, po06, po07, po08, po09, - po10, po11, po12, po13, po14, po15, po16, po17, po18, po19, - po20, po21, po22, po23, po24, po25; - -wire n137, n346, n364, n415, n295, n427, n351, n377, n454, n357, - n358, n359, n360, n361, n362, n363, n365, n366, n367, n368, - n369, n370, n371, n372, n373, n374, n375, n376, n378, n379, - n380, n381, n382, n383, n384, n385, n386, n387, n388, n389, - n390, n391, n392, n393, n394, n395, n396, n397, n398, n399, - n400, n401, n402, n403, n404, n405, n406, n407, n408, n409, - n410, n411, n412, n413, n414, n416, n417, n418, n419, n420, - n421, n422, n423, n424, n425, n426, n428, n429, n430, n431, - n432, n433, n434, n435, n436, n437, n438, n439, n440, n441, - n442, n443, n444, n445, n446, n447, n448, n449, n450, n451, - n452, n453, n455, n456, n457, n458, n459, n460, n461, n462, - n463, n464, n465, n466, n467, n468, n469, n470, n471, n472, - n473, n474, n475, n476, n477, n478, n479, n480, n481, n482, - n483, n484, n485, n486, n487, n488, n489, n490, n491, n492, - n493, n494, n495, n496, n497, n498, n499, n500, n501, n502, - n503, n504, n505, n506, n507, n508, n509, n510, n511, n512, - n513, n514, n515, n516, n517, n518, n519, n520, n521, n522, - n523, n524, n525, n526, n527, n528, n529, n530, n531, n532, - n533, n534, n535, n536, n537, n538, n539, n540, n541, n542, - n543, n544, n545, n546, n547, n548, n549, n550, n551, n552, - n553, n554, n555, n556, n557, n558, n559, n560, n561, n562, - n563, n564, n565, n566, n567, n568, n569, n570, n571, n572, - n573, n574, n575, n576, n577, n578, n579, n580, n581, n582, - n583, n584, n585, n586, n587, n588, n589, n590, n591, n592, - n593, n594, n595, n596, n597, n598, n599, n600, n601, n602, - n603, n604, n605, n606, n607, n608, n609, n610, n611, n612, - n613, n614, n615, n616, n617, n618, n619, n620, n621, n622, - n623, n624, n625, n626, n627, n628, n629, n630, n631, n632, - n633, n634, n635, n636, n637, n638, n639, n640, n641, n642, - n643, n644, n645, n646, n647, n648, n649, n650, n651, n652, - n653, n654, n655, n656, n657, n658, n659, n660, n661, n662, - n663, n664, n665, n666, n667, n668, n669, n670, n671, n672, - n673, n674, n675, n676, n677, n678, n679, n680, n681, n682, - n683, n684, n685, n686, n687, n688, n689, n690, n691, n692, - n693, n694, n695, n696; - - -assign po22 = n137; -assign po19 = n346; -assign po16 = n364; -assign po17 = n415; -assign po18 = n295; -assign po00 = n427; -assign po09 = n351; -assign po04 = n377; -assign po06 = n454; - AN2 U371 ( .A(pi11), .B(pi08), .Z(n357)); - AN2 U372 ( .A(pi28), .B(n357), .Z(n346)); - AN2 U373 ( .A(pi41), .B(pi25), .Z(n369)); - AN2 U374 ( .A(pi52), .B(n369), .Z(n361)); - AN2 U375 ( .A(pi51), .B(pi54), .Z(n359)); - AN2 U376 ( .A(pi28), .B(pi31), .Z(n604)); - AN2 U377 ( .A(n604), .B(pi55), .Z(n358)); - AN2 U378 ( .A(n359), .B(n358), .Z(n602)); - AN2 U379 ( .A(pi53), .B(n602), .Z(n360)); - AN2 U380 ( .A(n361), .B(n360), .Z(n577)); - IV2 U381 ( .A(pi20), .Z(n607)); - OR2 U382 ( .A(n607), .B(pi25), .Z(n362)); - IV2 U383 ( .A(n362), .Z(n365)); - AN2 U384 ( .A(pi25), .B(n607), .Z(n363)); - OR2 U385 ( .A(n365), .B(n363), .Z(n367)); - AN2 U386 ( .A(pi41), .B(pi24), .Z(n378)); - AN2 U387 ( .A(n346), .B(n378), .Z(n366)); - AN2 U388 ( .A(n367), .B(n366), .Z(n373)); - AN2 U389 ( .A(pi28), .B(pi54), .Z(n368)); - AN2 U390 ( .A(pi20), .B(n368), .Z(n603)); - AN2 U391 ( .A(pi08), .B(n603), .Z(n371)); - IV2 U392 ( .A(pi56), .Z(n694)); - IV2 U393 ( .A(n369), .Z(n692)); - OR2 U394 ( .A(n694), .B(n692), .Z(n370)); - AN2 U395 ( .A(n371), .B(n370), .Z(n372)); - OR2 U396 ( .A(n373), .B(n372), .Z(n424)); - AN2 U397 ( .A(pi14), .B(n424), .Z(n384)); - AN2 U398 ( .A(pi56), .B(pi48), .Z(n608)); - AN2 U399 ( .A(n608), .B(n346), .Z(n374)); - AN2 U400 ( .A(pi07), .B(n374), .Z(n376)); - IV2 U401 ( .A(pi43), .Z(n375)); - AN2 U402 ( .A(n376), .B(n375), .Z(n406)); - AN2 U403 ( .A(pi20), .B(n406), .Z(n403)); - IV2 U404 ( .A(n378), .Z(n379)); - AN2 U405 ( .A(n346), .B(n379), .Z(n407)); - AN2 U406 ( .A(pi55), .B(n407), .Z(n399)); - AN2 U407 ( .A(pi44), .B(n399), .Z(n381)); - AN2 U408 ( .A(pi37), .B(pi54), .Z(n380)); - OR2 U409 ( .A(n381), .B(n380), .Z(n382)); - OR2 U410 ( .A(n403), .B(n382), .Z(n383)); - OR2 U411 ( .A(n384), .B(n383), .Z(n436)); - AN2 U412 ( .A(pi26), .B(n436), .Z(n385)); - OR2 U413 ( .A(n577), .B(n385), .Z(n386)); - AN2 U414 ( .A(pi34), .B(n386), .Z(n448)); - AN2 U415 ( .A(pi43), .B(pi05), .Z(n388)); - AN2 U416 ( .A(pi32), .B(n436), .Z(n387)); - OR2 U417 ( .A(n388), .B(n387), .Z(n446)); - AN2 U418 ( .A(pi08), .B(pi37), .Z(n393)); - AN2 U419 ( .A(pi50), .B(n399), .Z(n390)); - AN2 U420 ( .A(pi18), .B(n424), .Z(n389)); - OR2 U421 ( .A(n390), .B(n389), .Z(n391)); - OR2 U422 ( .A(n403), .B(n391), .Z(n392)); - OR2 U423 ( .A(n393), .B(n392), .Z(n494)); - AN2 U424 ( .A(pi27), .B(n494), .Z(n497)); - OR2 U425 ( .A(pi27), .B(n494), .Z(n499)); - AN2 U426 ( .A(pi20), .B(pi37), .Z(n398)); - AN2 U427 ( .A(pi45), .B(n399), .Z(n395)); - AN2 U428 ( .A(pi22), .B(n424), .Z(n394)); - OR2 U429 ( .A(n395), .B(n394), .Z(n396)); - OR2 U430 ( .A(n403), .B(n396), .Z(n397)); - OR2 U431 ( .A(n398), .B(n397), .Z(n536)); - AN2 U432 ( .A(pi17), .B(n536), .Z(n539)); - OR2 U433 ( .A(pi17), .B(n536), .Z(n541)); - AN2 U434 ( .A(pi23), .B(n424), .Z(n405)); - AN2 U435 ( .A(pi30), .B(pi37), .Z(n401)); - AN2 U436 ( .A(pi29), .B(n399), .Z(n400)); - OR2 U437 ( .A(n401), .B(n400), .Z(n402)); - OR2 U438 ( .A(n403), .B(n402), .Z(n404)); - OR2 U439 ( .A(n405), .B(n404), .Z(n579)); - AN2 U440 ( .A(pi21), .B(n579), .Z(n582)); - OR2 U441 ( .A(pi21), .B(n579), .Z(n584)); - AN2 U442 ( .A(n406), .B(pi55), .Z(n429)); - IV2 U443 ( .A(pi28), .Z(n409)); - AN2 U444 ( .A(n407), .B(pi20), .Z(n408)); - OR2 U445 ( .A(n409), .B(n408), .Z(n423)); - AN2 U446 ( .A(pi50), .B(n423), .Z(n411)); - AN2 U447 ( .A(pi42), .B(n424), .Z(n410)); - OR2 U448 ( .A(n411), .B(n410), .Z(n412)); - OR2 U449 ( .A(n429), .B(n412), .Z(n514)); - AN2 U450 ( .A(pi15), .B(n514), .Z(n517)); - OR2 U451 ( .A(pi15), .B(n514), .Z(n519)); - AN2 U452 ( .A(pi45), .B(n423), .Z(n414)); - AN2 U453 ( .A(pi40), .B(n424), .Z(n413)); - OR2 U454 ( .A(n414), .B(n413), .Z(n416)); - OR2 U455 ( .A(n429), .B(n416), .Z(n556)); - AN2 U456 ( .A(pi03), .B(n556), .Z(n559)); - OR2 U457 ( .A(pi03), .B(n556), .Z(n561)); - AN2 U458 ( .A(pi29), .B(n423), .Z(n418)); - AN2 U459 ( .A(pi04), .B(n424), .Z(n417)); - OR2 U460 ( .A(n418), .B(n417), .Z(n419)); - OR2 U461 ( .A(n429), .B(n419), .Z(n471)); - AN2 U462 ( .A(pi10), .B(n471), .Z(n480)); - OR2 U463 ( .A(pi10), .B(n471), .Z(n482)); - AN2 U464 ( .A(pi46), .B(n482), .Z(n420)); - OR2 U465 ( .A(n480), .B(n420), .Z(n562)); - AN2 U466 ( .A(n561), .B(n562), .Z(n421)); - OR2 U467 ( .A(n559), .B(n421), .Z(n520)); - AN2 U468 ( .A(n519), .B(n520), .Z(n422)); - OR2 U469 ( .A(n517), .B(n422), .Z(n449)); - AN2 U470 ( .A(pi44), .B(n423), .Z(n426)); - AN2 U471 ( .A(pi49), .B(n424), .Z(n425)); - OR2 U472 ( .A(n426), .B(n425), .Z(n428)); - OR2 U473 ( .A(n429), .B(n428), .Z(n464)); - AN2 U474 ( .A(n449), .B(n464), .Z(n432)); - OR2 U475 ( .A(n449), .B(n464), .Z(n430)); - AN2 U476 ( .A(pi09), .B(n430), .Z(n431)); - OR2 U477 ( .A(n432), .B(n431), .Z(n585)); - AN2 U478 ( .A(n584), .B(n585), .Z(n433)); - OR2 U479 ( .A(n582), .B(n433), .Z(n542)); - AN2 U480 ( .A(n541), .B(n542), .Z(n434)); - OR2 U481 ( .A(n539), .B(n434), .Z(n500)); - AN2 U482 ( .A(n499), .B(n500), .Z(n435)); - OR2 U483 ( .A(n497), .B(n435), .Z(n597)); - OR2 U484 ( .A(pi34), .B(n436), .Z(n598)); - AN2 U485 ( .A(n436), .B(pi34), .Z(n600)); - IV2 U486 ( .A(n600), .Z(n437)); - AN2 U487 ( .A(n598), .B(n437), .Z(n442)); - OR2 U488 ( .A(n597), .B(n442), .Z(n440)); - AN2 U489 ( .A(n597), .B(n442), .Z(n438)); - IV2 U490 ( .A(n438), .Z(n439)); - AN2 U491 ( .A(n440), .B(n439), .Z(n441)); - AN2 U492 ( .A(pi12), .B(n441), .Z(n444)); - AN2 U493 ( .A(n442), .B(pi19), .Z(n443)); - OR2 U494 ( .A(n444), .B(n443), .Z(n445)); - OR2 U495 ( .A(n446), .B(n445), .Z(n447)); - OR2 U496 ( .A(n448), .B(n447), .Z(n137)); - IV2 U497 ( .A(n464), .Z(n459)); - AN2 U498 ( .A(pi12), .B(n449), .Z(n456)); - AN2 U499 ( .A(n459), .B(n456), .Z(n453)); - IV2 U500 ( .A(n449), .Z(n450)); - AN2 U501 ( .A(n450), .B(pi12), .Z(n451)); - OR2 U502 ( .A(pi19), .B(n451), .Z(n458)); - AN2 U503 ( .A(n464), .B(n458), .Z(n452)); - OR2 U504 ( .A(n453), .B(n452), .Z(n455)); - IV2 U505 ( .A(pi09), .Z(n612)); - AN2 U506 ( .A(n455), .B(n612), .Z(n470)); - OR2 U507 ( .A(pi26), .B(n456), .Z(n457)); - AN2 U508 ( .A(n464), .B(n457), .Z(n462)); - AN2 U509 ( .A(n459), .B(n458), .Z(n460)); - OR2 U510 ( .A(n577), .B(n460), .Z(n461)); - OR2 U511 ( .A(n462), .B(n461), .Z(n463)); - AN2 U512 ( .A(pi09), .B(n463), .Z(n468)); - AN2 U513 ( .A(pi23), .B(pi05), .Z(n466)); - AN2 U514 ( .A(pi32), .B(n464), .Z(n465)); - OR2 U515 ( .A(n466), .B(n465), .Z(n467)); - OR2 U516 ( .A(n468), .B(n467), .Z(n469)); - OR2 U517 ( .A(n470), .B(n469), .Z(n295)); - AN2 U518 ( .A(pi26), .B(n480), .Z(n479)); - AN2 U519 ( .A(pi40), .B(pi05), .Z(n473)); - AN2 U520 ( .A(pi32), .B(n471), .Z(n472)); - OR2 U521 ( .A(n473), .B(n472), .Z(n477)); - AN2 U522 ( .A(pi38), .B(pi36), .Z(n475)); - AN2 U523 ( .A(pi10), .B(n577), .Z(n474)); - OR2 U524 ( .A(n475), .B(n474), .Z(n476)); - OR2 U525 ( .A(n477), .B(n476), .Z(n478)); - OR2 U526 ( .A(n479), .B(n478), .Z(n491)); - IV2 U527 ( .A(n480), .Z(n481)); - AN2 U528 ( .A(n482), .B(n481), .Z(n487)); - OR2 U529 ( .A(pi46), .B(n487), .Z(n485)); - AN2 U530 ( .A(pi46), .B(n487), .Z(n483)); - IV2 U531 ( .A(n483), .Z(n484)); - AN2 U532 ( .A(n485), .B(n484), .Z(n486)); - AN2 U533 ( .A(pi12), .B(n486), .Z(n489)); - AN2 U534 ( .A(n487), .B(pi19), .Z(n488)); - OR2 U535 ( .A(n489), .B(n488), .Z(n490)); - OR2 U536 ( .A(n491), .B(n490), .Z(n351)); - AN2 U537 ( .A(pi26), .B(n494), .Z(n492)); - OR2 U538 ( .A(n577), .B(n492), .Z(n493)); - AN2 U539 ( .A(pi27), .B(n493), .Z(n511)); - AN2 U540 ( .A(pi14), .B(pi05), .Z(n496)); - AN2 U541 ( .A(pi32), .B(n494), .Z(n495)); - OR2 U542 ( .A(n496), .B(n495), .Z(n509)); - IV2 U543 ( .A(n497), .Z(n498)); - AN2 U544 ( .A(n499), .B(n498), .Z(n505)); - OR2 U545 ( .A(n500), .B(n505), .Z(n503)); - AN2 U546 ( .A(n500), .B(n505), .Z(n501)); - IV2 U547 ( .A(n501), .Z(n502)); - AN2 U548 ( .A(n503), .B(n502), .Z(n504)); - AN2 U549 ( .A(pi12), .B(n504), .Z(n507)); - AN2 U550 ( .A(n505), .B(pi19), .Z(n506)); - OR2 U551 ( .A(n507), .B(n506), .Z(n508)); - OR2 U552 ( .A(n509), .B(n508), .Z(n510)); - OR2 U553 ( .A(n511), .B(n510), .Z(n364)); - AN2 U554 ( .A(pi26), .B(n514), .Z(n512)); - OR2 U555 ( .A(n577), .B(n512), .Z(n513)); - AN2 U556 ( .A(pi15), .B(n513), .Z(n533)); - AN2 U557 ( .A(pi49), .B(pi05), .Z(n531)); - AN2 U558 ( .A(pi33), .B(pi36), .Z(n516)); - AN2 U559 ( .A(pi32), .B(n514), .Z(n515)); - OR2 U560 ( .A(n516), .B(n515), .Z(n529)); - IV2 U561 ( .A(n517), .Z(n518)); - AN2 U562 ( .A(n519), .B(n518), .Z(n525)); - OR2 U563 ( .A(n520), .B(n525), .Z(n523)); - AN2 U564 ( .A(n520), .B(n525), .Z(n521)); - IV2 U565 ( .A(n521), .Z(n522)); - AN2 U566 ( .A(n523), .B(n522), .Z(n524)); - AN2 U567 ( .A(pi12), .B(n524), .Z(n527)); - AN2 U568 ( .A(n525), .B(pi19), .Z(n526)); - OR2 U569 ( .A(n527), .B(n526), .Z(n528)); - OR2 U570 ( .A(n529), .B(n528), .Z(n530)); - OR2 U571 ( .A(n531), .B(n530), .Z(n532)); - OR2 U572 ( .A(n533), .B(n532), .Z(n377)); - AN2 U573 ( .A(pi26), .B(n536), .Z(n534)); - OR2 U574 ( .A(n577), .B(n534), .Z(n535)); - AN2 U575 ( .A(pi17), .B(n535), .Z(n553)); - AN2 U576 ( .A(pi18), .B(pi05), .Z(n538)); - AN2 U577 ( .A(pi32), .B(n536), .Z(n537)); - OR2 U578 ( .A(n538), .B(n537), .Z(n551)); - IV2 U579 ( .A(n539), .Z(n540)); - AN2 U580 ( .A(n541), .B(n540), .Z(n547)); - OR2 U581 ( .A(n542), .B(n547), .Z(n545)); - AN2 U582 ( .A(n542), .B(n547), .Z(n543)); - IV2 U583 ( .A(n543), .Z(n544)); - AN2 U584 ( .A(n545), .B(n544), .Z(n546)); - AN2 U585 ( .A(pi12), .B(n546), .Z(n549)); - AN2 U586 ( .A(n547), .B(pi19), .Z(n548)); - OR2 U587 ( .A(n549), .B(n548), .Z(n550)); - OR2 U588 ( .A(n551), .B(n550), .Z(n552)); - OR2 U589 ( .A(n553), .B(n552), .Z(n415)); - AN2 U590 ( .A(pi26), .B(n556), .Z(n554)); - OR2 U591 ( .A(n577), .B(n554), .Z(n555)); - AN2 U592 ( .A(pi03), .B(n555), .Z(n575)); - AN2 U593 ( .A(pi42), .B(pi05), .Z(n573)); - AN2 U594 ( .A(pi47), .B(pi36), .Z(n558)); - AN2 U595 ( .A(pi32), .B(n556), .Z(n557)); - OR2 U596 ( .A(n558), .B(n557), .Z(n571)); - IV2 U597 ( .A(n559), .Z(n560)); - AN2 U598 ( .A(n561), .B(n560), .Z(n567)); - OR2 U599 ( .A(n562), .B(n567), .Z(n565)); - AN2 U600 ( .A(n562), .B(n567), .Z(n563)); - IV2 U601 ( .A(n563), .Z(n564)); - AN2 U602 ( .A(n565), .B(n564), .Z(n566)); - AN2 U603 ( .A(pi12), .B(n566), .Z(n569)); - AN2 U604 ( .A(n567), .B(pi19), .Z(n568)); - OR2 U605 ( .A(n569), .B(n568), .Z(n570)); - OR2 U606 ( .A(n571), .B(n570), .Z(n572)); - OR2 U607 ( .A(n573), .B(n572), .Z(n574)); - OR2 U608 ( .A(n575), .B(n574), .Z(n427)); - AN2 U609 ( .A(pi26), .B(n579), .Z(n576)); - OR2 U610 ( .A(n577), .B(n576), .Z(n578)); - AN2 U611 ( .A(pi21), .B(n578), .Z(n596)); - AN2 U612 ( .A(pi22), .B(pi05), .Z(n581)); - AN2 U613 ( .A(pi32), .B(n579), .Z(n580)); - OR2 U614 ( .A(n581), .B(n580), .Z(n594)); - IV2 U615 ( .A(n582), .Z(n583)); - AN2 U616 ( .A(n584), .B(n583), .Z(n590)); - OR2 U617 ( .A(n585), .B(n590), .Z(n588)); - AN2 U618 ( .A(n585), .B(n590), .Z(n586)); - IV2 U619 ( .A(n586), .Z(n587)); - AN2 U620 ( .A(n588), .B(n587), .Z(n589)); - AN2 U621 ( .A(pi12), .B(n589), .Z(n592)); - AN2 U622 ( .A(n590), .B(pi19), .Z(n591)); - OR2 U623 ( .A(n592), .B(n591), .Z(n593)); - OR2 U624 ( .A(n594), .B(n593), .Z(n595)); - OR2 U625 ( .A(n596), .B(n595), .Z(n454)); - AN2 U626 ( .A(n598), .B(n597), .Z(n599)); - OR2 U627 ( .A(n600), .B(n599), .Z(po07)); - OR2 U628 ( .A(pi58), .B(pi00), .Z(n609)); - AN2 U629 ( .A(pi59), .B(n609), .Z(po24)); - AN2 U630 ( .A(n602), .B(pi57), .Z(n601)); - AN2 U631 ( .A(pi41), .B(n601), .Z(po13)); - AN2 U632 ( .A(pi48), .B(n602), .Z(po08)); - AN2 U633 ( .A(n603), .B(pi31), .Z(po03)); - AN2 U634 ( .A(pi48), .B(pi16), .Z(n610)); - AN2 U635 ( .A(pi25), .B(n610), .Z(po25)); - AN2 U636 ( .A(pi11), .B(n604), .Z(n605)); - IV2 U637 ( .A(n605), .Z(n606)); - OR2 U638 ( .A(n607), .B(n606), .Z(n691)); - OR2 U639 ( .A(po25), .B(n691), .Z(po02)); - AN2 U640 ( .A(n608), .B(pi25), .Z(po10)); - AN2 U641 ( .A(pi13), .B(n609), .Z(po12)); - AN2 U642 ( .A(pi07), .B(n610), .Z(po14)); - IV2 U643 ( .A(pi15), .Z(n611)); - AN2 U644 ( .A(pi09), .B(n611), .Z(n614)); - AN2 U645 ( .A(pi15), .B(n612), .Z(n613)); - OR2 U646 ( .A(n614), .B(n613), .Z(n618)); - IV2 U647 ( .A(pi35), .Z(n654)); - OR2 U648 ( .A(n654), .B(pi06), .Z(n617)); - IV2 U649 ( .A(pi06), .Z(n615)); - OR2 U650 ( .A(n615), .B(pi35), .Z(n616)); - AN2 U651 ( .A(n617), .B(n616), .Z(n619)); - OR2 U652 ( .A(n618), .B(n619), .Z(n622)); - AN2 U653 ( .A(n619), .B(n618), .Z(n620)); - IV2 U654 ( .A(n620), .Z(n621)); - AN2 U655 ( .A(n622), .B(n621), .Z(n628)); - IV2 U656 ( .A(pi10), .Z(n624)); - OR2 U657 ( .A(n624), .B(pi03), .Z(n623)); - IV2 U658 ( .A(n623), .Z(n626)); - AN2 U659 ( .A(pi03), .B(n624), .Z(n625)); - OR2 U660 ( .A(n626), .B(n625), .Z(n627)); - OR2 U661 ( .A(n628), .B(n627), .Z(n631)); - AN2 U662 ( .A(n628), .B(n627), .Z(n629)); - IV2 U663 ( .A(n629), .Z(n630)); - AN2 U664 ( .A(n631), .B(n630), .Z(n637)); - IV2 U665 ( .A(pi34), .Z(n632)); - AN2 U666 ( .A(pi27), .B(n632), .Z(n635)); - OR2 U667 ( .A(n632), .B(pi27), .Z(n633)); - IV2 U668 ( .A(n633), .Z(n634)); - OR2 U669 ( .A(n635), .B(n634), .Z(n636)); - OR2 U670 ( .A(n637), .B(n636), .Z(n640)); - AN2 U671 ( .A(n637), .B(n636), .Z(n638)); - IV2 U672 ( .A(n638), .Z(n639)); - AN2 U673 ( .A(n640), .B(n639), .Z(n647)); - IV2 U674 ( .A(pi21), .Z(n642)); - OR2 U675 ( .A(n642), .B(pi17), .Z(n641)); - IV2 U676 ( .A(n641), .Z(n644)); - AN2 U677 ( .A(pi17), .B(n642), .Z(n643)); - OR2 U678 ( .A(n644), .B(n643), .Z(n646)); - OR2 U679 ( .A(n647), .B(n646), .Z(n645)); - IV2 U680 ( .A(n645), .Z(n649)); - AN2 U681 ( .A(n647), .B(n646), .Z(n648)); - OR2 U682 ( .A(n649), .B(n648), .Z(po15)); - IV2 U683 ( .A(pi42), .Z(n650)); - AN2 U684 ( .A(pi49), .B(n650), .Z(n653)); - IV2 U685 ( .A(pi49), .Z(n651)); - AN2 U686 ( .A(pi42), .B(n651), .Z(n652)); - OR2 U687 ( .A(n653), .B(n652), .Z(n658)); - OR2 U688 ( .A(n654), .B(pi39), .Z(n657)); - IV2 U689 ( .A(pi39), .Z(n655)); - OR2 U690 ( .A(n655), .B(pi35), .Z(n656)); - AN2 U691 ( .A(n657), .B(n656), .Z(n659)); - OR2 U692 ( .A(n658), .B(n659), .Z(n662)); - AN2 U693 ( .A(n659), .B(n658), .Z(n660)); - IV2 U694 ( .A(n660), .Z(n661)); - AN2 U695 ( .A(n662), .B(n661), .Z(n668)); - IV2 U696 ( .A(pi04), .Z(n664)); - OR2 U697 ( .A(n664), .B(pi18), .Z(n663)); - IV2 U698 ( .A(n663), .Z(n666)); - AN2 U699 ( .A(pi18), .B(n664), .Z(n665)); - OR2 U700 ( .A(n666), .B(n665), .Z(n667)); - OR2 U701 ( .A(n668), .B(n667), .Z(n671)); - AN2 U702 ( .A(n668), .B(n667), .Z(n669)); - IV2 U703 ( .A(n669), .Z(n670)); - AN2 U704 ( .A(n671), .B(n670), .Z(n677)); - IV2 U705 ( .A(pi22), .Z(n673)); - OR2 U706 ( .A(n673), .B(pi14), .Z(n672)); - IV2 U707 ( .A(n672), .Z(n675)); - AN2 U708 ( .A(pi14), .B(n673), .Z(n674)); - OR2 U709 ( .A(n675), .B(n674), .Z(n676)); - OR2 U710 ( .A(n677), .B(n676), .Z(n680)); - AN2 U711 ( .A(n677), .B(n676), .Z(n678)); - IV2 U712 ( .A(n678), .Z(n679)); - AN2 U713 ( .A(n680), .B(n679), .Z(n687)); - IV2 U714 ( .A(pi40), .Z(n682)); - OR2 U715 ( .A(n682), .B(pi23), .Z(n681)); - IV2 U716 ( .A(n681), .Z(n684)); - AN2 U717 ( .A(pi23), .B(n682), .Z(n683)); - OR2 U718 ( .A(n684), .B(n683), .Z(n686)); - OR2 U719 ( .A(n687), .B(n686), .Z(n685)); - IV2 U720 ( .A(n685), .Z(n689)); - AN2 U721 ( .A(n687), .B(n686), .Z(n688)); - OR2 U722 ( .A(n689), .B(n688), .Z(po20)); - AN2 U723 ( .A(pi01), .B(pi02), .Z(po21)); - IV2 U724 ( .A(po25), .Z(n690)); - OR2 U725 ( .A(n691), .B(n690), .Z(po23)); - IV2 U726 ( .A(pi16), .Z(n696)); - OR2 U727 ( .A(n692), .B(n696), .Z(po11)); - AN2 U728 ( .A(pi07), .B(pi41), .Z(n693)); - IV2 U729 ( .A(n693), .Z(n695)); - OR2 U730 ( .A(n694), .B(n695), .Z(po01)); - OR2 U731 ( .A(n696), .B(n695), .Z(po05)); - -endmodule - -module IV2(A, Z); - input A; - output Z; - - assign Z = ~A; -endmodule - -module AN2(A, B, Z); - input A, B; - output Z; - - assign Z = A & B; -endmodule - -module OR2(A, B, Z); - input A, B; - output Z; - - assign Z = A | B; -endmodule diff --git a/yosys/examples/smtbmc/glift/C880.ys b/yosys/examples/smtbmc/glift/C880.ys deleted file mode 100644 index 410768f21b5..00000000000 --- a/yosys/examples/smtbmc/glift/C880.ys +++ /dev/null @@ -1,41 +0,0 @@ -read_verilog C880.v -techmap -flatten -select C880_lev2 -glift -create-instrumented-model -techmap -opt -rename C880_lev2 uut -cd .. -delete [AIONX][NVXR]2 -read_verilog C880.v -techmap -flatten -select C880_lev2 -glift -create-precise-model -techmap -opt -rename C880_lev2 spec -cd .. -delete [AIONX][NVXR]2 - -design -push-copy -miter -equiv spec uut miter -flatten -delete uut spec -techmap -opt -stat miter -qbfsat -O2 -write-solution C880.soln -solver yices -timeout 3600 -nocleanup -assume-outputs -assume-negative-polarity miter -design -pop -stat - -copy uut solved -qbfsat -specialize-from-file C880.soln solved -opt solved -miter -equiv spec solved satmiter -flatten -sat -prove trigger 0 satmiter -delete satmiter -stat -shell diff --git a/yosys/examples/smtbmc/glift/alu2.v b/yosys/examples/smtbmc/glift/alu2.v deleted file mode 100755 index 6b6e3d7af24..00000000000 --- a/yosys/examples/smtbmc/glift/alu2.v +++ /dev/null @@ -1,400 +0,0 @@ -module alu2_lev2(pi0, pi1, pi2, pi3, pi4, pi5, pi6, pi7, pi8, pi9, - po0, po1, po2, po3, po4, po5); - -input pi0, pi1, pi2, pi3, pi4, pi5, pi6, pi7, pi8, pi9; - -output po0, po1, po2, po3, po4, po5; - -wire n358, n359, n360, n361, n362, n363, n364, n365, n366, n367, - n368, n369, n370, n371, n372, n373, n374, n375, n376, n377, - n378, n379, n380, n381, n382, n383, n384, n385, n386, n387, - n388, n389, n390, n391, n392, n393, n394, n395, n396, n397, - n398, n399, n400, n401, n402, n403, n404, n405, n406, n407, - n408, n409, n410, n411, n412, n413, n414, n415, n416, n417, - n418, n419, n420, n421, n422, n423, n424, n425, n426, n427, - n428, n429, n430, n431, n432, n433, n434, n435, n436, n437, - n438, n439, n440, n441, n442, n443, n444, n445, n446, n447, - n448, n449, n450, n451, n452, n453, n454, n455, n456, n457, - n458, n459, n460, n461, n462, n463, n464, n465, n466, n467, - n468, n469, n470, n471, n472, n473, n474, n475, n476, n477, - n478, n479, n480, n481, n482, n483, n484, n485, n486, n487, - n488, n489, n490, n491, n492, n493, n494, n495, n496, n497, - n498, n499, n500, n501, n502, n503, n504, n505, n506, n507, - n508, n509, n510, n511, n512, n513, n514, n515, n516, n517, - n518, n519, n520, n521, n522, n523, n524, n525, n526, n527, - n528, n529, n530, n531, n532, n533, n534, n535, n536, n537, - n538, n539, n540, n541, n542, n543, n544, n545, n546, n547, - n548, n549, n550, n551, n552, n553, n554, n555, n556, n557, - n558, n559, n560, n561, n562, n563, n564, n565, n566, n567, - n568, n569, n570, n571, n572, n573, n574, n575, n576, n577, - n578, n579, n580, n581, n582, n583, n584, n585, n586, n587, - n588, n589, n590, n591, n592, n593, n594, n595, n596, n597, - n598, n599, n600, n601, n602, n603, n604, n605, n606, n607, - n608, n609, n610, n611, n612, n613, n614, n615, n616, n617, - n618, n619, n620, n621, n622, n623, n624, n625, n626, n627, - n628, n629, n630, n631, n632, n633, n634, n635, n636, n637, - n638, n639, n640, n641, n642, n643, n644, n645, n646, n647, - n648, n649, n650, n651, n652, n653, n654, n655, n656, n657, - n658, n659, n660, n661, n662, n663, n664, n665, n666, n667, - n668, n669, n670, n671, n672, n673, n674, n675, n676, n677, - n678, n679, n680, n681, n682, n683, n684, n685, n686, n687; - - AN2 U363 ( .A(n358), .B(po2), .Z(po5)); - OR2 U364 ( .A(n359), .B(n360), .Z(n358)); - AN2 U365 ( .A(n361), .B(n362), .Z(n359)); - AN2 U366 ( .A(pi9), .B(n363), .Z(po4)); - OR2 U367 ( .A(n364), .B(n365), .Z(n363)); - OR2 U368 ( .A(n366), .B(n367), .Z(n365)); - AN2 U369 ( .A(pi6), .B(n368), .Z(n367)); - OR2 U370 ( .A(n369), .B(n370), .Z(n368)); - OR2 U371 ( .A(n371), .B(n372), .Z(n370)); - OR2 U372 ( .A(n373), .B(n374), .Z(n372)); - AN2 U373 ( .A(n375), .B(n376), .Z(n374)); - AN2 U374 ( .A(n377), .B(n378), .Z(n375)); - OR2 U375 ( .A(n379), .B(n380), .Z(n377)); - OR2 U376 ( .A(n381), .B(n382), .Z(n380)); - OR2 U377 ( .A(n383), .B(n384), .Z(n379)); - AN2 U378 ( .A(n385), .B(pi5), .Z(n384)); - AN2 U379 ( .A(n386), .B(n387), .Z(n383)); - AN2 U380 ( .A(pi4), .B(n361), .Z(n386)); - AN2 U381 ( .A(n388), .B(n389), .Z(n373)); - OR2 U382 ( .A(n390), .B(n391), .Z(n388)); - AN2 U383 ( .A(pi1), .B(n392), .Z(n390)); - OR2 U384 ( .A(n393), .B(n394), .Z(n392)); - OR2 U385 ( .A(pi7), .B(n395), .Z(n394)); - AN2 U386 ( .A(n381), .B(n396), .Z(n395)); - OR2 U387 ( .A(n397), .B(n398), .Z(n369)); - AN2 U388 ( .A(n399), .B(n400), .Z(n398)); - AN2 U389 ( .A(n387), .B(n401), .Z(n399)); - AN2 U390 ( .A(n402), .B(n403), .Z(n397)); - AN2 U391 ( .A(pi0), .B(n404), .Z(n402)); - OR2 U392 ( .A(pi1), .B(n389), .Z(n404)); - AN2 U393 ( .A(n405), .B(n406), .Z(n366)); - OR2 U394 ( .A(n407), .B(n408), .Z(n406)); - AN2 U395 ( .A(n360), .B(n409), .Z(n408)); - OR2 U396 ( .A(n410), .B(n411), .Z(n409)); - OR2 U397 ( .A(n412), .B(n413), .Z(n411)); - AN2 U398 ( .A(n414), .B(pi3), .Z(n413)); - AN2 U399 ( .A(n389), .B(n415), .Z(n410)); - AN2 U400 ( .A(po3), .B(n416), .Z(n407)); - OR2 U401 ( .A(n417), .B(n414), .Z(n416)); - OR2 U402 ( .A(n418), .B(n419), .Z(n364)); - OR2 U403 ( .A(n420), .B(n421), .Z(n419)); - AN2 U404 ( .A(n422), .B(n382), .Z(n421)); - AN2 U405 ( .A(pi7), .B(n389), .Z(n422)); - AN2 U406 ( .A(n423), .B(n424), .Z(n418)); - AN2 U407 ( .A(n425), .B(n426), .Z(n423)); - OR2 U408 ( .A(n427), .B(po3), .Z(po2)); - AN2 U409 ( .A(n428), .B(n429), .Z(n427)); - OR2 U410 ( .A(n430), .B(n431), .Z(po1)); - AN2 U411 ( .A(pi9), .B(n432), .Z(n431)); - OR2 U412 ( .A(n433), .B(n434), .Z(n432)); - OR2 U413 ( .A(n435), .B(n436), .Z(n434)); - AN2 U414 ( .A(n437), .B(n438), .Z(n436)); - IV2 U415 ( .A(n425), .Z(n438)); - AN2 U416 ( .A(n424), .B(n426), .Z(n437)); - OR2 U417 ( .A(n439), .B(n440), .Z(n424)); - OR2 U418 ( .A(n441), .B(n442), .Z(n440)); - AN2 U419 ( .A(n381), .B(n443), .Z(n442)); - OR2 U420 ( .A(n444), .B(n445), .Z(n443)); - AN2 U421 ( .A(n446), .B(n447), .Z(n441)); - AN2 U422 ( .A(n387), .B(n361), .Z(n446)); - AN2 U423 ( .A(n448), .B(n425), .Z(n435)); - OR2 U424 ( .A(n449), .B(n450), .Z(n425)); - OR2 U425 ( .A(n420), .B(n451), .Z(n450)); - OR2 U426 ( .A(n452), .B(n453), .Z(n451)); - AN2 U427 ( .A(pi6), .B(n454), .Z(n453)); - OR2 U428 ( .A(n371), .B(n455), .Z(n454)); - AN2 U429 ( .A(n376), .B(n456), .Z(n455)); - OR2 U430 ( .A(n457), .B(n458), .Z(n456)); - OR2 U431 ( .A(n459), .B(n460), .Z(n458)); - AN2 U432 ( .A(n461), .B(n378), .Z(n460)); - OR2 U433 ( .A(n462), .B(n463), .Z(n461)); - AN2 U434 ( .A(n385), .B(n464), .Z(n462)); - OR2 U435 ( .A(n465), .B(pi5), .Z(n464)); - AN2 U436 ( .A(pi7), .B(n466), .Z(n459)); - OR2 U437 ( .A(n467), .B(n468), .Z(n466)); - OR2 U438 ( .A(n469), .B(n470), .Z(n468)); - AN2 U439 ( .A(n381), .B(pi1), .Z(n470)); - AN2 U440 ( .A(n471), .B(n428), .Z(n469)); - AN2 U441 ( .A(pi0), .B(n387), .Z(n471)); - AN2 U442 ( .A(n412), .B(n361), .Z(n467)); - AN2 U443 ( .A(n472), .B(n473), .Z(n457)); - AN2 U444 ( .A(n360), .B(n428), .Z(n472)); - AN2 U445 ( .A(n463), .B(n428), .Z(n371)); - AN2 U446 ( .A(n474), .B(n475), .Z(n452)); - OR2 U447 ( .A(n476), .B(n477), .Z(n474)); - OR2 U448 ( .A(n478), .B(n479), .Z(n477)); - AN2 U449 ( .A(n480), .B(n428), .Z(n479)); - AN2 U450 ( .A(n481), .B(n482), .Z(n480)); - OR2 U451 ( .A(n360), .B(n389), .Z(n482)); - OR2 U452 ( .A(n401), .B(n483), .Z(n481)); - AN2 U453 ( .A(pi7), .B(n484), .Z(n483)); - OR2 U454 ( .A(n393), .B(n485), .Z(n484)); - AN2 U455 ( .A(n376), .B(n415), .Z(n485)); - AN2 U456 ( .A(n414), .B(n429), .Z(n393)); - AN2 U457 ( .A(n486), .B(n378), .Z(n478)); - OR2 U458 ( .A(n412), .B(n389), .Z(n486)); - AN2 U459 ( .A(n487), .B(pi1), .Z(n412)); - OR2 U460 ( .A(n488), .B(n489), .Z(n476)); - AN2 U461 ( .A(n490), .B(n401), .Z(n488)); - AN2 U462 ( .A(pi1), .B(n429), .Z(n490)); - AN2 U463 ( .A(n385), .B(n491), .Z(n420)); - IV2 U464 ( .A(n492), .Z(n491)); - OR2 U465 ( .A(n493), .B(n487), .Z(n492)); - AN2 U466 ( .A(n494), .B(n495), .Z(n493)); - OR2 U467 ( .A(pi6), .B(n389), .Z(n495)); - OR2 U468 ( .A(pi7), .B(pi1), .Z(n494)); - OR2 U469 ( .A(n496), .B(n497), .Z(n449)); - AN2 U470 ( .A(n498), .B(n376), .Z(n497)); - AN2 U471 ( .A(n381), .B(n382), .Z(n498)); - AN2 U472 ( .A(n499), .B(n389), .Z(n496)); - OR2 U473 ( .A(n500), .B(n501), .Z(n499)); - OR2 U474 ( .A(n502), .B(n503), .Z(n501)); - AN2 U475 ( .A(n385), .B(n504), .Z(n503)); - OR2 U476 ( .A(n505), .B(n506), .Z(n504)); - AN2 U477 ( .A(po3), .B(n400), .Z(n506)); - AN2 U478 ( .A(n507), .B(n428), .Z(n505)); - AN2 U479 ( .A(n508), .B(n387), .Z(n502)); - OR2 U480 ( .A(n509), .B(n510), .Z(n508)); - OR2 U481 ( .A(n489), .B(n511), .Z(n510)); - OR2 U482 ( .A(n465), .B(n512), .Z(n511)); - AN2 U483 ( .A(n513), .B(pi1), .Z(n512)); - AN2 U484 ( .A(pi0), .B(n514), .Z(n513)); - OR2 U485 ( .A(n507), .B(n515), .Z(n514)); - AN2 U486 ( .A(n361), .B(n428), .Z(n465)); - AN2 U487 ( .A(po3), .B(n360), .Z(n489)); - OR2 U488 ( .A(n516), .B(n517), .Z(n509)); - OR2 U489 ( .A(n518), .B(n519), .Z(n517)); - AN2 U490 ( .A(n391), .B(n362), .Z(n519)); - AN2 U491 ( .A(n428), .B(n400), .Z(n391)); - AN2 U492 ( .A(n520), .B(n521), .Z(n518)); - OR2 U493 ( .A(n522), .B(n362), .Z(n521)); - AN2 U494 ( .A(n429), .B(n523), .Z(n520)); - AN2 U495 ( .A(n417), .B(n378), .Z(n516)); - AN2 U496 ( .A(n522), .B(n382), .Z(n500)); - AN2 U497 ( .A(pi1), .B(n396), .Z(n382)); - AN2 U498 ( .A(n361), .B(n378), .Z(n522)); - OR2 U499 ( .A(n524), .B(n525), .Z(n448)); - OR2 U500 ( .A(n526), .B(n527), .Z(n525)); - OR2 U501 ( .A(pi8), .B(n528), .Z(n524)); - AN2 U502 ( .A(n529), .B(n530), .Z(n430)); - OR2 U503 ( .A(n531), .B(n532), .Z(n529)); - OR2 U504 ( .A(n533), .B(n534), .Z(n532)); - OR2 U505 ( .A(n535), .B(n536), .Z(n534)); - AN2 U506 ( .A(n537), .B(n376), .Z(n536)); - IV2 U507 ( .A(n389), .Z(n376)); - AN2 U508 ( .A(n538), .B(n389), .Z(n535)); - OR2 U509 ( .A(n539), .B(n540), .Z(n389)); - OR2 U510 ( .A(n541), .B(n542), .Z(n540)); - OR2 U511 ( .A(n543), .B(n544), .Z(n542)); - AN2 U512 ( .A(pi1), .B(n545), .Z(n544)); - AN2 U513 ( .A(n546), .B(n428), .Z(n543)); - AN2 U514 ( .A(n547), .B(n548), .Z(n546)); - OR2 U515 ( .A(pi3), .B(n396), .Z(n548)); - AN2 U516 ( .A(pi9), .B(n549), .Z(n541)); - OR2 U517 ( .A(n550), .B(n551), .Z(n549)); - OR2 U518 ( .A(n552), .B(n553), .Z(n551)); - AN2 U519 ( .A(n554), .B(n507), .Z(n553)); - AN2 U520 ( .A(n396), .B(pi0), .Z(n554)); - AN2 U521 ( .A(n555), .B(n556), .Z(n552)); - AN2 U522 ( .A(n557), .B(n415), .Z(n556)); - AN2 U523 ( .A(po3), .B(n558), .Z(n555)); - OR2 U524 ( .A(n559), .B(n560), .Z(n550)); - AN2 U525 ( .A(n561), .B(n429), .Z(n560)); - AN2 U526 ( .A(n417), .B(n562), .Z(n561)); - OR2 U527 ( .A(n563), .B(n564), .Z(n562)); - AN2 U528 ( .A(n558), .B(n428), .Z(n564)); - AN2 U529 ( .A(pi1), .B(n565), .Z(n563)); - AN2 U530 ( .A(pi3), .B(n566), .Z(n559)); - OR2 U531 ( .A(n567), .B(n414), .Z(n566)); - AN2 U532 ( .A(n568), .B(n569), .Z(n567)); - AN2 U533 ( .A(n565), .B(n428), .Z(n568)); - OR2 U534 ( .A(n570), .B(n571), .Z(n539)); - AN2 U535 ( .A(n572), .B(n429), .Z(n571)); - AN2 U536 ( .A(po3), .B(n573), .Z(n570)); - OR2 U537 ( .A(n574), .B(n575), .Z(n538)); - OR2 U538 ( .A(n445), .B(n576), .Z(n575)); - AN2 U539 ( .A(n577), .B(pi3), .Z(n576)); - AN2 U540 ( .A(n578), .B(pi1), .Z(n574)); - AN2 U541 ( .A(n507), .B(pi1), .Z(n533)); - OR2 U542 ( .A(n579), .B(n580), .Z(n531)); - OR2 U543 ( .A(n581), .B(n582), .Z(n580)); - AN2 U544 ( .A(n444), .B(po3), .Z(n582)); - AN2 U545 ( .A(pi1), .B(pi3), .Z(po3)); - AN2 U546 ( .A(n583), .B(n557), .Z(n581)); - AN2 U547 ( .A(n584), .B(n429), .Z(n583)); - OR2 U548 ( .A(n585), .B(n414), .Z(n584)); - AN2 U549 ( .A(n417), .B(n428), .Z(n585)); - AN2 U550 ( .A(n586), .B(pi7), .Z(n579)); - AN2 U551 ( .A(n587), .B(n588), .Z(n586)); - OR2 U552 ( .A(pi3), .B(n589), .Z(n588)); - AN2 U553 ( .A(pi1), .B(n523), .Z(n589)); - OR2 U554 ( .A(n429), .B(n590), .Z(n587)); - OR2 U555 ( .A(n417), .B(n591), .Z(n590)); - AN2 U556 ( .A(n592), .B(n428), .Z(n591)); - IV2 U557 ( .A(pi1), .Z(n428)); - IV2 U558 ( .A(pi3), .Z(n429)); - OR2 U559 ( .A(n593), .B(n594), .Z(po0)); - OR2 U560 ( .A(n595), .B(n596), .Z(n594)); - AN2 U561 ( .A(n597), .B(pi8), .Z(n596)); - AN2 U562 ( .A(n598), .B(n381), .Z(n597)); - AN2 U563 ( .A(pi0), .B(n385), .Z(n381)); - AN2 U564 ( .A(n507), .B(n487), .Z(n598)); - AN2 U565 ( .A(n528), .B(n426), .Z(n595)); - AN2 U566 ( .A(pi6), .B(n599), .Z(n528)); - IV2 U567 ( .A(n600), .Z(n599)); - OR2 U568 ( .A(n601), .B(n361), .Z(n600)); - AN2 U569 ( .A(n602), .B(n603), .Z(n601)); - AN2 U570 ( .A(n604), .B(n605), .Z(n603)); - OR2 U571 ( .A(pi7), .B(n606), .Z(n605)); - OR2 U572 ( .A(n607), .B(n387), .Z(n606)); - OR2 U573 ( .A(n378), .B(n487), .Z(n604)); - AN2 U574 ( .A(n608), .B(n609), .Z(n602)); - OR2 U575 ( .A(pi2), .B(n415), .Z(n608)); - OR2 U576 ( .A(n610), .B(n611), .Z(n593)); - AN2 U577 ( .A(pi9), .B(n612), .Z(n611)); - OR2 U578 ( .A(n613), .B(n614), .Z(n612)); - OR2 U579 ( .A(n433), .B(n615), .Z(n614)); - AN2 U580 ( .A(n527), .B(n426), .Z(n615)); - OR2 U581 ( .A(n616), .B(n617), .Z(n527)); - AN2 U582 ( .A(n618), .B(n361), .Z(n617)); - OR2 U583 ( .A(n619), .B(n620), .Z(n618)); - OR2 U584 ( .A(n621), .B(n622), .Z(n620)); - AN2 U585 ( .A(n592), .B(n362), .Z(n622)); - AN2 U586 ( .A(n385), .B(n623), .Z(n621)); - OR2 U587 ( .A(n624), .B(n625), .Z(n623)); - AN2 U588 ( .A(n626), .B(n415), .Z(n625)); - AN2 U589 ( .A(n507), .B(n523), .Z(n624)); - AN2 U590 ( .A(n473), .B(n557), .Z(n619)); - AN2 U591 ( .A(n523), .B(n387), .Z(n473)); - AN2 U592 ( .A(n569), .B(n387), .Z(n616)); - AN2 U593 ( .A(n578), .B(n627), .Z(n433)); - AN2 U594 ( .A(n378), .B(n475), .Z(n627)); - OR2 U595 ( .A(n628), .B(n629), .Z(n613)); - AN2 U596 ( .A(n526), .B(n426), .Z(n629)); - IV2 U597 ( .A(pi8), .Z(n426)); - AN2 U598 ( .A(n360), .B(n405), .Z(n526)); - AN2 U599 ( .A(pi8), .B(n630), .Z(n628)); - OR2 U600 ( .A(n631), .B(n439), .Z(n630)); - OR2 U601 ( .A(n632), .B(n633), .Z(n439)); - OR2 U602 ( .A(n634), .B(n635), .Z(n633)); - AN2 U603 ( .A(n636), .B(n378), .Z(n635)); - OR2 U604 ( .A(n637), .B(n360), .Z(n636)); - AN2 U605 ( .A(n387), .B(n475), .Z(n637)); - AN2 U606 ( .A(n638), .B(n475), .Z(n634)); - OR2 U607 ( .A(n639), .B(n640), .Z(n638)); - AN2 U608 ( .A(n558), .B(pi4), .Z(n639)); - OR2 U609 ( .A(n463), .B(n641), .Z(n632)); - AN2 U610 ( .A(n642), .B(n385), .Z(n641)); - AN2 U611 ( .A(n557), .B(n361), .Z(n642)); - AN2 U612 ( .A(n361), .B(n578), .Z(n463)); - AN2 U613 ( .A(n403), .B(n361), .Z(n631)); - IV2 U614 ( .A(n609), .Z(n403)); - OR2 U615 ( .A(n385), .B(n378), .Z(n609)); - AN2 U616 ( .A(n643), .B(n530), .Z(n610)); - OR2 U617 ( .A(n644), .B(n645), .Z(n643)); - OR2 U618 ( .A(n646), .B(n647), .Z(n645)); - OR2 U619 ( .A(n648), .B(n649), .Z(n647)); - AN2 U620 ( .A(n537), .B(n385), .Z(n649)); - IV2 U621 ( .A(n387), .Z(n385)); - OR2 U622 ( .A(n650), .B(n651), .Z(n537)); - AN2 U623 ( .A(n396), .B(pi6), .Z(n651)); - AN2 U624 ( .A(n400), .B(n475), .Z(n650)); - AN2 U625 ( .A(n652), .B(n387), .Z(n648)); - OR2 U626 ( .A(n653), .B(n654), .Z(n387)); - OR2 U627 ( .A(n655), .B(n656), .Z(n654)); - OR2 U628 ( .A(n657), .B(n658), .Z(n656)); - AN2 U629 ( .A(n360), .B(n573), .Z(n658)); - OR2 U630 ( .A(n659), .B(n660), .Z(n573)); - AN2 U631 ( .A(n405), .B(n578), .Z(n660)); - AN2 U632 ( .A(n396), .B(n661), .Z(n659)); - OR2 U633 ( .A(n405), .B(n557), .Z(n661)); - AN2 U634 ( .A(n475), .B(pi7), .Z(n405)); - IV2 U635 ( .A(n607), .Z(n396)); - OR2 U636 ( .A(pi5), .B(pi4), .Z(n607)); - AN2 U637 ( .A(n640), .B(n417), .Z(n657)); - AN2 U638 ( .A(n572), .B(n362), .Z(n655)); - OR2 U639 ( .A(n662), .B(n663), .Z(n572)); - OR2 U640 ( .A(n664), .B(n665), .Z(n663)); - AN2 U641 ( .A(n578), .B(n557), .Z(n665)); - AN2 U642 ( .A(n417), .B(n626), .Z(n664)); - AN2 U643 ( .A(n507), .B(n530), .Z(n662)); - OR2 U644 ( .A(n666), .B(n667), .Z(n653)); - OR2 U645 ( .A(n668), .B(n669), .Z(n667)); - AN2 U646 ( .A(n670), .B(n545), .Z(n669)); - OR2 U647 ( .A(n400), .B(n671), .Z(n545)); - AN2 U648 ( .A(pi9), .B(n414), .Z(n671)); - AN2 U649 ( .A(n378), .B(n414), .Z(n400)); - IV2 U650 ( .A(pi7), .Z(n378)); - OR2 U651 ( .A(pi0), .B(pi2), .Z(n670)); - AN2 U652 ( .A(n672), .B(n547), .Z(n668)); - AN2 U653 ( .A(n475), .B(n530), .Z(n547)); - IV2 U654 ( .A(pi9), .Z(n530)); - AN2 U655 ( .A(n361), .B(n415), .Z(n672)); - AN2 U656 ( .A(n558), .B(n569), .Z(n666)); - AN2 U657 ( .A(n557), .B(n417), .Z(n569)); - OR2 U658 ( .A(n673), .B(n674), .Z(n652)); - OR2 U659 ( .A(n445), .B(n675), .Z(n674)); - AN2 U660 ( .A(n577), .B(pi2), .Z(n675)); - AN2 U661 ( .A(n523), .B(n447), .Z(n445)); - OR2 U662 ( .A(n577), .B(n507), .Z(n447)); - AN2 U663 ( .A(n475), .B(n415), .Z(n577)); - AN2 U664 ( .A(n578), .B(pi0), .Z(n673)); - IV2 U665 ( .A(n487), .Z(n578)); - OR2 U666 ( .A(n415), .B(n523), .Z(n487)); - AN2 U667 ( .A(n507), .B(pi0), .Z(n646)); - AN2 U668 ( .A(pi6), .B(pi7), .Z(n507)); - OR2 U669 ( .A(n676), .B(n677), .Z(n644)); - OR2 U670 ( .A(n678), .B(n679), .Z(n677)); - AN2 U671 ( .A(n444), .B(n360), .Z(n679)); - IV2 U672 ( .A(n401), .Z(n360)); - OR2 U673 ( .A(n362), .B(n361), .Z(n401)); - AN2 U674 ( .A(pi6), .B(n417), .Z(n444)); - AN2 U675 ( .A(n680), .B(n557), .Z(n678)); - IV2 U676 ( .A(n626), .Z(n557)); - OR2 U677 ( .A(pi7), .B(n475), .Z(n626)); - AN2 U678 ( .A(n681), .B(n362), .Z(n680)); - OR2 U679 ( .A(n682), .B(n414), .Z(n681)); - AN2 U680 ( .A(n417), .B(n361), .Z(n682)); - IV2 U681 ( .A(pi0), .Z(n361)); - AN2 U682 ( .A(pi7), .B(n683), .Z(n676)); - OR2 U683 ( .A(n684), .B(n685), .Z(n683)); - OR2 U684 ( .A(n686), .B(n687), .Z(n685)); - AN2 U685 ( .A(n592), .B(n558), .Z(n687)); - IV2 U686 ( .A(n565), .Z(n558)); - OR2 U687 ( .A(pi0), .B(n362), .Z(n565)); - AN2 U688 ( .A(n475), .B(n414), .Z(n592)); - IV2 U689 ( .A(n515), .Z(n414)); - OR2 U690 ( .A(pi5), .B(n415), .Z(n515)); - IV2 U691 ( .A(pi6), .Z(n475)); - AN2 U692 ( .A(n640), .B(n523), .Z(n686)); - IV2 U693 ( .A(pi5), .Z(n523)); - AN2 U694 ( .A(n362), .B(pi0), .Z(n640)); - IV2 U695 ( .A(pi2), .Z(n362)); - AN2 U696 ( .A(n417), .B(pi2), .Z(n684)); - AN2 U697 ( .A(n415), .B(pi5), .Z(n417)); - IV2 U698 ( .A(pi4), .Z(n415)); - -endmodule - -module IV2(A, Z); - input A; - output Z; - - assign Z = ~A; -endmodule - -module AN2(A, B, Z); - input A, B; - output Z; - - assign Z = A & B; -endmodule - -module OR2(A, B, Z); - input A, B; - output Z; - - assign Z = A | B; -endmodule diff --git a/yosys/examples/smtbmc/glift/alu2.ys b/yosys/examples/smtbmc/glift/alu2.ys deleted file mode 100644 index b1671752e9b..00000000000 --- a/yosys/examples/smtbmc/glift/alu2.ys +++ /dev/null @@ -1,41 +0,0 @@ -read_verilog alu2.v -techmap -flatten -select alu2_lev2 -glift -create-instrumented-model -techmap -opt -rename alu2_lev2 uut -cd .. -delete [AIONX][NVXR]2 -read_verilog alu2.v -techmap -flatten -select alu2_lev2 -glift -create-precise-model -techmap -opt -rename alu2_lev2 spec -cd .. -delete [AIONX][NVXR]2 - -design -push-copy -miter -equiv spec uut miter -flatten -delete uut spec -techmap -opt -stat miter -qbfsat -O2 -write-solution alu2.soln -solver yices -timeout 3600 -nocleanup -assume-outputs -assume-negative-polarity miter -design -pop -stat - -copy uut solved -qbfsat -specialize-from-file alu2.soln solved -opt solved -miter -equiv spec solved satmiter -flatten -sat -prove trigger 0 satmiter -delete satmiter -stat -shell diff --git a/yosys/examples/smtbmc/glift/alu4.v b/yosys/examples/smtbmc/glift/alu4.v deleted file mode 100755 index e110612e53f..00000000000 --- a/yosys/examples/smtbmc/glift/alu4.v +++ /dev/null @@ -1,802 +0,0 @@ -module alu4_lev2(pi00, pi01, pi02, pi03, pi04, pi05, pi06, pi07, pi08, pi09, - pi10, pi11, pi12, pi13, po0, po1, po2, po3, po4, po5, po6, po7); - -input pi00, pi01, pi02, pi03, pi04, pi05, pi06, pi07, pi08, pi09, - pi10, pi11, pi12, pi13; - -output po0, po1, po2, po3, po4, po5, po6, po7; - -wire n705, n706, n707, n708, n709, n710, n711, n712, n713, n714, - n715, n716, n717, n718, n719, n720, n721, n722, n723, n724, - n725, n726, n727, n728, n729, n730, n731, n732, n733, n734, - n735, n736, n737, n738, n739, n740, n741, n742, n743, n744, - n745, n746, n747, n748, n749, n750, n751, n752, n753, n754, - n755, n756, n757, n758, n759, n760, n761, n762, n763, n764, - n765, n766, n767, n768, n769, n770, n771, n772, n773, n774, - n775, n776, n777, n778, n779, n780, n781, n782, n783, n784, - n785, n786, n787, n788, n789, n790, n791, n792, n793, n794, - n795, n796, n797, n798, n799, n800, n801, n802, n803, n804, - n805, n806, n807, n808, n809, n810, n811, n812, n813, n814, - n815, n816, n817, n818, n819, n820, n821, n822, n823, n824, - n825, n826, n827, n828, n829, n830, n831, n832, n833, n834, - n835, n836, n837, n838, n839, n840, n841, n842, n843, n844, - n845, n846, n847, n848, n849, n850, n851, n852, n853, n854, - n855, n856, n857, n858, n859, n860, n861, n862, n863, n864, - n865, n866, n867, n868, n869, n870, n871, n872, n873, n874, - n875, n876, n877, n878, n879, n880, n881, n882, n883, n884, - n885, n886, n887, n888, n889, n890, n891, n892, n893, n894, - n895, n896, n897, n898, n899, n900, n901, n902, n903, n904, - n905, n906, n907, n908, n909, n910, n911, n912, n913, n914, - n915, n916, n917, n918, n919, n920, n921, n922, n923, n924, - n925, n926, n927, n928, n929, n930, n931, n932, n933, n934, - n935, n936, n937, n938, n939, n940, n941, n942, n943, n944, - n945, n946, n947, n948, n949, n950, n951, n952, n953, n954, - n955, n956, n957, n958, n959, n960, n961, n962, n963, n964, - n965, n966, n967, n968, n969, n970, n971, n972, n973, n974, - n975, n976, n977, n978, n979, n980, n981, n982, n983, n984, - n985, n986, n987, n988, n989, n990, n991, n992, n993, n994, - n995, n996, n997, n998, n999, n1000, n1001, n1002, n1003, n1004, - n1005, n1006, n1007, n1008, n1009, n1010, n1011, n1012, n1013, n1014, - n1015, n1016, n1017, n1018, n1019, n1020, n1021, n1022, n1023, n1024, - n1025, n1026, n1027, n1028, n1029, n1030, n1031, n1032, n1033, n1034, - n1035, n1036, n1037, n1038, n1039, n1040, n1041, n1042, n1043, n1044, - n1045, n1046, n1047, n1048, n1049, n1050, n1051, n1052, n1053, n1054, - n1055, n1056, n1057, n1058, n1059, n1060, n1061, n1062, n1063, n1064, - n1065, n1066, n1067, n1068, n1069, n1070, n1071, n1072, n1073, n1074, - n1075, n1076, n1077, n1078, n1079, n1080, n1081, n1082, n1083, n1084, - n1085, n1086, n1087, n1088, n1089, n1090, n1091, n1092, n1093, n1094, - n1095, n1096, n1097, n1098, n1099, n1100, n1101, n1102, n1103, n1104, - n1105, n1106, n1107, n1108, n1109, n1110, n1111, n1112, n1113, n1114, - n1115, n1116, n1117, n1118, n1119, n1120, n1121, n1122, n1123, n1124, - n1125, n1126, n1127, n1128, n1129, n1130, n1131, n1132, n1133, n1134, - n1135, n1136, n1137, n1138, n1139, n1140, n1141, n1142, n1143, n1144, - n1145, n1146, n1147, n1148, n1149, n1150, n1151, n1152, n1153, n1154, - n1155, n1156, n1157, n1158, n1159, n1160, n1161, n1162, n1163, n1164, - n1165, n1166, n1167, n1168, n1169, n1170, n1171, n1172, n1173, n1174, - n1175, n1176, n1177, n1178, n1179, n1180, n1181, n1182, n1183, n1184, - n1185, n1186, n1187, n1188, n1189, n1190, n1191, n1192, n1193, n1194, - n1195, n1196, n1197, n1198, n1199, n1200, n1201, n1202, n1203, n1204, - n1205, n1206, n1207, n1208, n1209, n1210, n1211, n1212, n1213, n1214, - n1215, n1216, n1217, n1218, n1219, n1220, n1221, n1222, n1223, n1224, - n1225, n1226, n1227, n1228, n1229, n1230, n1231, n1232, n1233, n1234, - n1235, n1236, n1237, n1238, n1239, n1240, n1241, n1242, n1243, n1244, - n1245, n1246, n1247, n1248, n1249, n1250, n1251, n1252, n1253, n1254, - n1255, n1256, n1257, n1258, n1259, n1260, n1261, n1262, n1263, n1264, - n1265, n1266, n1267, n1268, n1269, n1270, n1271, n1272, n1273, n1274, - n1275, n1276, n1277, n1278, n1279, n1280, n1281, n1282, n1283, n1284, - n1285, n1286, n1287, n1288, n1289, n1290, n1291, n1292, n1293, n1294, - n1295, n1296, n1297, n1298, n1299, n1300, n1301, n1302, n1303, n1304, - n1305, n1306, n1307, n1308, n1309, n1310, n1311, n1312, n1313, n1314, - n1315, n1316, n1317, n1318, n1319, n1320, n1321, n1322, n1323, n1324, - n1325, n1326, n1327, n1328, n1329, n1330, n1331, n1332, n1333, n1334, - n1335, n1336, n1337, n1338, n1339, n1340, n1341, n1342, n1343, n1344, - n1345, n1346, n1347, n1348, n1349, n1350, n1351, n1352, n1353, n1354, - n1355, n1356, n1357, n1358, n1359, n1360, n1361, n1362, n1363, n1364, - n1365, n1366, n1367, n1368, n1369, n1370, n1371, n1372, n1373, n1374, - n1375, n1376, n1377, n1378, n1379, n1380, n1381, n1382, n1383, n1384, - n1385, n1386, n1387, n1388, n1389, n1390, n1391, n1392, n1393, n1394, - n1395, n1396; - - AN2 U712 ( .A(n705), .B(po4), .Z(po7)); - OR2 U713 ( .A(n706), .B(n707), .Z(n705)); - AN2 U714 ( .A(n708), .B(n709), .Z(n707)); - OR2 U715 ( .A(n710), .B(n711), .Z(n708)); - AN2 U716 ( .A(n712), .B(n713), .Z(n711)); - AN2 U717 ( .A(n714), .B(n715), .Z(n710)); - AN2 U718 ( .A(n716), .B(n717), .Z(n714)); - AN2 U719 ( .A(n718), .B(n719), .Z(n706)); - OR2 U720 ( .A(n720), .B(n712), .Z(n719)); - OR2 U721 ( .A(n721), .B(n722), .Z(n712)); - AN2 U722 ( .A(n723), .B(n724), .Z(n722)); - AN2 U723 ( .A(n725), .B(n726), .Z(n721)); - OR2 U724 ( .A(n724), .B(n727), .Z(n726)); - AN2 U725 ( .A(n727), .B(n723), .Z(n720)); - OR2 U726 ( .A(n728), .B(n729), .Z(po6)); - AN2 U727 ( .A(pi13), .B(n730), .Z(n729)); - OR2 U728 ( .A(n731), .B(n732), .Z(n730)); - OR2 U729 ( .A(n733), .B(n734), .Z(n732)); - OR2 U730 ( .A(n735), .B(n736), .Z(n734)); - AN2 U731 ( .A(n737), .B(n738), .Z(n736)); - OR2 U732 ( .A(n739), .B(n740), .Z(n737)); - OR2 U733 ( .A(n741), .B(n742), .Z(n740)); - AN2 U734 ( .A(n743), .B(n744), .Z(n742)); - OR2 U735 ( .A(n745), .B(n746), .Z(n743)); - AN2 U736 ( .A(pi03), .B(n747), .Z(n745)); - AN2 U737 ( .A(n748), .B(n749), .Z(n741)); - AN2 U738 ( .A(n750), .B(n751), .Z(n748)); - AN2 U739 ( .A(pi11), .B(n752), .Z(n735)); - OR2 U740 ( .A(n753), .B(n754), .Z(n752)); - OR2 U741 ( .A(n755), .B(n756), .Z(n754)); - AN2 U742 ( .A(n757), .B(n747), .Z(n756)); - OR2 U743 ( .A(n758), .B(n759), .Z(n757)); - IV2 U744 ( .A(n760), .Z(n755)); - AN2 U745 ( .A(n761), .B(n762), .Z(n753)); - OR2 U746 ( .A(n763), .B(po5), .Z(n762)); - AN2 U747 ( .A(n764), .B(n765), .Z(n763)); - AN2 U748 ( .A(n766), .B(n767), .Z(n733)); - OR2 U749 ( .A(n768), .B(n769), .Z(n767)); - AN2 U750 ( .A(n770), .B(n771), .Z(n768)); - IV2 U751 ( .A(n772), .Z(n766)); - OR2 U752 ( .A(n773), .B(n774), .Z(n731)); - AN2 U753 ( .A(n775), .B(n776), .Z(n774)); - AN2 U754 ( .A(n777), .B(n778), .Z(n775)); - AN2 U755 ( .A(n779), .B(n780), .Z(n773)); - AN2 U756 ( .A(n781), .B(n782), .Z(n779)); - AN2 U757 ( .A(n783), .B(n781), .Z(n728)); - AN2 U758 ( .A(n782), .B(n784), .Z(n783)); - OR2 U759 ( .A(n785), .B(n786), .Z(po3)); - OR2 U760 ( .A(n787), .B(n788), .Z(n786)); - OR2 U761 ( .A(n789), .B(n790), .Z(n788)); - OR2 U762 ( .A(n791), .B(n792), .Z(n790)); - AN2 U763 ( .A(n793), .B(n782), .Z(n792)); - AN2 U764 ( .A(n794), .B(n795), .Z(n791)); - OR2 U765 ( .A(n796), .B(n797), .Z(n789)); - IV2 U766 ( .A(n798), .Z(n797)); - OR2 U767 ( .A(n799), .B(n778), .Z(n798)); - AN2 U768 ( .A(n778), .B(n799), .Z(n796)); - OR2 U769 ( .A(n800), .B(n801), .Z(n799)); - IV2 U770 ( .A(n802), .Z(n778)); - OR2 U771 ( .A(n803), .B(n804), .Z(n802)); - AN2 U772 ( .A(n805), .B(n806), .Z(n803)); - AN2 U773 ( .A(n807), .B(n808), .Z(n806)); - AN2 U774 ( .A(n809), .B(n810), .Z(n808)); - OR2 U775 ( .A(pi11), .B(n811), .Z(n810)); - AN2 U776 ( .A(n812), .B(n813), .Z(n811)); - AN2 U777 ( .A(n814), .B(n815), .Z(n813)); - OR2 U778 ( .A(n782), .B(n816), .Z(n815)); - OR2 U779 ( .A(n817), .B(n818), .Z(n814)); - OR2 U780 ( .A(n819), .B(n820), .Z(n818)); - AN2 U781 ( .A(n750), .B(n821), .Z(n820)); - AN2 U782 ( .A(n749), .B(n747), .Z(n819)); - IV2 U783 ( .A(n821), .Z(n749)); - AN2 U784 ( .A(n822), .B(n823), .Z(n812)); - OR2 U785 ( .A(n824), .B(n825), .Z(n823)); - OR2 U786 ( .A(n826), .B(n827), .Z(n822)); - AN2 U787 ( .A(pi10), .B(n828), .Z(n826)); - OR2 U788 ( .A(n829), .B(n830), .Z(n828)); - OR2 U789 ( .A(n831), .B(n738), .Z(n809)); - AN2 U790 ( .A(n832), .B(n833), .Z(n831)); - AN2 U791 ( .A(n834), .B(n760), .Z(n833)); - OR2 U792 ( .A(n817), .B(n835), .Z(n760)); - OR2 U793 ( .A(pi03), .B(n836), .Z(n835)); - OR2 U794 ( .A(n817), .B(n837), .Z(n834)); - OR2 U795 ( .A(n715), .B(n827), .Z(n837)); - IV2 U796 ( .A(n836), .Z(n715)); - AN2 U797 ( .A(n838), .B(n839), .Z(n832)); - OR2 U798 ( .A(n765), .B(n840), .Z(n839)); - OR2 U799 ( .A(n841), .B(n825), .Z(n840)); - OR2 U800 ( .A(n816), .B(n842), .Z(n838)); - OR2 U801 ( .A(n843), .B(n844), .Z(n842)); - AN2 U802 ( .A(n845), .B(n846), .Z(n844)); - OR2 U803 ( .A(n847), .B(n848), .Z(n845)); - AN2 U804 ( .A(n758), .B(n747), .Z(n848)); - IV2 U805 ( .A(n849), .Z(n758)); - AN2 U806 ( .A(n750), .B(n849), .Z(n847)); - AN2 U807 ( .A(n849), .B(n759), .Z(n843)); - OR2 U808 ( .A(n850), .B(n851), .Z(n849)); - AN2 U809 ( .A(n852), .B(n853), .Z(n850)); - IV2 U810 ( .A(n854), .Z(n816)); - AN2 U811 ( .A(n855), .B(n856), .Z(n807)); - OR2 U812 ( .A(n857), .B(n858), .Z(n856)); - OR2 U813 ( .A(n859), .B(n860), .Z(n858)); - AN2 U814 ( .A(n861), .B(n739), .Z(n859)); - OR2 U815 ( .A(n862), .B(n863), .Z(n739)); - AN2 U816 ( .A(n759), .B(n795), .Z(n862)); - OR2 U817 ( .A(n846), .B(n864), .Z(n861)); - IV2 U818 ( .A(n865), .Z(n864)); - AN2 U819 ( .A(n795), .B(n863), .Z(n865)); - IV2 U820 ( .A(n759), .Z(n846)); - OR2 U821 ( .A(n866), .B(n867), .Z(n759)); - AN2 U822 ( .A(n868), .B(po5), .Z(n867)); - AN2 U823 ( .A(n750), .B(n869), .Z(n866)); - OR2 U824 ( .A(n825), .B(n870), .Z(n855)); - OR2 U825 ( .A(n871), .B(n872), .Z(n870)); - AN2 U826 ( .A(n764), .B(n873), .Z(n872)); - IV2 U827 ( .A(po5), .Z(n873)); - AN2 U828 ( .A(n841), .B(po4), .Z(n871)); - OR2 U829 ( .A(n874), .B(po5), .Z(po4)); - IV2 U830 ( .A(n764), .Z(n841)); - OR2 U831 ( .A(n875), .B(n724), .Z(n764)); - AN2 U832 ( .A(n876), .B(n877), .Z(n875)); - AN2 U833 ( .A(n878), .B(n879), .Z(n805)); - AN2 U834 ( .A(n880), .B(n881), .Z(n879)); - OR2 U835 ( .A(n782), .B(n882), .Z(n881)); - OR2 U836 ( .A(n781), .B(n883), .Z(n882)); - IV2 U837 ( .A(n884), .Z(n781)); - OR2 U838 ( .A(n795), .B(n885), .Z(n880)); - AN2 U839 ( .A(n886), .B(n887), .Z(n878)); - OR2 U840 ( .A(pi03), .B(n888), .Z(n887)); - AN2 U841 ( .A(n889), .B(n890), .Z(n888)); - IV2 U842 ( .A(n891), .Z(n890)); - AN2 U843 ( .A(n830), .B(n892), .Z(n891)); - OR2 U844 ( .A(n893), .B(n894), .Z(n830)); - IV2 U845 ( .A(n895), .Z(n894)); - OR2 U846 ( .A(n746), .B(n750), .Z(n895)); - AN2 U847 ( .A(n750), .B(n746), .Z(n893)); - OR2 U848 ( .A(n896), .B(n897), .Z(n746)); - AN2 U849 ( .A(pi02), .B(n898), .Z(n896)); - IV2 U850 ( .A(n747), .Z(n750)); - OR2 U851 ( .A(n899), .B(n900), .Z(n747)); - AN2 U852 ( .A(n901), .B(n771), .Z(n900)); - OR2 U853 ( .A(pi03), .B(n795), .Z(n771)); - AN2 U854 ( .A(n902), .B(n903), .Z(n899)); - OR2 U855 ( .A(n904), .B(n905), .Z(n903)); - OR2 U856 ( .A(n906), .B(n907), .Z(n905)); - AN2 U857 ( .A(n782), .B(n892), .Z(n907)); - AN2 U858 ( .A(n769), .B(n751), .Z(n906)); - AN2 U859 ( .A(po5), .B(n908), .Z(n904)); - OR2 U860 ( .A(n909), .B(n772), .Z(n889)); - AN2 U861 ( .A(n910), .B(n911), .Z(n909)); - OR2 U862 ( .A(n912), .B(n795), .Z(n911)); - OR2 U863 ( .A(n782), .B(n770), .Z(n910)); - OR2 U864 ( .A(n827), .B(n913), .Z(n886)); - OR2 U865 ( .A(n914), .B(n772), .Z(n913)); - OR2 U866 ( .A(n915), .B(n916), .Z(n914)); - AN2 U867 ( .A(n912), .B(n795), .Z(n916)); - IV2 U868 ( .A(n770), .Z(n912)); - AN2 U869 ( .A(n782), .B(n770), .Z(n915)); - OR2 U870 ( .A(n917), .B(n918), .Z(n770)); - AN2 U871 ( .A(n919), .B(n920), .Z(n917)); - IV2 U872 ( .A(n795), .Z(n782)); - OR2 U873 ( .A(n921), .B(n922), .Z(n787)); - AN2 U874 ( .A(n923), .B(n824), .Z(n922)); - AN2 U875 ( .A(n924), .B(n925), .Z(n923)); - OR2 U876 ( .A(n926), .B(n927), .Z(n925)); - AN2 U877 ( .A(pi11), .B(pi03), .Z(n926)); - AN2 U878 ( .A(pi07), .B(n928), .Z(n921)); - OR2 U879 ( .A(n929), .B(n930), .Z(n928)); - AN2 U880 ( .A(n931), .B(n804), .Z(n929)); - OR2 U881 ( .A(n932), .B(n933), .Z(n931)); - AN2 U882 ( .A(n854), .B(n795), .Z(n933)); - AN2 U883 ( .A(n934), .B(n827), .Z(n932)); - OR2 U884 ( .A(n935), .B(n936), .Z(n785)); - OR2 U885 ( .A(n937), .B(n938), .Z(n936)); - AN2 U886 ( .A(n939), .B(n940), .Z(n938)); - OR2 U887 ( .A(n941), .B(n942), .Z(n940)); - OR2 U888 ( .A(n769), .B(n943), .Z(n942)); - AN2 U889 ( .A(n874), .B(n944), .Z(n943)); - AN2 U890 ( .A(n795), .B(pi03), .Z(n769)); - OR2 U891 ( .A(n945), .B(n946), .Z(n795)); - OR2 U892 ( .A(n947), .B(n948), .Z(n946)); - AN2 U893 ( .A(n949), .B(n824), .Z(n948)); - AN2 U894 ( .A(n950), .B(n765), .Z(n947)); - IV2 U895 ( .A(n874), .Z(n765)); - OR2 U896 ( .A(n951), .B(n952), .Z(n945)); - OR2 U897 ( .A(n953), .B(n954), .Z(n952)); - AN2 U898 ( .A(n955), .B(n827), .Z(n954)); - OR2 U899 ( .A(n956), .B(n957), .Z(n955)); - AN2 U900 ( .A(n958), .B(n784), .Z(n956)); - AN2 U901 ( .A(pi07), .B(n959), .Z(n958)); - AN2 U902 ( .A(po5), .B(n960), .Z(n953)); - OR2 U903 ( .A(n961), .B(n962), .Z(n960)); - AN2 U904 ( .A(n892), .B(n963), .Z(n962)); - AN2 U905 ( .A(n964), .B(n965), .Z(n961)); - AN2 U906 ( .A(pi13), .B(n966), .Z(n951)); - OR2 U907 ( .A(n967), .B(n968), .Z(n966)); - OR2 U908 ( .A(n969), .B(n970), .Z(n968)); - AN2 U909 ( .A(n971), .B(pi02), .Z(n970)); - AN2 U910 ( .A(n972), .B(n973), .Z(n969)); - AN2 U911 ( .A(n974), .B(n975), .Z(n972)); - OR2 U912 ( .A(n874), .B(n959), .Z(n975)); - AN2 U913 ( .A(n827), .B(n824), .Z(n874)); - IV2 U914 ( .A(pi03), .Z(n827)); - OR2 U915 ( .A(n964), .B(n976), .Z(n974)); - AN2 U916 ( .A(pi03), .B(n824), .Z(n976)); - IV2 U917 ( .A(pi07), .Z(n824)); - IV2 U918 ( .A(n959), .Z(n964)); - OR2 U919 ( .A(n977), .B(n978), .Z(n959)); - AN2 U920 ( .A(n979), .B(pi02), .Z(n978)); - AN2 U921 ( .A(n980), .B(n717), .Z(n977)); - OR2 U922 ( .A(n979), .B(pi02), .Z(n980)); - AN2 U923 ( .A(n981), .B(po5), .Z(n967)); - AN2 U924 ( .A(po5), .B(n982), .Z(n941)); - AN2 U925 ( .A(pi03), .B(pi07), .Z(po5)); - AN2 U926 ( .A(n983), .B(pi03), .Z(n935)); - OR2 U927 ( .A(n984), .B(n985), .Z(po2)); - OR2 U928 ( .A(n986), .B(n987), .Z(n985)); - OR2 U929 ( .A(n988), .B(n989), .Z(n987)); - OR2 U930 ( .A(n990), .B(n991), .Z(n989)); - AN2 U931 ( .A(n793), .B(n992), .Z(n991)); - AN2 U932 ( .A(n794), .B(n993), .Z(n990)); - OR2 U933 ( .A(n994), .B(n995), .Z(n988)); - AN2 U934 ( .A(n777), .B(n801), .Z(n995)); - IV2 U935 ( .A(n800), .Z(n777)); - AN2 U936 ( .A(n776), .B(n800), .Z(n994)); - OR2 U937 ( .A(n996), .B(n804), .Z(n800)); - AN2 U938 ( .A(n997), .B(n998), .Z(n996)); - AN2 U939 ( .A(n999), .B(n1000), .Z(n998)); - AN2 U940 ( .A(n1001), .B(n1002), .Z(n1000)); - OR2 U941 ( .A(n1003), .B(n817), .Z(n1002)); - AN2 U942 ( .A(n1004), .B(n836), .Z(n1003)); - OR2 U943 ( .A(pi00), .B(n1005), .Z(n836)); - OR2 U944 ( .A(pi02), .B(pi01), .Z(n1005)); - AN2 U945 ( .A(n1006), .B(n1007), .Z(n1004)); - OR2 U946 ( .A(pi11), .B(n1008), .Z(n1007)); - AN2 U947 ( .A(n1009), .B(n821), .Z(n1008)); - OR2 U948 ( .A(n898), .B(n1010), .Z(n821)); - OR2 U949 ( .A(n1011), .B(n851), .Z(n1009)); - AN2 U950 ( .A(n1012), .B(n1013), .Z(n1011)); - OR2 U951 ( .A(n738), .B(n1014), .Z(n1006)); - OR2 U952 ( .A(n1015), .B(n1016), .Z(n1014)); - AN2 U953 ( .A(n713), .B(n1017), .Z(n1015)); - OR2 U954 ( .A(n1018), .B(n1019), .Z(n1001)); - OR2 U955 ( .A(n744), .B(n1020), .Z(n1019)); - OR2 U956 ( .A(n1021), .B(n1022), .Z(n1018)); - AN2 U957 ( .A(n717), .B(n1023), .Z(n1022)); - AN2 U958 ( .A(n863), .B(n1024), .Z(n1021)); - OR2 U959 ( .A(n1025), .B(n1026), .Z(n1024)); - OR2 U960 ( .A(n992), .B(n852), .Z(n1026)); - IV2 U961 ( .A(n1027), .Z(n1025)); - OR2 U962 ( .A(n1028), .B(n1027), .Z(n863)); - OR2 U963 ( .A(n1029), .B(n1030), .Z(n1027)); - AN2 U964 ( .A(n1031), .B(n1032), .Z(n1029)); - AN2 U965 ( .A(n1033), .B(n993), .Z(n1028)); - AN2 U966 ( .A(n885), .B(n1034), .Z(n999)); - OR2 U967 ( .A(n825), .B(n1035), .Z(n1034)); - OR2 U968 ( .A(n1036), .B(n1037), .Z(n1035)); - AN2 U969 ( .A(n1038), .B(n1039), .Z(n1037)); - IV2 U970 ( .A(n724), .Z(n1039)); - OR2 U971 ( .A(n877), .B(n738), .Z(n1038)); - IV2 U972 ( .A(n876), .Z(n1036)); - OR2 U973 ( .A(n1040), .B(n884), .Z(n885)); - OR2 U974 ( .A(n1041), .B(n1042), .Z(n884)); - OR2 U975 ( .A(n993), .B(n1032), .Z(n1042)); - AN2 U976 ( .A(n1043), .B(n1044), .Z(n997)); - AN2 U977 ( .A(n1045), .B(n1046), .Z(n1044)); - OR2 U978 ( .A(pi02), .B(n1047), .Z(n1046)); - AN2 U979 ( .A(n1048), .B(n1049), .Z(n1047)); - OR2 U980 ( .A(n876), .B(n1050), .Z(n1049)); - OR2 U981 ( .A(n717), .B(n825), .Z(n1050)); - AN2 U982 ( .A(n1051), .B(n1052), .Z(n1048)); - OR2 U983 ( .A(n1053), .B(n1054), .Z(n1052)); - OR2 U984 ( .A(n1055), .B(n772), .Z(n1051)); - AN2 U985 ( .A(n1056), .B(n1057), .Z(n1055)); - OR2 U986 ( .A(n1058), .B(n993), .Z(n1057)); - OR2 U987 ( .A(n992), .B(n919), .Z(n1056)); - OR2 U988 ( .A(n1059), .B(n1016), .Z(n1045)); - AN2 U989 ( .A(n1060), .B(n1061), .Z(n1059)); - AN2 U990 ( .A(n1062), .B(n1063), .Z(n1061)); - OR2 U991 ( .A(n876), .B(n1064), .Z(n1062)); - OR2 U992 ( .A(pi06), .B(n825), .Z(n1064)); - OR2 U993 ( .A(n1065), .B(n725), .Z(n876)); - AN2 U994 ( .A(n718), .B(n1066), .Z(n1065)); - AN2 U995 ( .A(n1067), .B(n1068), .Z(n1060)); - OR2 U996 ( .A(n772), .B(n1069), .Z(n1068)); - OR2 U997 ( .A(n1070), .B(n1071), .Z(n1069)); - AN2 U998 ( .A(n1058), .B(n993), .Z(n1071)); - IV2 U999 ( .A(n919), .Z(n1058)); - AN2 U1000 ( .A(n992), .B(n919), .Z(n1070)); - OR2 U1001 ( .A(n1072), .B(n1073), .Z(n919)); - AN2 U1002 ( .A(n1074), .B(n1075), .Z(n1072)); - OR2 U1003 ( .A(n1054), .B(n1076), .Z(n1067)); - IV2 U1004 ( .A(n1053), .Z(n1076)); - AN2 U1005 ( .A(n1077), .B(n1078), .Z(n1053)); - OR2 U1006 ( .A(n897), .B(n851), .Z(n1078)); - IV2 U1007 ( .A(n1079), .Z(n1077)); - AN2 U1008 ( .A(n851), .B(n897), .Z(n1079)); - OR2 U1009 ( .A(n1080), .B(n1081), .Z(n897)); - AN2 U1010 ( .A(pi01), .B(n1082), .Z(n1080)); - AN2 U1011 ( .A(n1083), .B(n1084), .Z(n1043)); - OR2 U1012 ( .A(pi10), .B(n1085), .Z(n1084)); - OR2 U1013 ( .A(n1086), .B(n1087), .Z(n1085)); - AN2 U1014 ( .A(n1088), .B(n1089), .Z(n1087)); - AN2 U1015 ( .A(n852), .B(n898), .Z(n1088)); - IV2 U1016 ( .A(n1033), .Z(n852)); - AN2 U1017 ( .A(n1090), .B(n853), .Z(n1086)); - IV2 U1018 ( .A(n1089), .Z(n853)); - AN2 U1019 ( .A(n1091), .B(n1082), .Z(n1089)); - OR2 U1020 ( .A(n1031), .B(n1092), .Z(n1091)); - OR2 U1021 ( .A(n851), .B(n1033), .Z(n1090)); - OR2 U1022 ( .A(n1093), .B(n1094), .Z(n1033)); - AN2 U1023 ( .A(n868), .B(n724), .Z(n1094)); - AN2 U1024 ( .A(n851), .B(n869), .Z(n1093)); - IV2 U1025 ( .A(n898), .Z(n851)); - OR2 U1026 ( .A(n1095), .B(n1096), .Z(n898)); - AN2 U1027 ( .A(n901), .B(n920), .Z(n1096)); - OR2 U1028 ( .A(pi02), .B(n993), .Z(n920)); - AN2 U1029 ( .A(n902), .B(n1097), .Z(n1095)); - OR2 U1030 ( .A(n1098), .B(n1099), .Z(n1097)); - OR2 U1031 ( .A(n1100), .B(n1101), .Z(n1099)); - AN2 U1032 ( .A(n992), .B(n892), .Z(n1101)); - AN2 U1033 ( .A(n918), .B(n751), .Z(n1100)); - AN2 U1034 ( .A(n908), .B(n724), .Z(n1098)); - OR2 U1035 ( .A(n1102), .B(n992), .Z(n1083)); - IV2 U1036 ( .A(n993), .Z(n992)); - AN2 U1037 ( .A(n1103), .B(n1104), .Z(n1102)); - OR2 U1038 ( .A(n883), .B(n1105), .Z(n1104)); - IV2 U1039 ( .A(n1106), .Z(n883)); - IV2 U1040 ( .A(n801), .Z(n776)); - OR2 U1041 ( .A(n1107), .B(n1108), .Z(n801)); - OR2 U1042 ( .A(pi12), .B(n1109), .Z(n1108)); - OR2 U1043 ( .A(n1110), .B(n1111), .Z(n986)); - AN2 U1044 ( .A(n1112), .B(n717), .Z(n1111)); - AN2 U1045 ( .A(n924), .B(n1113), .Z(n1112)); - OR2 U1046 ( .A(n1114), .B(n927), .Z(n1113)); - AN2 U1047 ( .A(pi11), .B(pi02), .Z(n1114)); - AN2 U1048 ( .A(pi06), .B(n1115), .Z(n1110)); - OR2 U1049 ( .A(n1116), .B(n930), .Z(n1115)); - AN2 U1050 ( .A(n1117), .B(n804), .Z(n1116)); - OR2 U1051 ( .A(n1118), .B(n1119), .Z(n1117)); - AN2 U1052 ( .A(n854), .B(n993), .Z(n1119)); - AN2 U1053 ( .A(n934), .B(n1016), .Z(n1118)); - OR2 U1054 ( .A(n1120), .B(n1121), .Z(n984)); - OR2 U1055 ( .A(n937), .B(n1122), .Z(n1121)); - AN2 U1056 ( .A(n939), .B(n1123), .Z(n1122)); - OR2 U1057 ( .A(n1124), .B(n1125), .Z(n1123)); - OR2 U1058 ( .A(n918), .B(n1126), .Z(n1125)); - AN2 U1059 ( .A(n724), .B(n982), .Z(n1126)); - AN2 U1060 ( .A(n993), .B(pi02), .Z(n918)); - OR2 U1061 ( .A(n1127), .B(n1128), .Z(n993)); - OR2 U1062 ( .A(n1129), .B(n1130), .Z(n1128)); - AN2 U1063 ( .A(n949), .B(n717), .Z(n1130)); - AN2 U1064 ( .A(n950), .B(n877), .Z(n1129)); - IV2 U1065 ( .A(n727), .Z(n877)); - OR2 U1066 ( .A(n1131), .B(n1132), .Z(n1127)); - OR2 U1067 ( .A(n1133), .B(n1134), .Z(n1132)); - AN2 U1068 ( .A(n1135), .B(n1016), .Z(n1134)); - OR2 U1069 ( .A(n1136), .B(n957), .Z(n1135)); - AN2 U1070 ( .A(n1137), .B(n979), .Z(n1136)); - AN2 U1071 ( .A(n784), .B(pi06), .Z(n1137)); - AN2 U1072 ( .A(n724), .B(n1138), .Z(n1133)); - OR2 U1073 ( .A(n1139), .B(n1140), .Z(n1138)); - AN2 U1074 ( .A(n965), .B(n1141), .Z(n1139)); - AN2 U1075 ( .A(pi02), .B(pi06), .Z(n724)); - AN2 U1076 ( .A(pi13), .B(n1142), .Z(n1131)); - OR2 U1077 ( .A(n1143), .B(n1144), .Z(n1142)); - AN2 U1078 ( .A(n971), .B(pi01), .Z(n1144)); - AN2 U1079 ( .A(n1145), .B(n973), .Z(n1143)); - AN2 U1080 ( .A(n1146), .B(n1147), .Z(n1145)); - OR2 U1081 ( .A(n727), .B(n979), .Z(n1147)); - IV2 U1082 ( .A(n1141), .Z(n979)); - OR2 U1083 ( .A(n1148), .B(n1141), .Z(n1146)); - OR2 U1084 ( .A(n1149), .B(n1150), .Z(n1141)); - AN2 U1085 ( .A(n1151), .B(n1017), .Z(n1150)); - AN2 U1086 ( .A(pi05), .B(n1152), .Z(n1149)); - OR2 U1087 ( .A(n1151), .B(n1017), .Z(n1152)); - AN2 U1088 ( .A(pi02), .B(n717), .Z(n1148)); - AN2 U1089 ( .A(n944), .B(n727), .Z(n1124)); - AN2 U1090 ( .A(n1016), .B(n717), .Z(n727)); - IV2 U1091 ( .A(pi06), .Z(n717)); - IV2 U1092 ( .A(pi02), .Z(n1016)); - AN2 U1093 ( .A(n983), .B(pi02), .Z(n1120)); - OR2 U1094 ( .A(n1153), .B(n1154), .Z(po1)); - OR2 U1095 ( .A(n1155), .B(n1156), .Z(n1154)); - OR2 U1096 ( .A(n1157), .B(n1158), .Z(n1156)); - OR2 U1097 ( .A(n1159), .B(n1160), .Z(n1158)); - AN2 U1098 ( .A(n793), .B(n1105), .Z(n1160)); - AN2 U1099 ( .A(n794), .B(n1032), .Z(n1159)); - OR2 U1100 ( .A(n1161), .B(n1162), .Z(n1157)); - AN2 U1101 ( .A(n1163), .B(n1107), .Z(n1162)); - IV2 U1102 ( .A(n1164), .Z(n1161)); - OR2 U1103 ( .A(n1107), .B(n1163), .Z(n1164)); - AN2 U1104 ( .A(n1165), .B(n1166), .Z(n1163)); - OR2 U1105 ( .A(n1167), .B(n804), .Z(n1107)); - AN2 U1106 ( .A(n1168), .B(n1169), .Z(n1167)); - AN2 U1107 ( .A(n1170), .B(n1171), .Z(n1169)); - OR2 U1108 ( .A(n817), .B(n1172), .Z(n1171)); - OR2 U1109 ( .A(pi11), .B(n1173), .Z(n1172)); - AN2 U1110 ( .A(n1010), .B(n1174), .Z(n1173)); - OR2 U1111 ( .A(n1012), .B(n1013), .Z(n1174)); - OR2 U1112 ( .A(n1175), .B(n1082), .Z(n1010)); - AN2 U1113 ( .A(n1176), .B(n1177), .Z(n1170)); - OR2 U1114 ( .A(pi10), .B(n1178), .Z(n1177)); - OR2 U1115 ( .A(n1179), .B(n1180), .Z(n1178)); - AN2 U1116 ( .A(n1181), .B(n1031), .Z(n1180)); - IV2 U1117 ( .A(n1182), .Z(n1179)); - OR2 U1118 ( .A(n1181), .B(n1031), .Z(n1182)); - OR2 U1119 ( .A(n1183), .B(n1184), .Z(n1181)); - AN2 U1120 ( .A(n1185), .B(n1082), .Z(n1184)); - AN2 U1121 ( .A(n1012), .B(n1092), .Z(n1183)); - OR2 U1122 ( .A(n825), .B(n1186), .Z(n1176)); - OR2 U1123 ( .A(n1187), .B(n1188), .Z(n1186)); - AN2 U1124 ( .A(n1189), .B(n1190), .Z(n1187)); - IV2 U1125 ( .A(n725), .Z(n1190)); - OR2 U1126 ( .A(n1066), .B(n738), .Z(n1189)); - AN2 U1127 ( .A(n1191), .B(n1192), .Z(n1168)); - AN2 U1128 ( .A(n1193), .B(n1194), .Z(n1192)); - OR2 U1129 ( .A(n1195), .B(n1017), .Z(n1194)); - AN2 U1130 ( .A(n1196), .B(n1197), .Z(n1195)); - AN2 U1131 ( .A(n1198), .B(n1199), .Z(n1197)); - OR2 U1132 ( .A(pi05), .B(n1200), .Z(n1199)); - AN2 U1133 ( .A(n1201), .B(n1063), .Z(n1198)); - OR2 U1134 ( .A(n1202), .B(n772), .Z(n1201)); - AN2 U1135 ( .A(n1203), .B(n1204), .Z(n1202)); - OR2 U1136 ( .A(n1074), .B(n1032), .Z(n1204)); - OR2 U1137 ( .A(n1105), .B(n1205), .Z(n1203)); - AN2 U1138 ( .A(n1206), .B(n1207), .Z(n1196)); - OR2 U1139 ( .A(n1208), .B(n1054), .Z(n1207)); - AN2 U1140 ( .A(n1209), .B(n1210), .Z(n1208)); - OR2 U1141 ( .A(n1081), .B(n1082), .Z(n1210)); - OR2 U1142 ( .A(n1012), .B(n1211), .Z(n1209)); - IV2 U1143 ( .A(n1081), .Z(n1211)); - OR2 U1144 ( .A(n817), .B(n1212), .Z(n1206)); - OR2 U1145 ( .A(n713), .B(n738), .Z(n1212)); - OR2 U1146 ( .A(pi01), .B(n1213), .Z(n1193)); - AN2 U1147 ( .A(n1214), .B(n1215), .Z(n1213)); - AN2 U1148 ( .A(n1216), .B(n1217), .Z(n1215)); - OR2 U1149 ( .A(n1054), .B(n1218), .Z(n1216)); - OR2 U1150 ( .A(n1012), .B(n1081), .Z(n1218)); - AN2 U1151 ( .A(pi00), .B(n1175), .Z(n1081)); - OR2 U1152 ( .A(pi08), .B(n1020), .Z(n1054)); - AN2 U1153 ( .A(n1219), .B(n1220), .Z(n1214)); - OR2 U1154 ( .A(n772), .B(n1221), .Z(n1220)); - OR2 U1155 ( .A(n1222), .B(n1223), .Z(n1221)); - AN2 U1156 ( .A(n1074), .B(n1032), .Z(n1223)); - AN2 U1157 ( .A(n1105), .B(n1205), .Z(n1222)); - OR2 U1158 ( .A(n1224), .B(n738), .Z(n772)); - AN2 U1159 ( .A(n1225), .B(n829), .Z(n1224)); - OR2 U1160 ( .A(n751), .B(n1023), .Z(n1225)); - OR2 U1161 ( .A(n716), .B(n1200), .Z(n1219)); - OR2 U1162 ( .A(n718), .B(n825), .Z(n1200)); - IV2 U1163 ( .A(n761), .Z(n825)); - AN2 U1164 ( .A(n1226), .B(n1227), .Z(n1191)); - OR2 U1165 ( .A(n1228), .B(n1229), .Z(n1227)); - OR2 U1166 ( .A(n1020), .B(n1230), .Z(n1229)); - OR2 U1167 ( .A(n1231), .B(n1232), .Z(n1230)); - AN2 U1168 ( .A(n1233), .B(n1234), .Z(n1232)); - AN2 U1169 ( .A(n1235), .B(n1031), .Z(n1233)); - OR2 U1170 ( .A(n1030), .B(n1032), .Z(n1235)); - AN2 U1171 ( .A(n1092), .B(n1041), .Z(n1030)); - IV2 U1172 ( .A(n1236), .Z(n1231)); - OR2 U1173 ( .A(n1234), .B(n1031), .Z(n1236)); - OR2 U1174 ( .A(n1237), .B(n1238), .Z(n1031)); - AN2 U1175 ( .A(n868), .B(n725), .Z(n1238)); - AN2 U1176 ( .A(n1012), .B(n869), .Z(n1237)); - IV2 U1177 ( .A(n1082), .Z(n1012)); - OR2 U1178 ( .A(n1239), .B(n1240), .Z(n1082)); - AN2 U1179 ( .A(n901), .B(n1075), .Z(n1240)); - OR2 U1180 ( .A(pi01), .B(n1032), .Z(n1075)); - AN2 U1181 ( .A(n902), .B(n1241), .Z(n1239)); - OR2 U1182 ( .A(n1242), .B(n1243), .Z(n1241)); - OR2 U1183 ( .A(n1244), .B(n1245), .Z(n1243)); - AN2 U1184 ( .A(n1105), .B(n892), .Z(n1245)); - AN2 U1185 ( .A(n1073), .B(n751), .Z(n1244)); - AN2 U1186 ( .A(n908), .B(n725), .Z(n1242)); - OR2 U1187 ( .A(n1185), .B(n1246), .Z(n1234)); - OR2 U1188 ( .A(n1247), .B(n1105), .Z(n1246)); - IV2 U1189 ( .A(n1248), .Z(n1020)); - OR2 U1190 ( .A(n1249), .B(n744), .Z(n1228)); - AN2 U1191 ( .A(n716), .B(n1023), .Z(n1249)); - AN2 U1192 ( .A(n1250), .B(n1251), .Z(n1226)); - OR2 U1193 ( .A(n1105), .B(n1103), .Z(n1251)); - IV2 U1194 ( .A(n1252), .Z(n1103)); - OR2 U1195 ( .A(n1253), .B(n1254), .Z(n1252)); - AN2 U1196 ( .A(n1106), .B(n1041), .Z(n1254)); - OR2 U1197 ( .A(n1255), .B(n780), .Z(n1106)); - AN2 U1198 ( .A(n973), .B(n738), .Z(n1255)); - AN2 U1199 ( .A(n854), .B(n738), .Z(n1253)); - IV2 U1200 ( .A(n1032), .Z(n1105)); - OR2 U1201 ( .A(n1032), .B(n1256), .Z(n1250)); - OR2 U1202 ( .A(n1040), .B(n1041), .Z(n1256)); - IV2 U1203 ( .A(n1257), .Z(n1040)); - OR2 U1204 ( .A(n1258), .B(n1259), .Z(n1155)); - AN2 U1205 ( .A(n1260), .B(n716), .Z(n1259)); - AN2 U1206 ( .A(n924), .B(n1261), .Z(n1260)); - OR2 U1207 ( .A(n1262), .B(n927), .Z(n1261)); - AN2 U1208 ( .A(pi11), .B(pi01), .Z(n1262)); - AN2 U1209 ( .A(pi05), .B(n1263), .Z(n1258)); - OR2 U1210 ( .A(n1264), .B(n930), .Z(n1263)); - AN2 U1211 ( .A(n1265), .B(n804), .Z(n1264)); - OR2 U1212 ( .A(n1266), .B(n1267), .Z(n1265)); - AN2 U1213 ( .A(n854), .B(n1032), .Z(n1267)); - AN2 U1214 ( .A(n934), .B(n1017), .Z(n1266)); - AN2 U1215 ( .A(pi11), .B(n761), .Z(n934)); - OR2 U1216 ( .A(n1268), .B(n1269), .Z(n1153)); - OR2 U1217 ( .A(n937), .B(n1270), .Z(n1269)); - AN2 U1218 ( .A(n939), .B(n1271), .Z(n1270)); - OR2 U1219 ( .A(n1272), .B(n1273), .Z(n1271)); - OR2 U1220 ( .A(n1073), .B(n1274), .Z(n1273)); - AN2 U1221 ( .A(n725), .B(n982), .Z(n1274)); - AN2 U1222 ( .A(n1032), .B(pi01), .Z(n1073)); - OR2 U1223 ( .A(n1275), .B(n1276), .Z(n1032)); - OR2 U1224 ( .A(n1277), .B(n1278), .Z(n1276)); - AN2 U1225 ( .A(n949), .B(n716), .Z(n1278)); - AN2 U1226 ( .A(n950), .B(n1066), .Z(n1277)); - IV2 U1227 ( .A(n723), .Z(n1066)); - OR2 U1228 ( .A(n1279), .B(n1280), .Z(n1275)); - OR2 U1229 ( .A(n1281), .B(n1282), .Z(n1280)); - AN2 U1230 ( .A(n1283), .B(n1017), .Z(n1282)); - OR2 U1231 ( .A(n1284), .B(n957), .Z(n1283)); - AN2 U1232 ( .A(n1285), .B(n784), .Z(n1284)); - AN2 U1233 ( .A(pi05), .B(n1286), .Z(n1285)); - AN2 U1234 ( .A(n725), .B(n1287), .Z(n1281)); - OR2 U1235 ( .A(n1288), .B(n1140), .Z(n1287)); - AN2 U1236 ( .A(n965), .B(n1151), .Z(n1288)); - AN2 U1237 ( .A(n744), .B(n902), .Z(n965)); - AN2 U1238 ( .A(pi01), .B(pi05), .Z(n725)); - AN2 U1239 ( .A(pi13), .B(n1289), .Z(n1279)); - OR2 U1240 ( .A(n1290), .B(n1291), .Z(n1289)); - AN2 U1241 ( .A(n971), .B(pi00), .Z(n1291)); - AN2 U1242 ( .A(n892), .B(n1292), .Z(n971)); - AN2 U1243 ( .A(pi10), .B(pi11), .Z(n1292)); - AN2 U1244 ( .A(n1293), .B(n973), .Z(n1290)); - AN2 U1245 ( .A(n1294), .B(n1295), .Z(n1293)); - OR2 U1246 ( .A(n723), .B(n1286), .Z(n1295)); - IV2 U1247 ( .A(n1151), .Z(n1286)); - OR2 U1248 ( .A(n1151), .B(n1296), .Z(n1294)); - AN2 U1249 ( .A(pi01), .B(n716), .Z(n1296)); - AN2 U1250 ( .A(n944), .B(n723), .Z(n1272)); - AN2 U1251 ( .A(n1017), .B(n716), .Z(n723)); - IV2 U1252 ( .A(pi05), .Z(n716)); - IV2 U1253 ( .A(pi01), .Z(n1017)); - AN2 U1254 ( .A(n983), .B(pi01), .Z(n1268)); - AN2 U1255 ( .A(pi11), .B(n1297), .Z(n983)); - OR2 U1256 ( .A(n1298), .B(n1299), .Z(po0)); - OR2 U1257 ( .A(n1300), .B(n1301), .Z(n1299)); - OR2 U1258 ( .A(n1302), .B(n1303), .Z(n1301)); - OR2 U1259 ( .A(n1304), .B(n1305), .Z(n1303)); - AN2 U1260 ( .A(n793), .B(n1247), .Z(n1305)); - AN2 U1261 ( .A(n924), .B(n1306), .Z(n793)); - IV2 U1262 ( .A(n1307), .Z(n1306)); - OR2 U1263 ( .A(n854), .B(n1308), .Z(n1307)); - AN2 U1264 ( .A(pi08), .B(n1063), .Z(n1308)); - IV2 U1265 ( .A(n1309), .Z(n1063)); - AN2 U1266 ( .A(n794), .B(n1041), .Z(n1304)); - AN2 U1267 ( .A(n1310), .B(n924), .Z(n794)); - OR2 U1268 ( .A(pi11), .B(n854), .Z(n1310)); - AN2 U1269 ( .A(pi11), .B(n1311), .Z(n1302)); - OR2 U1270 ( .A(n1312), .B(n1313), .Z(n1311)); - OR2 U1271 ( .A(n1314), .B(n1315), .Z(n1313)); - AN2 U1272 ( .A(n924), .B(n1316), .Z(n1315)); - AN2 U1273 ( .A(n1317), .B(n761), .Z(n1314)); - AN2 U1274 ( .A(n1023), .B(n908), .Z(n761)); - AN2 U1275 ( .A(n1151), .B(n804), .Z(n1317)); - AN2 U1276 ( .A(n1297), .B(pi00), .Z(n1312)); - AN2 U1277 ( .A(n804), .B(n1318), .Z(n1297)); - OR2 U1278 ( .A(pi10), .B(n892), .Z(n1318)); - OR2 U1279 ( .A(n1319), .B(n1320), .Z(n1300)); - AN2 U1280 ( .A(n1321), .B(n709), .Z(n1320)); - AN2 U1281 ( .A(n927), .B(n924), .Z(n1321)); - AN2 U1282 ( .A(pi04), .B(n1322), .Z(n1319)); - OR2 U1283 ( .A(n1323), .B(n930), .Z(n1322)); - AN2 U1284 ( .A(n939), .B(n1324), .Z(n930)); - AN2 U1285 ( .A(n744), .B(pi11), .Z(n1324)); - AN2 U1286 ( .A(n957), .B(n1041), .Z(n1323)); - OR2 U1287 ( .A(n1325), .B(n1326), .Z(n1298)); - OR2 U1288 ( .A(n937), .B(n1327), .Z(n1326)); - AN2 U1289 ( .A(pi13), .B(n1328), .Z(n1327)); - OR2 U1290 ( .A(n1329), .B(n1330), .Z(n1328)); - AN2 U1291 ( .A(n1109), .B(n1166), .Z(n1330)); - IV2 U1292 ( .A(pi12), .Z(n1166)); - IV2 U1293 ( .A(n1165), .Z(n1109)); - AN2 U1294 ( .A(pi12), .B(n1165), .Z(n1329)); - OR2 U1295 ( .A(n1331), .B(n1332), .Z(n1165)); - AN2 U1296 ( .A(pi13), .B(n1333), .Z(n1332)); - OR2 U1297 ( .A(n1334), .B(n1335), .Z(n1333)); - OR2 U1298 ( .A(n1336), .B(n1337), .Z(n1335)); - AN2 U1299 ( .A(n1247), .B(n1257), .Z(n1337)); - OR2 U1300 ( .A(n1338), .B(n780), .Z(n1257)); - AN2 U1301 ( .A(n1023), .B(n751), .Z(n780)); - AN2 U1302 ( .A(n944), .B(pi09), .Z(n1338)); - AN2 U1303 ( .A(pi11), .B(n1339), .Z(n1336)); - OR2 U1304 ( .A(n1340), .B(n1341), .Z(n1339)); - OR2 U1305 ( .A(n1342), .B(n1343), .Z(n1341)); - AN2 U1306 ( .A(n1344), .B(pi00), .Z(n1343)); - AN2 U1307 ( .A(n1345), .B(n1247), .Z(n1344)); - AN2 U1308 ( .A(pi10), .B(n1346), .Z(n1345)); - AN2 U1309 ( .A(n1041), .B(n713), .Z(n1342)); - IV2 U1310 ( .A(n1217), .Z(n1340)); - OR2 U1311 ( .A(pi00), .B(n817), .Z(n1217)); - OR2 U1312 ( .A(n1023), .B(n1346), .Z(n817)); - OR2 U1313 ( .A(n1347), .B(n1348), .Z(n1334)); - OR2 U1314 ( .A(n1349), .B(n1350), .Z(n1348)); - AN2 U1315 ( .A(n1316), .B(n1023), .Z(n1350)); - AN2 U1316 ( .A(n854), .B(n1351), .Z(n1349)); - OR2 U1317 ( .A(n1352), .B(n1353), .Z(n1351)); - AN2 U1318 ( .A(pi00), .B(n738), .Z(n1353)); - AN2 U1319 ( .A(pi09), .B(n1041), .Z(n1352)); - AN2 U1320 ( .A(n1248), .B(n1354), .Z(n1347)); - OR2 U1321 ( .A(n1355), .B(n1356), .Z(n1354)); - OR2 U1322 ( .A(n1357), .B(n1358), .Z(n1356)); - AN2 U1323 ( .A(n1185), .B(n1041), .Z(n1358)); - IV2 U1324 ( .A(n1092), .Z(n1185)); - AN2 U1325 ( .A(n1247), .B(n1092), .Z(n1357)); - OR2 U1326 ( .A(n1359), .B(n1360), .Z(n1092)); - AN2 U1327 ( .A(n868), .B(n718), .Z(n1360)); - AN2 U1328 ( .A(n1023), .B(n901), .Z(n868)); - AN2 U1329 ( .A(n973), .B(pi11), .Z(n901)); - AN2 U1330 ( .A(n869), .B(n1013), .Z(n1359)); - AN2 U1331 ( .A(n1361), .B(n927), .Z(n869)); - AN2 U1332 ( .A(n963), .B(pi08), .Z(n927)); - IV2 U1333 ( .A(n1041), .Z(n1247)); - AN2 U1334 ( .A(n1175), .B(n713), .Z(n1355)); - IV2 U1335 ( .A(n1013), .Z(n1175)); - AN2 U1336 ( .A(n1361), .B(n738), .Z(n1248)); - AN2 U1337 ( .A(n1362), .B(n751), .Z(n1331)); - AN2 U1338 ( .A(n902), .B(n1013), .Z(n1362)); - OR2 U1339 ( .A(n1363), .B(n1364), .Z(n1013)); - IV2 U1340 ( .A(n902), .Z(n1364)); - AN2 U1341 ( .A(n1365), .B(n1366), .Z(n1363)); - OR2 U1342 ( .A(n1188), .B(n857), .Z(n1366)); - IV2 U1343 ( .A(n908), .Z(n857)); - IV2 U1344 ( .A(n718), .Z(n1188)); - AN2 U1345 ( .A(n1367), .B(n1368), .Z(n1365)); - OR2 U1346 ( .A(n1346), .B(n1205), .Z(n1368)); - IV2 U1347 ( .A(n1074), .Z(n1205)); - IV2 U1348 ( .A(n751), .Z(n1346)); - OR2 U1349 ( .A(n829), .B(n1041), .Z(n1367)); - IV2 U1350 ( .A(n892), .Z(n829)); - AN2 U1351 ( .A(n1309), .B(n1369), .Z(n937)); - AN2 U1352 ( .A(pi13), .B(n751), .Z(n1369)); - AN2 U1353 ( .A(n939), .B(n1370), .Z(n1325)); - OR2 U1354 ( .A(n1371), .B(n1372), .Z(n1370)); - OR2 U1355 ( .A(n1074), .B(n1373), .Z(n1372)); - AN2 U1356 ( .A(n1374), .B(n944), .Z(n1373)); - AN2 U1357 ( .A(n713), .B(n709), .Z(n1374)); - AN2 U1358 ( .A(n1041), .B(pi00), .Z(n1074)); - OR2 U1359 ( .A(n1375), .B(n1376), .Z(n1041)); - OR2 U1360 ( .A(n1377), .B(n1378), .Z(n1376)); - OR2 U1361 ( .A(n1379), .B(n1380), .Z(n1378)); - AN2 U1362 ( .A(n949), .B(n709), .Z(n1380)); - OR2 U1363 ( .A(n1381), .B(n1382), .Z(n949)); - OR2 U1364 ( .A(n1383), .B(n1384), .Z(n1382)); - AN2 U1365 ( .A(n751), .B(n963), .Z(n1384)); - AN2 U1366 ( .A(n1385), .B(n860), .Z(n1383)); - IV2 U1367 ( .A(n963), .Z(n860)); - AN2 U1368 ( .A(n1386), .B(n924), .Z(n1381)); - AN2 U1369 ( .A(n804), .B(n1361), .Z(n924)); - AN2 U1370 ( .A(pi08), .B(pi10), .Z(n1386)); - AN2 U1371 ( .A(n718), .B(n1140), .Z(n1379)); - OR2 U1372 ( .A(n1387), .B(n981), .Z(n1140)); - AN2 U1373 ( .A(pi11), .B(n1388), .Z(n981)); - AN2 U1374 ( .A(n1023), .B(n1389), .Z(n1388)); - OR2 U1375 ( .A(n751), .B(n892), .Z(n1389)); - AN2 U1376 ( .A(n744), .B(n1361), .Z(n892)); - AN2 U1377 ( .A(pi09), .B(pi08), .Z(n751)); - AN2 U1378 ( .A(n944), .B(n1361), .Z(n1387)); - AN2 U1379 ( .A(n744), .B(n963), .Z(n944)); - AN2 U1380 ( .A(n784), .B(n1151), .Z(n1377)); - AN2 U1381 ( .A(n713), .B(pi04), .Z(n1151)); - AN2 U1382 ( .A(n973), .B(n902), .Z(n784)); - AN2 U1383 ( .A(n963), .B(pi13), .Z(n902)); - AN2 U1384 ( .A(n738), .B(pi10), .Z(n963)); - OR2 U1385 ( .A(n1390), .B(n1391), .Z(n1375)); - OR2 U1386 ( .A(n1392), .B(n1393), .Z(n1391)); - AN2 U1387 ( .A(n950), .B(n1394), .Z(n1393)); - OR2 U1388 ( .A(pi00), .B(pi04), .Z(n1394)); - AN2 U1389 ( .A(n1395), .B(n908), .Z(n950)); - AN2 U1390 ( .A(n1361), .B(pi08), .Z(n908)); - IV2 U1391 ( .A(pi09), .Z(n1361)); - OR2 U1392 ( .A(pi13), .B(n1309), .Z(n1395)); - AN2 U1393 ( .A(n1023), .B(n738), .Z(n1309)); - IV2 U1394 ( .A(pi11), .Z(n738)); - AN2 U1395 ( .A(n1385), .B(n1316), .Z(n1392)); - AN2 U1396 ( .A(n709), .B(pi00), .Z(n1316)); - IV2 U1397 ( .A(pi04), .Z(n709)); - AN2 U1398 ( .A(n973), .B(pi13), .Z(n1385)); - AN2 U1399 ( .A(n744), .B(pi09), .Z(n973)); - AN2 U1400 ( .A(n957), .B(n713), .Z(n1390)); - IV2 U1401 ( .A(pi00), .Z(n713)); - AN2 U1402 ( .A(n804), .B(n854), .Z(n957)); - AN2 U1403 ( .A(n744), .B(n1023), .Z(n854)); - IV2 U1404 ( .A(pi10), .Z(n1023)); - AN2 U1405 ( .A(n718), .B(n982), .Z(n1371)); - OR2 U1406 ( .A(n1396), .B(pi11), .Z(n982)); - AN2 U1407 ( .A(pi10), .B(n744), .Z(n1396)); - IV2 U1408 ( .A(pi08), .Z(n744)); - AN2 U1409 ( .A(pi00), .B(pi04), .Z(n718)); - AN2 U1410 ( .A(n804), .B(pi09), .Z(n939)); - IV2 U1411 ( .A(pi13), .Z(n804)); - -endmodule - -module IV2(A, Z); - input A; - output Z; - - assign Z = ~A; -endmodule - -module AN2(A, B, Z); - input A, B; - output Z; - - assign Z = A & B; -endmodule - -module OR2(A, B, Z); - input A, B; - output Z; - - assign Z = A | B; -endmodule diff --git a/yosys/examples/smtbmc/glift/alu4.ys b/yosys/examples/smtbmc/glift/alu4.ys deleted file mode 100644 index 8e8d14225f3..00000000000 --- a/yosys/examples/smtbmc/glift/alu4.ys +++ /dev/null @@ -1,41 +0,0 @@ -read_verilog alu4.v -techmap -flatten -select alu4_lev2 -glift -create-instrumented-model -techmap -opt -rename alu4_lev2 uut -cd .. -delete [AIONX][NVXR]2 -read_verilog alu4.v -techmap -flatten -select alu4_lev2 -glift -create-precise-model -techmap -opt -rename alu4_lev2 spec -cd .. -delete [AIONX][NVXR]2 - -design -push-copy -miter -equiv spec uut miter -flatten -delete uut spec -techmap -opt -stat miter -qbfsat -O2 -write-solution alu4.soln -solver yices -timeout 3600 -nocleanup -assume-outputs -assume-negative-polarity miter -design -pop -stat - -copy uut solved -qbfsat -specialize-from-file alu4.soln solved -opt solved -miter -equiv spec solved satmiter -flatten -sat -prove trigger 0 satmiter -delete satmiter -stat -shell diff --git a/yosys/examples/smtbmc/glift/mux2.ys b/yosys/examples/smtbmc/glift/mux2.ys deleted file mode 100644 index a8e99912b26..00000000000 --- a/yosys/examples/smtbmc/glift/mux2.ys +++ /dev/null @@ -1,40 +0,0 @@ -logger -expect log "SAT proof finished - no model found: SUCCESS!" 1 -logger -expect log "Number of cells:.*[\t ]12" 1 -logger -expect log "Number of cells:.*[\t ]20" 1 -logger -expect log "Problem is satisfiable with \\gate.__glift_weight = 11." 1 -logger -expect log "Problem is NOT satisfiable with \\gate.__glift_weight <= 10." 1 -logger -expect log "Wire \\gate.__glift_weight is minimized at 11." 1 -logger -expect log "Specializing .* from file with .* = 1." 2 -logger -expect log "Specializing .* from file with .* = 0." 4 -read_verilog < - * 2019 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 - -// https://stackoverflow.com/a/46137633 -#ifdef _MSC_VER -#include -#define __builtin_bswap32 _byteswap_ulong -#elif defined(__APPLE__) -#include -#define __builtin_bswap32 OSSwapInt32 -#endif -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif -#include - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "aigerparse.h" - -YOSYS_NAMESPACE_BEGIN - -inline int32_t from_big_endian(int32_t i32) { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - return __builtin_bswap32(i32); -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - return i32; -#else -#error "Unknown endianness" -#endif -} - -#define log_debug2(...) ; -//#define log_debug2(...) log_debug(__VA_ARGS__) - -static int decimal_digits(uint32_t n) { - static uint32_t digit_cutoff[9] = { - 10, 100, 1000, 10000, 100000, - 1000000, 10000000, 100000000, 1000000000 - }; - for (int i = 0; i < 9; ++i) { - if (n < digit_cutoff[i]) return i + 1; - } - return 10; -} - -struct ConstEvalAig -{ - RTLIL::Module *module; - dict values_map; - dict sig2driver; - dict> sig2deps; - - ConstEvalAig(RTLIL::Module *module) : module(module) - { - for (auto &it : module->cells_) { - if (!yosys_celltypes.cell_known(it.second->type)) - continue; - for (auto &it2 : it.second->connections()) - if (yosys_celltypes.cell_output(it.second->type, it2.first)) { - auto r = sig2driver.insert(std::make_pair(it2.second, it.second)); - log_assert(r.second); - } - } - } - - void clear() - { - values_map.clear(); - sig2deps.clear(); - } - - void set(RTLIL::SigBit sig, RTLIL::State value) - { - auto it = values_map.find(sig); -#ifndef NDEBUG - if (it != values_map.end()) { - RTLIL::State current_val = it->second; - log_assert(current_val == value); - } -#endif - if (it != values_map.end()) - it->second = value; - else - values_map[sig] = value; - } - - void set_incremental(RTLIL::SigSpec sig, RTLIL::Const value) - { - log_assert(GetSize(sig) == GetSize(value)); - - for (int i = 0; i < GetSize(sig); i++) { - auto it = values_map.find(sig[i]); - if (it != values_map.end()) { - RTLIL::State current_val = it->second; - if (current_val != value[i]) - for (auto dep : sig2deps[sig[i]]) - values_map.erase(dep); - it->second = value[i]; - } - else - values_map[sig[i]] = value[i]; - } - } - - void compute_deps(RTLIL::SigBit output, const pool &inputs) - { - sig2deps[output].insert(output); - - RTLIL::Cell *cell = sig2driver.at(output); - RTLIL::SigBit sig_a = cell->getPort(ID::A); - sig2deps[sig_a].reserve(sig2deps[sig_a].size() + sig2deps[output].size()); // Reserve so that any invalidation - // that may occur does so here, and - // not mid insertion (below) - sig2deps[sig_a].insert(sig2deps[output].begin(), sig2deps[output].end()); - if (!inputs.count(sig_a)) - compute_deps(sig_a, inputs); - - if (cell->type == ID($_AND_)) { - RTLIL::SigSpec sig_b = cell->getPort(ID::B); - sig2deps[sig_b].reserve(sig2deps[sig_b].size() + sig2deps[output].size()); // Reserve so that any invalidation - // that may occur does so here, and - // not mid insertion (below) - sig2deps[sig_b].insert(sig2deps[output].begin(), sig2deps[output].end()); - - if (!inputs.count(sig_b)) - compute_deps(sig_b, inputs); - } - else if (cell->type == ID($_NOT_)) { - } - else log_abort(); - } - - bool eval(RTLIL::Cell *cell) - { - RTLIL::SigBit sig_y = cell->getPort(ID::Y); - if (values_map.count(sig_y)) - return true; - - RTLIL::SigBit sig_a = cell->getPort(ID::A); - if (!eval(sig_a)) - return false; - - RTLIL::State eval_ret = RTLIL::Sx; - if (cell->type == ID($_NOT_)) { - if (sig_a == State::S0) eval_ret = State::S1; - else if (sig_a == State::S1) eval_ret = State::S0; - } - else if (cell->type == ID($_AND_)) { - if (sig_a == State::S0) { - eval_ret = State::S0; - goto eval_end; - } - - { - RTLIL::SigBit sig_b = cell->getPort(ID::B); - if (!eval(sig_b)) - return false; - if (sig_b == State::S0) { - eval_ret = State::S0; - goto eval_end; - } - - if (sig_a != State::S1 || sig_b != State::S1) - goto eval_end; - - eval_ret = State::S1; - } - } - else log_abort(); - -eval_end: - set(sig_y, eval_ret); - return true; - } - - bool eval(RTLIL::SigBit &sig) - { - auto it = values_map.find(sig); - if (it != values_map.end()) { - sig = it->second; - return true; - } - - RTLIL::Cell *cell = sig2driver.at(sig); - if (!eval(cell)) - return false; - - it = values_map.find(sig); - if (it != values_map.end()) { - sig = it->second; - return true; - } - - return false; - } -}; - -AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports) - : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports), aiger_autoidx(autoidx++) -{ - 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; - piNum = 0; - flopNum = 0; - - if (header == "aag") - parse_aiger_ascii(); - else if (header == "aig") - parse_aiger_binary(); - else - log_abort(); - - RTLIL::Wire* n0 = module->wire(stringf("$aiger%d$0", aiger_autoidx)); - if (n0) - module->connect(n0, State::S0); - - // 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::IdString escaped_s = stringf("\\%s", s.c_str()); - RTLIL::Wire* wire; - if (c == 'i') wire = inputs[l1]; - else if (c == 'l') wire = latches[l1]; - else if (c == 'o') { - wire = module->wire(escaped_s); - if (wire) { - // Could have been renamed by a latch - module->swap_names(wire, outputs[l1]); - module->connect(outputs[l1], wire); - goto next; - } - wire = outputs[l1]; - } - else if (c == 'b') wire = bad_properties[l1]; - else log_abort(); - - module->rename(wire, escaped_s); - } - else if (c == 'j' || c == 'f') { - // TODO - } - else if (c == 'c') { - f.ignore(1); - if (f.peek() == '\r') - 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); -next: - std::getline(f, line); // Ignore up to start of next line - } - - post_process(); -} - -static uint32_t parse_xaiger_literal(std::istream &f) -{ - uint32_t l; - f.read(reinterpret_cast(&l), sizeof(l)); - if (f.gcount() != sizeof(l)) -#if defined(_WIN32) && defined(__MINGW32__) - log_error("Offset %I64d: unable to read literal!\n", static_cast(f.tellg())); -#else - log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast(f.tellg())); -#endif - return from_big_endian(l); -} - -RTLIL::Wire* AigerReader::createWireIfNotExists(RTLIL::Module *module, unsigned literal) -{ - const unsigned variable = literal >> 1; - const bool invert = literal & 1; - RTLIL::IdString wire_name(stringf("$aiger%d$%d%s", aiger_autoidx, variable, invert ? "b" : "")); - RTLIL::Wire *wire = module->wire(wire_name); - if (wire) return wire; - log_debug2("Creating %s\n", wire_name.c_str()); - wire = module->addWire(wire_name); - wire->port_input = wire->port_output = false; - if (!invert) return wire; - RTLIL::IdString wire_inv_name(stringf("$aiger%d$%d", aiger_autoidx, variable)); - RTLIL::Wire *wire_inv = module->wire(wire_inv_name); - if (wire_inv) { - if (module->cell(wire_inv_name)) return wire; - } - else { - log_debug2("Creating %s\n", wire_inv_name.c_str()); - wire_inv = module->addWire(wire_inv_name); - wire_inv->port_input = wire_inv->port_output = false; - } - - log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); - module->addNotGate(stringf("$not$aiger%d$%d", aiger_autoidx, variable), wire_inv, wire); - - return wire; -} - -void AigerReader::parse_xaiger() -{ - 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; - - 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\n", M, I, L, O, A); - - line_count = 1; - piNum = 0; - flopNum = 0; - - if (header == "aag") - parse_aiger_ascii(); - else if (header == "aig") - parse_aiger_binary(); - else - log_abort(); - - RTLIL::Wire* n0 = module->wire(stringf("$aiger%d$0", aiger_autoidx)); - if (n0) - module->connect(n0, State::S0); - - int c = f.get(); - if (c != 'c') - log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); - if (f.peek() == '\n') - f.get(); - - // Parse footer (symbol table, comments, etc.) - std::string s; - for (int c = f.get(); c != EOF; c = f.get()) { - // XAIGER extensions - if (c == 'm') { - uint32_t dataSize = parse_xaiger_literal(f); - uint32_t lutNum = parse_xaiger_literal(f); - uint32_t lutSize = parse_xaiger_literal(f); - log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize); - ConstEvalAig ce(module); - for (unsigned i = 0; i < lutNum; ++i) { - uint32_t rootNodeID = parse_xaiger_literal(f); - uint32_t cutLeavesM = parse_xaiger_literal(f); - log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM); - RTLIL::Wire *output_sig = module->wire(stringf("$aiger%d$%d", aiger_autoidx, rootNodeID)); - log_assert(output_sig); - uint32_t nodeID; - RTLIL::SigSpec input_sig; - for (unsigned j = 0; j < cutLeavesM; ++j) { - nodeID = parse_xaiger_literal(f); - log_debug2("\t%u\n", nodeID); - if (nodeID == 0) { - log_debug("\tLUT '$lut$aiger%d$%d' input %d is constant!\n", aiger_autoidx, rootNodeID, cutLeavesM); - continue; - } - RTLIL::Wire *wire = module->wire(stringf("$aiger%d$%d", aiger_autoidx, nodeID)); - log_assert(wire); - input_sig.append(wire); - } - // Reverse input order as fastest input is returned first - input_sig.reverse(); - // TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size()) - ce.clear(); - ce.compute_deps(output_sig, input_sig.to_sigbit_pool()); - RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << GetSize(input_sig)); - for (int j = 0; j < GetSize(lut_mask); ++j) { - int gray = j ^ (j >> 1); - ce.set_incremental(input_sig, RTLIL::Const{gray, GetSize(input_sig)}); - RTLIL::SigBit o(output_sig); - bool success = ce.eval(o); - log_assert(success); - log_assert(o.wire == nullptr); - lut_mask[gray] = o.data; - } - RTLIL::Cell *output_cell = module->cell(stringf("$and$aiger%d$%d", aiger_autoidx, rootNodeID)); - log_assert(output_cell); - module->remove(output_cell); - module->addLut(stringf("$lut$aiger%d$%d", aiger_autoidx, rootNodeID), input_sig, output_sig, std::move(lut_mask)); - } - } - else if (c == 'r') { - uint32_t dataSize = parse_xaiger_literal(f); - flopNum = parse_xaiger_literal(f); - log_debug("flopNum = %u\n", flopNum); - log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); - mergeability.reserve(flopNum); - for (unsigned i = 0; i < flopNum; i++) - mergeability.emplace_back(parse_xaiger_literal(f)); - } - else if (c == 's') { - uint32_t dataSize = parse_xaiger_literal(f); - flopNum = parse_xaiger_literal(f); - log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); - initial_state.reserve(flopNum); - for (unsigned i = 0; i < flopNum; i++) - initial_state.emplace_back(parse_xaiger_literal(f)); - } - else if (c == 'n') { - parse_xaiger_literal(f); - f >> s; - log_debug("n: '%s'\n", s.c_str()); - } - else if (c == 'h') { - f.ignore(sizeof(uint32_t)); - uint32_t version = parse_xaiger_literal(f); - log_assert(version == 1); - uint32_t ciNum = parse_xaiger_literal(f); - log_debug("ciNum = %u\n", ciNum); - uint32_t coNum = parse_xaiger_literal(f); - log_debug("coNum = %u\n", coNum); - piNum = parse_xaiger_literal(f); - log_debug("piNum = %u\n", piNum); - uint32_t poNum = parse_xaiger_literal(f); - log_debug("poNum = %u\n", poNum); - uint32_t boxNum = parse_xaiger_literal(f); - log_debug("boxNum = %u\n", boxNum); - for (unsigned i = 0; i < boxNum; i++) { - uint32_t boxInputs = parse_xaiger_literal(f); - uint32_t boxOutputs = parse_xaiger_literal(f); - uint32_t boxUniqueId = parse_xaiger_literal(f); - log_assert(boxUniqueId > 0); - uint32_t oldBoxNum = parse_xaiger_literal(f); - RTLIL::Cell* cell = module->addCell(stringf("$box%u", oldBoxNum), stringf("$__boxid%u", boxUniqueId)); - cell->setPort(ID(i), SigSpec(State::S0, boxInputs)); - cell->setPort(ID(o), SigSpec(State::S0, boxOutputs)); - cell->attributes[ID::abc9_box_seq] = oldBoxNum; - boxes.emplace_back(cell); - } - } - else if (c == 'a' || c == 'i' || c == 'o' || c == 's') { - uint32_t dataSize = parse_xaiger_literal(f); - f.ignore(dataSize); - log_debug("ignoring '%c'\n", c); - } - else { - break; - } - } - - post_process(); -} - -void AigerReader::parse_aiger_ascii() -{ - std::string line; - std::stringstream ss; - - unsigned l1, l2, l3; - - // Parse inputs - int digits = decimal_digits(I); - 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_debug2("%d is an input\n", l1); - log_assert(!(l1 & 1)); // Inputs can't be inverted - RTLIL::Wire *wire = module->addWire(stringf("$i%0*d", digits, l1 >> 1)); - wire->port_input = true; - module->connect(createWireIfNotExists(module, l1), wire); - inputs.push_back(wire); - } - - // Parse latches - RTLIL::Wire *clk_wire = nullptr; - if (L > 0 && !clk_name.empty()) { - clk_wire = module->wire(clk_name); - log_assert(!clk_wire); - log_debug2("Creating %s\n", clk_name.c_str()); - clk_wire = module->addWire(clk_name); - clk_wire->port_input = true; - clk_wire->port_output = false; - } - digits = decimal_digits(L); - 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_debug2("%d %d is a latch\n", l1, l2); - log_assert(!(l1 & 1)); - RTLIL::Wire *q_wire = module->addWire(stringf("$l%0*d", digits, l1 >> 1)); - module->connect(createWireIfNotExists(module, l1), q_wire); - RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - - if (clk_wire) - module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); - else - module->addFfGate(NEW_ID, 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[ID::init] = State::S0; - else if (l3 == 1) - q_wire->attributes[ID::init] = State::S1; - else if (l3 == l1) { - //q_wire->attributes[ID::init] = RTLIL::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[ID::init] = State::S0; - } - latches.push_back(q_wire); - } - - // Parse outputs - digits = decimal_digits(O); - 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_debug2("%d is an output\n", l1); - RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i)); - wire->port_output = true; - module->connect(wire, createWireIfNotExists(module, l1)); - 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_debug2("%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 - 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_debug2("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); - RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); - RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); - module->addAndGate("$and" + o_wire->name.str(), 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 - int digits = decimal_digits(I); - for (unsigned i = 1; i <= I; ++i) { - log_debug2("%d is an input\n", i); - RTLIL::Wire *wire = module->addWire(stringf("$i%0*d", digits, i)); - wire->port_input = true; - module->connect(createWireIfNotExists(module, i << 1), wire); - inputs.push_back(wire); - } - - // Parse latches - RTLIL::Wire *clk_wire = nullptr; - if (L > 0 && !clk_name.empty()) { - clk_wire = module->wire(clk_name); - log_assert(!clk_wire); - log_debug2("Creating %s\n", clk_name.c_str()); - clk_wire = module->addWire(clk_name); - clk_wire->port_input = true; - clk_wire->port_output = false; - } - digits = decimal_digits(L); - 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 = module->addWire(stringf("$l%0*d", digits, l1 >> 1)); - module->connect(createWireIfNotExists(module, l1), q_wire); - RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); - - if (clk_wire) - module->addDff(NEW_ID, clk_wire, d_wire, q_wire); - else - module->addFf(NEW_ID, 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[ID::init] = State::S0; - else if (l3 == 1) - q_wire->attributes[ID::init] = State::S1; - else if (l3 == l1) { - //q_wire->attributes[ID::init] = RTLIL::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[ID::init] = State::S0; - } - latches.push_back(q_wire); - } - - // Parse outputs - digits = decimal_digits(O); - 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_debug2("%d is an output\n", l1); - RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i)); - wire->port_output = true; - module->connect(wire, createWireIfNotExists(module, l1)); - 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_debug2("%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_debug2("%d %d %d is an AND\n", l1, l2, l3); - log_assert(!(l1 & 1)); - RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); - RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); - RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); - module->addAndGate("$and" + o_wire->name.str(), i1_wire, i2_wire, o_wire); - } -} - -void AigerReader::post_process() -{ - unsigned ci_count = 0, co_count = 0; - for (auto cell : boxes) { - for (auto &bit : cell->connections_.at(ID(i))) { - log_assert(bit == State::S0); - log_assert(co_count < outputs.size()); - bit = outputs[co_count++]; - log_assert(bit.wire && GetSize(bit.wire) == 1); - log_assert(bit.wire->port_output); - bit.wire->port_output = false; - } - for (auto &bit : cell->connections_.at(ID(o))) { - log_assert(bit == State::S0); - log_assert((piNum + ci_count) < inputs.size()); - bit = inputs[piNum + ci_count++]; - log_assert(bit.wire && GetSize(bit.wire) == 1); - log_assert(bit.wire->port_input); - bit.wire->port_input = false; - } - } - - for (uint32_t i = 0; i < flopNum; i++) { - RTLIL::Wire *d = outputs[outputs.size() - flopNum + i]; - log_assert(d); - log_assert(d->port_output); - d->port_output = false; - - RTLIL::Wire *q = inputs[piNum - flopNum + i]; - log_assert(q); - log_assert(q->port_input); - q->port_input = false; - - Cell* ff = module->addFfGate(NEW_ID, d, q); - ff->attributes[ID::abc9_mergeability] = mergeability[i]; - q->attributes[ID::init] = initial_state[i]; - } - - dict> wideports_cache; - - if (!map_filename.empty()) { - std::ifstream mf(map_filename); - std::string type, symbol; - int variable, index; - while (mf >> type >> variable >> index >> symbol) { - RTLIL::IdString escaped_s = RTLIL::escape_id(symbol); - if (type == "input") { - log_assert(static_cast(variable) < inputs.size()); - RTLIL::Wire* wire = inputs[variable]; - log_assert(wire); - log_assert(wire->port_input); - log_debug("Renaming input %s", log_id(wire)); - - RTLIL::Wire *existing = nullptr; - if (index == 0) { - // Cope with the fact that a CI might be identical - // to a PI (necessary due to ABC); in those cases - // simply connect the latter to the former - existing = module->wire(escaped_s); - if (!existing) - module->rename(wire, escaped_s); - else { - wire->port_input = false; - module->connect(wire, existing); - } - log_debug(" -> %s\n", log_id(escaped_s)); - } - else { - RTLIL::IdString indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); - existing = module->wire(indexed_name); - if (!existing) - module->rename(wire, indexed_name); - else { - module->connect(wire, existing); - wire->port_input = false; - } - log_debug(" -> %s\n", log_id(indexed_name)); - } - - if (wideports && !existing) { - auto r = wideports_cache.insert(escaped_s); - if (r.second) { - r.first->second.first = index; - r.first->second.second = index; - } - else { - r.first->second.first = std::min(r.first->second.first, index); - r.first->second.second = std::max(r.first->second.second, index); - } - } - } - else if (type == "output") { - log_assert(static_cast(variable + co_count) < outputs.size()); - RTLIL::Wire* wire = outputs[variable + co_count]; - log_assert(wire); - log_assert(wire->port_output); - log_debug("Renaming output %s", log_id(wire)); - - RTLIL::Wire *existing; - if (index == 0) { - // Cope with the fact that a CO might be identical - // to a PO (necessary due to ABC); in those cases - // simply connect the latter to the former - existing = module->wire(escaped_s); - if (!existing) - module->rename(wire, escaped_s); - else { - wire->port_output = false; - existing->port_output = true; - module->connect(wire, existing); - wire = existing; - } - log_debug(" -> %s\n", log_id(escaped_s)); - } - else { - RTLIL::IdString indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); - existing = module->wire(indexed_name); - if (!existing) - module->rename(wire, indexed_name); - else { - wire->port_output = false; - existing->port_output = true; - module->connect(wire, existing); - } - log_debug(" -> %s\n", log_id(indexed_name)); - } - - if (wideports && !existing) { - auto r = wideports_cache.insert(escaped_s); - if (r.second) { - r.first->second.first = index; - r.first->second.second = index; - } - else { - r.first->second.first = std::min(r.first->second.first, index); - r.first->second.second = std::max(r.first->second.second, index); - } - } - } - else if (type == "box") { - RTLIL::Cell* cell = module->cell(stringf("$box%d", variable)); - if (!cell) - log_debug("Box %d (%s) no longer exists.\n", variable, log_id(escaped_s)); - else - module->rename(cell, escaped_s); - } - else - log_error("Symbol type '%s' not recognised.\n", type.c_str()); - } - } - - for (auto &wp : wideports_cache) { - auto name = wp.first; - int min = wp.second.first; - int max = wp.second.second; - if (min == 0 && max == 0) - continue; - - RTLIL::Wire *wire = module->wire(name); - if (wire) - module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0))); - - // Do not make ports with a mix of input/output into - // wide ports - bool port_input = false, port_output = false; - for (int i = min; i <= max; i++) { - RTLIL::IdString other_name = name.str() + stringf("[%d]", i); - RTLIL::Wire *other_wire = module->wire(other_name); - if (other_wire) { - port_input = port_input || other_wire->port_input; - port_output = port_output || other_wire->port_output; - } - } - - wire = module->addWire(name, max-min+1); - wire->start_offset = min; - wire->port_input = port_input; - wire->port_output = port_output; - - for (int i = min; i <= max; i++) { - RTLIL::IdString other_name = stringf("%s[%d]", name.c_str(), i); - RTLIL::Wire *other_wire = module->wire(other_name); - if (other_wire) { - other_wire->port_input = false; - other_wire->port_output = false; - if (wire->port_input) - module->connect(other_wire, SigSpec(wire, i-min)); - else - module->connect(SigSpec(wire, i-min), other_wire); - } - } - } - - module->fixup_ports(); - - // Insert into a new (temporary) design so that "clean" will only - // operate (and run checks on) this one module - RTLIL::Design *mapped_design = new RTLIL::Design; - mapped_design->add(module); - Pass::call(mapped_design, "clean"); - mapped_design->modules_.erase(module->name); - delete mapped_design; - - design->add(module); - - for (auto cell : module->cells().to_vector()) { - if (cell->type != ID($lut)) continue; - auto y_port = cell->getPort(ID::Y).as_bit(); - if (y_port.wire->width == 1) - module->rename(cell, stringf("$lut%s", y_port.wire->name.c_str())); - else - module->rename(cell, stringf("$lut%s[%d]", y_port.wire->name.c_str(), y_port.offset)); - } -} - -struct AigerFrontend : public Frontend { - AigerFrontend() : Frontend("aiger", "read AIGER file") { } - void help() 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: )\n"); - log("\n"); - log(" -clk_name \n"); - log(" if specified, AIGER latches to be transformed into $_DFF_P_ cells\n"); - log(" clocked by wire of this name. otherwise, $_FF_ cells will be used\n"); - log("\n"); - log(" -map \n"); - log(" read file with port and latch symbols\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"); - log(" -xaiger\n"); - log(" read XAIGER extensions\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) override - { - log_header(design, "Executing AIGER frontend.\n"); - - RTLIL::IdString clk_name; - RTLIL::IdString module_name; - std::string map_filename; - bool wideports = false, xaiger = false; - - 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; - } - if (map_filename.empty() && arg == "-map" && argidx+1 < args.size()) { - map_filename = args[++argidx]; - continue; - } - if (arg == "-wideports") { - wideports = true; - continue; - } - if (arg == "-xaiger") { - xaiger = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx, true); - - if (module_name.empty()) { -#ifdef _WIN32 - char fname[_MAX_FNAME]; - _splitpath(filename.c_str(), NULL /* drive */, NULL /* dir */, fname, NULL /* ext */); - char* bn = strdup(fname); - module_name = RTLIL::escape_id(bn); - free(bn); -#else - char* bn = strdup(filename.c_str()); - module_name = RTLIL::escape_id(bn); - free(bn); -#endif - } - - AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports); - if (xaiger) - reader.parse_xaiger(); - else - 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 81b9559474f..00000000000 --- a/yosys/frontends/aiger/aigerparse.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * 2019 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; - std::string map_filename; - bool wideports; - const int aiger_autoidx; - - unsigned M, I, L, O, A; - unsigned B, C, J, F; // Optional in AIGER 1.9 - unsigned line_count; - uint32_t piNum, flopNum; - - std::vector inputs; - std::vector latches; - std::vector outputs; - std::vector bad_properties; - std::vector boxes; - std::vector mergeability, initial_state; - - AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); - void parse_aiger(); - void parse_xaiger(); - void parse_aiger_ascii(); - void parse_aiger_binary(); - void post_process(); - - RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal); -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/ast/Makefile.inc b/yosys/frontends/ast/Makefile.inc deleted file mode 100644 index 9e6eee1e8fb..00000000000 --- a/yosys/frontends/ast/Makefile.inc +++ /dev/null @@ -1,7 +0,0 @@ - -OBJS += frontends/ast/ast.o -OBJS += frontends/ast/simplify.o -OBJS += frontends/ast/genrtlil.o -OBJS += frontends/ast/dpicall.o -OBJS += frontends/ast/ast_binding.o - diff --git a/yosys/frontends/ast/ast.cc b/yosys/frontends/ast/ast.cc deleted file mode 100644 index 982943d1ba9..00000000000 --- a/yosys/frontends/ast/ast.cc +++ /dev/null @@ -1,1838 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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; - Module *current_module; - bool current_always_clocked; - dict current_memwr_count; - dict> current_memwr_visible; -} - -// 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_ENUM) - X(AST_ENUM_ITEM) - X(AST_FCALL) - X(AST_TO_BITS) - X(AST_TO_SIGNED) - X(AST_TO_UNSIGNED) - X(AST_SELFSZ) - X(AST_CAST_SIZE) - 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_SHIFTX) - X(AST_SHIFT) - 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_INTERFACE) - X(AST_INTERFACEPORT) - X(AST_INTERFACEPORTTYPE) - X(AST_MODPORT) - X(AST_MODPORTMEMBER) - X(AST_PACKAGE) - X(AST_WIRETYPE) - X(AST_TYPEDEF) - X(AST_STRUCT) - X(AST_UNION) - X(AST_STRUCT_ITEM) - X(AST_BIND) -#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->location.first_line, "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, AstNode *child4) -{ - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; - - this->type = type; - filename = current_filename; - is_input = false; - is_output = false; - is_reg = false; - is_logic = false; - is_signed = false; - is_string = false; - is_enum = false; - is_wand = false; - is_wor = false; - is_unsized = false; - was_checked = false; - range_valid = false; - range_swapped = false; - is_custom_type = false; - port_id = 0; - range_left = -1; - range_right = 0; - integer = 0; - realvalue = 0; - id2ast = NULL; - basic_prep = false; - lookahead = false; - - if (child1) - children.push_back(child1); - if (child2) - children.push_back(child2); - if (child3) - children.push_back(child3); - if (child4) - children.push_back(child4); -} - -// 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>", indent.c_str(), type_name.c_str(), loc_string().c_str()); - - 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] == State::S0 ? '0' : - bits[i-1] == State::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 (is_unsized) - fprintf(f, " unsized"); - if (basic_prep) - fprintf(f, " basic_prep"); - if (lookahead) - fprintf(f, " lookahead"); - 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, " ]"); - } - if (!multirange_swapped.empty()) { - fprintf(f, " multirange_swapped=["); - for (bool v : multirange_swapped) - fprintf(f, " %d", v); - fprintf(f, " ]"); - } - if (is_enum) { - fprintf(f, " type=enum"); - } - 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.size() > 1 && children[1]->type == AST_CONDX) - fprintf(f, "%s" "casex (", indent.c_str()); - else if (children.size() > 1 && children[1]->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 = "!"; } - if (0) { case AST_SELFSZ: txt = "@selfsz@"; } - 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_SHIFTX: txt = "@shiftx@"; } - if (0) { case AST_SHIFT: txt = "@shift@"; } - 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) ? State::S1 : State::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] == State::S1) << i; - else if (is_signed && !node->bits.empty()) - node->integer |= (node->bits.back() == State::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) ? State::S1 : State::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 != State::S0 && bit != State::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() const -{ - 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() const -{ - if (type == AST_REALVALUE) - { - AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue)); - RTLIL::Const val = strnode->asAttrConst(); - val.flags |= RTLIL::CONST_FLAG_REAL; - delete strnode; - return val; - } - - 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; -} - -std::string AstNode::loc_string() const -{ - return stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); -} - -void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) -{ - obj->attributes[ID::src] = ast->loc_string(); -} - -static bool param_has_no_default(const AstNode *param) { - const auto &children = param->children; - log_assert(param->type == AST_PARAMETER); - log_assert(children.size() <= 2); - return children.empty() || - (children.size() == 1 && children[0]->type == AST_RANGE); -} - -static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) -{ - log_assert(current_scope.empty()); - 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 if (!quiet) { - log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str()); - } - - AstModule *module = new AstModule; - current_module = module; - - module->ast = NULL; - module->name = ast->str; - set_src_attr(module, ast); - module->set_bool_attribute(ID::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) - { - for (const AstNode *node : ast->children) - if (node->type == AST_PARAMETER && param_has_no_default(node)) - log_file_error(node->filename, node->location.first_line, "Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str()); - - 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; - } - } - - // simplify this module or interface using the current design as context - // for lookup up ports and wires within cells - set_simplify_design_context(design); - while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } - set_simplify_design_context(nullptr); - - 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(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); - ast->attributes.erase(ID::whitebox); - } - - if (ast->attributes.count(ID::lib_whitebox)) { - if (!flag_lib || flag_nowb) { - delete ast->attributes.at(ID::lib_whitebox); - ast->attributes.erase(ID::lib_whitebox); - } else { - if (ast->attributes.count(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); - ast->attributes.erase(ID::whitebox); - } - AstNode *n = ast->attributes.at(ID::lib_whitebox); - ast->attributes[ID::whitebox] = n; - ast->attributes.erase(ID::lib_whitebox); - } - } - - if (!blackbox_module && ast->attributes.count(ID::blackbox)) { - AstNode *n = ast->attributes.at(ID::blackbox); - if (n->type != AST_CONSTANT) - log_file_error(ast->filename, ast->location.first_line, "Got blackbox attribute with non-constant value!\n"); - blackbox_module = n->asBool(); - } - - if (blackbox_module && ast->attributes.count(ID::whitebox)) { - AstNode *n = ast->attributes.at(ID::whitebox); - if (n->type != AST_CONSTANT) - log_file_error(ast->filename, ast->location.first_line, "Got whitebox attribute with non-constant value!\n"); - blackbox_module = !n->asBool(); - } - - if (ast->attributes.count(ID::noblackbox)) { - if (blackbox_module) { - AstNode *n = ast->attributes.at(ID::noblackbox); - if (n->type != AST_CONSTANT) - log_file_error(ast->filename, ast->location.first_line, "Got noblackbox attribute with non-constant value!\n"); - blackbox_module = !n->asBool(); - } - delete ast->attributes.at(ID::noblackbox); - ast->attributes.erase(ID::noblackbox); - } - - if (blackbox_module) - { - if (ast->attributes.count(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); - ast->attributes.erase(ID::whitebox); - } - - if (ast->attributes.count(ID::lib_whitebox)) { - delete ast->attributes.at(ID::lib_whitebox); - ast->attributes.erase(ID::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) { - 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(ID::blackbox) == 0) { - ast->attributes[ID::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->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - 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(); - current_scope.clear(); - } - else { - for (auto &attr : ast->attributes) { - if (attr.second->type != AST_CONSTANT) - continue; - module->attributes[attr.first] = attr.second->asAttrConst(); - } - for (const AstNode *node : ast->children) - if (node->type == AST_PARAMETER) - current_module->avail_parameters(node->str); - } - - if (ast->type == AST_INTERFACE) - module->set_bool_attribute(ID::is_interface); - module->ast = ast_before_simplify; - module->nolatches = flag_nolatches; - module->nomeminit = flag_nomeminit; - module->nomem2reg = flag_nomem2reg; - module->mem2reg = flag_mem2reg; - module->noblackbox = flag_noblackbox; - module->lib = flag_lib; - module->nowb = flag_nowb; - module->noopt = flag_noopt; - module->icells = flag_icells; - module->pwires = flag_pwires; - module->autowire = flag_autowire; - module->fixup_ports(); - - if (flag_dump_rtlil) { - log("Dumping generated RTLIL:\n"); - log_module(module); - log("--- END OF RTLIL DUMP ---\n"); - } - - design->add(current_module); - return current_module; -} - -RTLIL::Module * -AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, - RTLIL::Module *old_module, - AstNode *new_ast, - AstNode *original_ast) -{ - // The old module will be deleted. Rename and mark for deletion, using - // a static counter to make sure we get a unique name. - static unsigned counter; - std::ostringstream new_name; - new_name << old_module->name.str() - << "_before_process_and_replace_module_" - << counter; - ++counter; - - design->rename(old_module, new_name.str()); - old_module->set_bool_attribute(ID::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. - bool is_top = false; - if (old_module->get_bool_attribute(ID::initial_top)) { - old_module->attributes.erase(ID::initial_top); - is_top = true; - } - - // Generate RTLIL from AST for the new module and add to the design: - RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast); - - if (is_top) - new_module->set_bool_attribute(ID::top); - - return new_module; -} - -// renames identifiers in tasks and functions within a package -static void rename_in_package_stmts(AstNode *pkg) -{ - std::unordered_set idents; - for (AstNode *item : pkg->children) - idents.insert(item->str); - std::function rename = - [&rename, &idents, pkg](AstNode *node) { - for (AstNode *child : node->children) { - if (idents.count(child->str)) - child->str = pkg->str + "::" + child->str.substr(1); - rename(child); - } - }; - for (AstNode *item : pkg->children) - if (item->type == AST_FUNCTION || item->type == AST_TASK) - rename(item); -} - -// 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; - current_ast_mod = nullptr; - 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 (AstNode *child : current_ast->children) - { - if (child->type == AST_MODULE || child->type == AST_INTERFACE) - { - for (auto n : design->verilog_globals) - child->children.push_back(n->clone()); - - // append nodes from previous packages using package-qualified names - for (auto &n : design->verilog_packages) { - for (auto &o : n->children) { - AstNode *cloned_node = o->clone(); - // log("cloned node %s\n", type2str(cloned_node->type).c_str()); - if (cloned_node->type == AST_ENUM) { - for (auto &e : cloned_node->children) { - log_assert(e->type == AST_ENUM_ITEM); - e->str = n->str + std::string("::") + e->str.substr(1); - } - } else { - cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); - } - child->children.push_back(cloned_node); - } - } - - if (flag_icells && child->str.compare(0, 2, "\\$") == 0) - child->str = child->str.substr(1); - - bool defer_local = defer; - if (!defer_local) - for (const AstNode *node : child->children) - if (node->type == AST_PARAMETER && param_has_no_default(node)) - { - log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str()); - defer_local = true; - break; - } - - - if (defer_local) - child->str = "$abstract" + child->str; - - if (design->has(child->str)) { - RTLIL::Module *existing_mod = design->module(child->str); - if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { - log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); - } else if (nooverwrite) { - log("Ignoring re-definition of module `%s' at %s.\n", - child->str.c_str(), child->loc_string().c_str()); - continue; - } else { - log("Replacing existing%s module `%s' at %s.\n", - existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", - child->str.c_str(), child->loc_string().c_str()); - design->remove(existing_mod); - } - } - - process_module(design, child, defer_local); - current_ast_mod = nullptr; - } - else if (child->type == AST_PACKAGE) { - // process enum/other declarations - child->simplify(true, false, false, 1, -1, false, false); - rename_in_package_stmts(child); - design->verilog_packages.push_back(child->clone()); - current_scope.clear(); - } - else if (child->type == AST_BIND) { - // top-level bind construct - for (RTLIL::Binding *binding : child->genBindings()) - design->add(binding); - } - else { - // must be global definition - if (child->type == AST_PARAMETER) - child->type = AST_LOCALPARAM; // cannot be overridden - design->verilog_globals.push_back(child->clone()); - current_scope.clear(); - } - } -} - -// 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 w : intfmodule->wires()){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); - std::string origname = log_id(w->name); - 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); - } - } -} - -// AstModules may contain cells marked with ID::reprocess_after, which indicates -// that it should be reprocessed once the specified module has been elaborated. -bool AstModule::reprocess_if_necessary(RTLIL::Design *design) -{ - for (const RTLIL::Cell *cell : cells()) - { - std::string modname = cell->get_string_attribute(ID::reprocess_after); - if (modname.empty()) - continue; - if (design->module(modname) || design->module("$abstract" + modname)) { - log("Reprocessing module %s because instantiated module %s has become available.\n", - log_id(name), log_id(modname)); - loadconfig(); - process_and_replace_module(design, this, ast, NULL); - return true; - } - } - return false; -} - -// 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::expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) -{ - loadconfig(); - - AstNode *new_ast = ast->clone(); - for (auto &intf : local_interfaces) { - std::string intfname = intf.first.str(); - RTLIL::Module *intfmodule = intf.second; - for (auto w : intfmodule->wires()){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); - std::string newname = log_id(w->name); - 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->module(interface_type) != nullptr) { - // 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->module(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; - } - } - } - } - } - - // Generate RTLIL from AST for the new module and add to the design, - // renaming this module to move it out of the way. - RTLIL::Module* new_module = - process_and_replace_module(design, this, new_ast, ast_before_replacing_interface_ports); - - delete new_ast; - - // Set the attribute "interfaces_replaced_in_module" so that it does not happen again. - new_module->set_bool_attribute(ID::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, const dict ¶meters, const dict &interfaces, const dict &modports, bool /*mayfail*/) -{ - AstNode *new_ast = NULL; - std::string modname = derive_common(design, parameters, &new_ast); - - // 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; - } - - std::string new_modname = modname; - if (has_interfaces) - new_modname += "$interfaces$" + interf_info; - - - if (!design->has(new_modname)) { - if (!new_ast) { - auto mod = dynamic_cast(design->module(modname)); - new_ast = mod->ast->clone(); - } - modname = new_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); - } - - process_module(design, 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->wire(intf.first) != nullptr) { - // Normally, removing wires would be batched together as it's an - // expensive operation, however, in this case doing so would mean - // that a cell with the same name cannot be created (below)... - // Since we won't expect many interfaces to exist in a module, - // we can let this slide... - pool to_remove; - to_remove.insert(mod->wire(intf.first)); - mod->remove(to_remove); - 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(ID::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(ID::interfaces_replaced_in_module); - } - - } else { - modname = new_modname; - 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, const dict ¶meters, bool /*mayfail*/) -{ - bool quiet = lib || attributes.count(ID::blackbox) || attributes.count(ID::whitebox); - - AstNode *new_ast = NULL; - std::string modname = derive_common(design, parameters, &new_ast, quiet); - - if (!design->has(modname) && new_ast) { - new_ast->str = modname; - process_module(design, new_ast, false, NULL, quiet); - design->module(modname)->check(); - } else if (!quiet) { - log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); - } - - delete new_ast; - return modname; -} - -static std::string serialize_param_value(const RTLIL::Const &val) { - std::string res; - if (val.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) - res.push_back('t'); - if (val.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) - res.push_back('s'); - if (val.flags & RTLIL::ConstFlags::CONST_FLAG_REAL) - res.push_back('r'); - res += stringf("%d", GetSize(val)); - res.push_back('\''); - for (int i = GetSize(val) - 1; i >= 0; i--) { - switch (val.bits[i]) { - case RTLIL::State::S0: res.push_back('0'); break; - case RTLIL::State::S1: res.push_back('1'); break; - case RTLIL::State::Sx: res.push_back('x'); break; - case RTLIL::State::Sz: res.push_back('z'); break; - case RTLIL::State::Sa: res.push_back('?'); break; - case RTLIL::State::Sm: res.push_back('m'); break; - } - } - return res; -} - -std::string AST::derived_module_name(std::string stripped_name, const std::vector> ¶meters) { - std::string para_info; - for (const auto &elem : parameters) - para_info += stringf("%s=%s", elem.first.c_str(), serialize_param_value(elem.second).c_str()); - - if (para_info.size() > 60) - return "$paramod$" + sha1(para_info) + stripped_name; - else - return "$paramod" + stripped_name + para_info; -} - -// create a new parametric module (when needed) and return the name of the generated module -std::string AstModule::derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet) -{ - std::string stripped_name = name.str(); - (*new_ast_out) = nullptr; - - if (stripped_name.compare(0, 9, "$abstract") == 0) - stripped_name = stripped_name.substr(9); - - int para_counter = 0; - std::vector> named_parameters; - for (const auto child : ast->children) { - if (child->type != AST_PARAMETER) - continue; - para_counter++; - auto it = parameters.find(child->str); - if (it != parameters.end()) { - if (!quiet) - log("Parameter %s = %s\n", child->str.c_str(), log_signal(it->second)); - named_parameters.emplace_back(child->str, it->second); - continue; - } - it = parameters.find(stringf("$%d", para_counter)); - if (it != parameters.end()) { - if (!quiet) - log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(it->second)); - named_parameters.emplace_back(child->str, it->second); - continue; - } - } - - std::string modname = stripped_name; - if (parameters.size()) // not named_parameters to cover hierarchical defparams - modname = derived_module_name(stripped_name, named_parameters); - - if (design->has(modname)) - return modname; - - if (!quiet) - log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); - loadconfig(); - - pool rewritten; - rewritten.reserve(GetSize(parameters)); - - AstNode *new_ast = ast->clone(); - if (!new_ast->attributes.count(ID::hdlname)) - new_ast->attributes[ID::hdlname] = AstNode::mkconst_str(stripped_name); - - para_counter = 0; - for (auto child : new_ast->children) { - if (child->type != AST_PARAMETER) - continue; - para_counter++; - auto it = parameters.find(child->str); - if (it != parameters.end()) { - if (!quiet) - log("Parameter %s = %s\n", child->str.c_str(), log_signal(it->second)); - goto rewrite_parameter; - } - it = parameters.find(stringf("$%d", para_counter)); - if (it != parameters.end()) { - if (!quiet) - log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(it->second)); - goto rewrite_parameter; - } - continue; - rewrite_parameter: - if (param_has_no_default(child)) - child->children.insert(child->children.begin(), nullptr); - delete child->children.at(0); - if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) { - child->children[0] = new AstNode(AST_REALVALUE); - child->children[0]->realvalue = std::stod(it->second.decode_string()); - } else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0) - child->children[0] = AstNode::mkconst_str(it->second.decode_string()); - else - child->children[0] = AstNode::mkconst_bits(it->second.bits, (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0); - rewritten.insert(it->first); - } - - if (GetSize(rewritten) < GetSize(parameters)) - for (const auto ¶m : parameters) { - if (rewritten.count(param.first)) - continue; - 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); - } - - (*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->noblackbox = noblackbox; - new_mod->lib = lib; - new_mod->nowb = nowb; - new_mod->noopt = noopt; - new_mod->icells = icells; - new_mod->pwires = pwires; - new_mod->autowire = autowire; - - return new_mod; -} - -void AstModule::loadconfig() const -{ - 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; -} - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/ast/ast.h b/yosys/frontends/ast/ast.h deleted file mode 100644 index 142ec0801d4..00000000000 --- a/yosys/frontends/ast/ast.h +++ /dev/null @@ -1,425 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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_ENUM, - AST_ENUM_ITEM, - - AST_FCALL, - AST_TO_BITS, - AST_TO_SIGNED, - AST_TO_UNSIGNED, - AST_SELFSZ, - AST_CAST_SIZE, - 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_SHIFTX, - AST_SHIFT, - 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, - - AST_WIRETYPE, - AST_TYPEDEF, - AST_STRUCT, - AST_UNION, - AST_STRUCT_ITEM, - AST_BIND - }; - - struct AstSrcLocType { - unsigned int first_line, last_line; - unsigned int first_column, last_column; - AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {} - AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} - }; - - // 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, is_custom_type; - int port_id, range_left, range_right; - uint32_t integer; - double realvalue; - // set for IDs typed to an enumeration, not used - bool is_enum; - - // if this is a multirange memory then this vector contains offset and length of each dimension - std::vector multirange_dimensions; - std::vector multirange_swapped; // true if range is swapped - - // 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 used for ID references in RHS expressions that should use the "new" value for non-blocking assignments - bool lookahead; - - // 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; - AstSrcLocType location; - - // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr); - 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); - void replace_result_wire_name_in_function(const std::string &from, const std::string &to); - AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); - void expand_genblock(const std::string &prefix); - void label_genblks(std::set& existing, int &counter); - 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); - bool detect_latch(const std::string &var); - const RTLIL::Module* lookup_cell_module(); - - // additional functionality for evaluating constant functions - struct varinfo_t { - RTLIL::Const val; - int offset; - bool range_swapped; - bool is_signed; - AstNode *arg = nullptr; - bool explicitly_sized; - }; - bool has_const_only_constructs(); - bool replace_variables(std::map &variables, AstNode *fcall, bool must_succeed); - AstNode *eval_const_function(AstNode *fcall, bool must_succeed); - bool is_simple_const_expr(); - std::string process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint); - - bool is_recursive_function() const; - std::pair get_tern_choice(); - - // 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; - - // Generate RTLIL for a bind construct - std::vector genBindings() 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, bool sgn, 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() const; - RTLIL::Const asParaConst() const; - 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); - - // helpers for enum - void allocateDefaultEnumValues(); - void annotateTypedEnums(AstNode *template_node); - - // helpers for locations - std::string loc_string() const; - - // Helper for looking up identifiers which are prefixed with the current module name - std::string try_pop_module_prefix() const; - }; - - // 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() override; - RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail) override; - RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail) override; - std::string derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet = false); - void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) override; - bool reprocess_if_necessary(RTLIL::Design *design) override; - RTLIL::Module *clone() const override; - void loadconfig() const; - }; - - // 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); - - // Helper for setting the src attribute. - void set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast); - - // struct helper exposed from simplify for genrtlil - AstNode *make_struct_member_range(AstNode *node, AstNode *member_node); - - // generate standard $paramod... derived module name; parameters should be - // in the order they are declared in the instantiated module - std::string derived_module_name(std::string stripped_name, const std::vector> ¶meters); - - // used to provide simplify() access to the current design for looking up - // modules, ports, wires, etc. - void set_simplify_design_context(const RTLIL::Design *design); -} - -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 RTLIL::Module *current_module; - extern bool current_always_clocked; - extern dict current_memwr_count; - extern dict> current_memwr_visible; - struct LookaheadRewriter; - struct ProcessGenerator; - - // Create and add a new AstModule from new_ast, then use it to replace - // old_module in design, renaming old_module to move it out of the way. - // Return the new module. - // - // If original_ast is not null, it will be used as the AST node for the - // new module. Otherwise, new_ast will be used. - RTLIL::Module * - process_and_replace_module(RTLIL::Design *design, - RTLIL::Module *old_module, - AST::AstNode *new_ast, - AST::AstNode *original_ast = nullptr); -} - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/ast/ast_binding.cc b/yosys/frontends/ast/ast_binding.cc deleted file mode 100644 index c20d1df4d6e..00000000000 --- a/yosys/frontends/ast/ast_binding.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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_binding.h" -#include "ast.h" - -YOSYS_NAMESPACE_BEGIN - -using namespace AST_INTERNAL; - -AST::Binding::Binding(RTLIL::IdString target_type, - RTLIL::IdString target_name, - const AstNode &cell) - : RTLIL::Binding(target_type, target_name), - ast_node(cell.clone()) -{ - log_assert(cell.type == AST_CELL); -} - -std::string -AST::Binding::describe() const -{ - std::ostringstream oss; - oss << "directive to bind " << ast_node->str - << " to " << target_name.str(); - if (!target_type.empty()) - oss << " (target type: " - << target_type.str() - << ")"; - return oss.str(); -} - -PRIVATE_NAMESPACE_END diff --git a/yosys/frontends/ast/ast_binding.h b/yosys/frontends/ast/ast_binding.h deleted file mode 100644 index 641497d52d4..00000000000 --- a/yosys/frontends/ast/ast_binding.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 header declares the AST::Binding class - * - * This is used to support the bind directive and is to RTLIL::Binding as - * AST::AstModule is to RTLIL::Module, holding a syntax-level representation of - * cells until we get to a stage where they make sense. In the case of a bind - * directive, this is when we elaborate the design in the hierarchy pass. - * - */ - -#ifndef AST_BINDING_H -#define AST_BINDING_H - -#include "kernel/rtlil.h" -#include "kernel/binding.h" - -#include - -YOSYS_NAMESPACE_BEGIN - -namespace AST -{ - class Binding : public RTLIL::Binding - { - public: - Binding(RTLIL::IdString target_type, - RTLIL::IdString target_name, - const AstNode &cell); - - std::string describe() const override; - - private: - // The syntax-level representation of the cell to be bound. - std::unique_ptr ast_node; - }; -} - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/ast/dpicall.cc b/yosys/frontends/ast/dpicall.cc deleted file mode 100644 index 12a7e1183f7..00000000000 --- a/yosys/frontends/ast/dpicall.cc +++ /dev/null @@ -1,163 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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; void *ptr; } 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 if (argtypes[i] == "chandle") { - log(" arg %d (%s): %llx\n", i, argtypes[i].c_str(), (unsigned long long)args[i]->asInt(false)); - value_store[i].ptr = (void *)args[i]->asInt(args[i]->is_signed); - values[i] = &value_store[i].ptr; - types[i] = &ffi_type_pointer; - } 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 if (rtype == "chandle") { - types[args.size()] = &ffi_type_pointer; - values[args.size()] = &value_store[args.size()].ptr; - } 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 if (rtype == "chandle") { - uint64_t rawval = (uint64_t)value_store[args.size()].ptr; - std::vector bits(64); - for (int i = 0; i < 64; i++) - bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0; - newNode = AstNode::mkconst_bits(bits, false); - log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false)); - } 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 index 1016ef636c1..5c0b8802792 100644 --- a/yosys/frontends/ast/genrtlil.cc +++ b/yosys/frontends/ast/genrtlil.cc @@ -844,13 +844,14 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM || id_ast->type == AST_ENUM_ITEM) { 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, location.first_line, "Failed to detect width for parameter %s!\n", str.c_str()); + } 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, location.first_line, "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) { @@ -1375,6 +1376,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::SigChunk chunk; bool is_interface = false; + AST::AstNode *member_node = NULL; int add_undef_bits_msb = 0; int add_undef_bits_lsb = 0; @@ -1438,12 +1440,28 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.width = wire->width; chunk.offset = 0; + if ((member_node = get_struct_member(this))) { + // Clamp wire chunk to range of member within struct/union. + chunk.width = member_node->range_left - member_node->range_right + 1; + chunk.offset = member_node->range_right; + } + use_const_chunk: if (children.size() != 0) { if (children[0]->type != AST_RANGE) log_file_error(filename, location.first_line, "Single range expected.\n"); int source_width = id2ast->range_left - id2ast->range_right + 1; int source_offset = id2ast->range_right; + int chunk_left = source_width - 1; + int chunk_right = 0; + + if (member_node) { + // Clamp wire chunk to range of member within struct/union. + log_assert(!source_offset && !id2ast->range_swapped); + chunk_left = chunk.offset + chunk.width - 1; + chunk_right = chunk.offset; + } + 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(); @@ -1455,14 +1473,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) 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(); + if (member_node) + fake_ast->children[0]->attributes[ID::wiretype] = member_node->clone(); int fake_ast_width = 0; bool fake_ast_sign = true; fake_ast->children[1]->detectSignWidth(fake_ast_width, fake_ast_sign); RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(fake_ast_width, fake_ast_sign); - if (id2ast->range_right != 0) { - shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast_sign); + if (source_offset != 0) { + shift_val = current_module->Sub(NEW_ID, shift_val, source_offset, fake_ast_sign); fake_ast->children[1]->is_signed = true; } if (id2ast->range_swapped) { @@ -1478,10 +1498,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) return sig; } else { chunk.width = children[0]->range_left - children[0]->range_right + 1; - chunk.offset = children[0]->range_right - source_offset; + 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) { + chunk.offset = source_width - (chunk.offset + chunk.width); + if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) { if (chunk.width == 1) log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", str.c_str()); @@ -1490,12 +1510,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) 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; + if (chunk.offset + chunk.width - 1 > chunk_left) { + add_undef_bits_msb = (chunk.offset + chunk.width - 1) - chunk_left; chunk.width -= add_undef_bits_msb; } - if (chunk.offset < 0) { - add_undef_bits_lsb = -chunk.offset; + if (chunk.offset < chunk_right) { + add_undef_bits_lsb = chunk_right - chunk.offset; chunk.width -= add_undef_bits_lsb; chunk.offset += add_undef_bits_lsb; } diff --git a/yosys/frontends/ast/simplify.cc b/yosys/frontends/ast/simplify.cc deleted file mode 100644 index 2dbabca2851..00000000000 --- a/yosys/frontends/ast/simplify.cc +++ /dev/null @@ -1,5602 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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; - -// Process a format string and arguments for $display, $write, $sprintf, etc - -std::string AstNode::process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint) { - // Other arguments are placeholders. Process the string as we go through it - std::string sout; - 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, location.first_line, "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; - } - - bool got_len = false; - bool got_zlen = false; - int len_value = 0; - - while ('0' <= cformat && cformat <= '9') - { - if (!got_len && cformat == '0') - got_zlen = true; - - got_len = true; - len_value = 10*len_value + (cformat - '0'); - - cformat = sformat[++i]; - } - - // 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': - if (got_len && len_value != 0) - goto unsupported_format; - YS_FALLTHROUGH - case 'x': - case 'X': - if (next_arg >= GetSize(children)) - log_file_error(filename, location.first_line, "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, location.first_line, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str()); - break; - - case 'm': - case 'M': - if (got_len) - goto unsupported_format; - break; - - case 'l': - case 'L': - if (got_len) - goto unsupported_format; - break; - - default: - unsupported_format: - log_file_error(filename, location.first_line, "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': - sout += stringf("%d", node_arg->bitsAsConst().as_int()); - break; - - case 'x': - case 'X': - { - Const val = node_arg->bitsAsConst(); - - while (GetSize(val) % 4 != 0) - val.bits.push_back(State::S0); - - int len = GetSize(val) / 4; - for (int i = len; i < len_value; i++) - sout += got_zlen ? '0' : ' '; - - for (int i = len-1; i >= 0; i--) { - Const digit = val.extract(4*i, 4); - if (digit.is_fully_def()) - sout += stringf(cformat == 'x' ? "%x" : "%X", digit.as_int()); - else - sout += cformat == 'x' ? "x" : "X"; - } - } - break; - - case 'm': - case 'M': - sout += log_id(current_module->name); - break; - - case 'l': - case 'L': - sout += log_id(current_module->name); - break; - - default: - log_abort(); - } - } - - // not a format specifier - else - sout += sformat[i]; - } - return sout; -} - - -void AstNode::annotateTypedEnums(AstNode *template_node) -{ - //check if enum - if (template_node->attributes.count(ID::enum_type)) { - //get reference to enum node: - std::string enum_type = template_node->attributes[ID::enum_type]->str.c_str(); - // log("enum_type=%s (count=%lu)\n", enum_type.c_str(), current_scope.count(enum_type)); - // log("current scope:\n"); - // for (auto &it : current_scope) - // log(" %s\n", it.first.c_str()); - log_assert(current_scope.count(enum_type) == 1); - AstNode *enum_node = current_scope.at(enum_type); - log_assert(enum_node->type == AST_ENUM); - while (enum_node->simplify(true, false, false, 1, -1, false, true)) { } - //get width from 1st enum item: - log_assert(enum_node->children.size() >= 1); - AstNode *enum_item0 = enum_node->children[0]; - log_assert(enum_item0->type == AST_ENUM_ITEM); - int width; - if (!enum_item0->range_valid) - width = 1; - else if (enum_item0->range_swapped) - width = enum_item0->range_right - enum_item0->range_left + 1; - else - width = enum_item0->range_left - enum_item0->range_right + 1; - log_assert(width > 0); - //add declared enum items: - for (auto enum_item : enum_node->children){ - log_assert(enum_item->type == AST_ENUM_ITEM); - //get is_signed - bool is_signed; - if (enum_item->children.size() == 1){ - is_signed = false; - } else if (enum_item->children.size() == 2){ - log_assert(enum_item->children[1]->type == AST_RANGE); - is_signed = enum_item->children[1]->is_signed; - } else { - log_error("enum_item children size==%lu, expected 1 or 2 for %s (%s)\n", - enum_item->children.size(), - enum_item->str.c_str(), enum_node->str.c_str() - ); - } - //start building attribute string - std::string enum_item_str = "\\enum_value_"; - //get enum item value - if(enum_item->children[0]->type != AST_CONSTANT){ - log_error("expected const, got %s for %s (%s)\n", - type2str(enum_item->children[0]->type).c_str(), - enum_item->str.c_str(), enum_node->str.c_str() - ); - } - RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); - enum_item_str.append(val.as_string()); - //set attribute for available val to enum item name mappings - attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str); - } - } -} - -static bool name_has_dot(const std::string &name, std::string &struct_name) -{ - // check if plausible struct member name \sss.mmm - std::string::size_type pos; - if (name.substr(0, 1) == "\\" && (pos = name.find('.', 0)) != std::string::npos) { - struct_name = name.substr(0, pos); - return true; - } - return false; -} - -static AstNode *make_range(int left, int right, bool is_signed = false) -{ - // generate a pre-validated range node for a fixed signal range. - auto range = new AstNode(AST_RANGE); - range->range_left = left; - range->range_right = right; - range->range_valid = true; - range->children.push_back(AstNode::mkconst_int(left, true)); - range->children.push_back(AstNode::mkconst_int(right, true)); - range->is_signed = is_signed; - return range; -} - -static int range_width(AstNode *node, AstNode *rnode) -{ - log_assert(rnode->type==AST_RANGE); - if (!rnode->range_valid) { - log_file_error(node->filename, node->location.first_line, "Size must be constant in packed struct/union member %s\n", node->str.c_str()); - - } - // note: range swapping has already been checked for - return rnode->range_left - rnode->range_right + 1; -} - -[[noreturn]] static void struct_array_packing_error(AstNode *node) -{ - log_file_error(node->filename, node->location.first_line, "Unpacked array in packed struct/union member %s\n", node->str.c_str()); -} - -static void save_struct_array_width(AstNode *node, int width) -{ - // stash the stride for the array - node->multirange_dimensions.push_back(width); - -} - -static void save_struct_range_swapped(AstNode *node, bool range_swapped) -{ - node->multirange_swapped.push_back(range_swapped); - -} - -static int size_packed_struct(AstNode *snode, int base_offset) -{ - // Struct members will be laid out in the structure contiguously from left to right. - // Union members all have zero offset from the start of the union. - // Determine total packed size and assign offsets. Store these in the member node. - bool is_union = (snode->type == AST_UNION); - int offset = 0; - int packed_width = -1; - // examine members from last to first - for (auto it = snode->children.rbegin(); it != snode->children.rend(); ++it) { - auto node = *it; - int width; - if (node->type == AST_STRUCT || node->type == AST_UNION) { - // embedded struct or union - width = size_packed_struct(node, base_offset + offset); - // set range of struct - node->range_right = base_offset + offset; - node->range_left = base_offset + offset + width - 1; - node->range_valid = true; - } - else { - log_assert(node->type == AST_STRUCT_ITEM); - if (node->children.size() > 0 && node->children[0]->type == AST_RANGE) { - // member width e.g. bit [7:0] a - width = range_width(node, node->children[0]); - if (node->children.size() == 2) { - // Unpacked array. Note that this is a Yosys extension; only packed data types - // and integer data types are allowed in packed structs / unions in SystemVerilog. - if (node->children[1]->type == AST_RANGE) { - // Unpacked array, e.g. bit [63:0] a [0:3] - auto rnode = node->children[1]; - // C-style array size, e.g. bit [63:0] a [4] - bool c_type = rnode->children.size() == 1; - int array_count = c_type ? rnode->range_left : range_width(node, rnode); - save_struct_array_width(node, array_count); - save_struct_range_swapped(node, rnode->range_swapped || c_type); - save_struct_array_width(node, width); - save_struct_range_swapped(node, node->children[0]->range_swapped); - width *= array_count; - } - else { - // The Yosys extension for unpacked arrays in packed structs / unions - // only supports memories, i.e. e.g. logic [7:0] a [256] - see above. - struct_array_packing_error(node); - } - } else { - // Vector - save_struct_array_width(node, width); - save_struct_range_swapped(node, node->children[0]->range_swapped); - } - // range nodes are now redundant - for (AstNode *child : node->children) - delete child; - node->children.clear(); - } - else if (node->children.size() > 0 && node->children[0]->type == AST_MULTIRANGE) { - // Packed array, e.g. bit [3:0][63:0] a - if (node->children.size() != 1) { - // The Yosys extension for unpacked arrays in packed structs / unions - // only supports memories, i.e. e.g. logic [7:0] a [256] - see above. - struct_array_packing_error(node); - } - width = 1; - for (auto rnode : node->children[0]->children) { - int rwidth = range_width(node, rnode); - save_struct_array_width(node, rwidth); - save_struct_range_swapped(node, rnode->range_swapped); - width *= rwidth; - } - // range nodes are now redundant - for (AstNode *child : node->children) - delete child; - node->children.clear(); - } - else if (node->range_left < 0) { - // 1 bit signal: bit, logic or reg - width = 1; - } - else { - // already resolved and compacted - width = node->range_left - node->range_right + 1; - } - if (is_union) { - node->range_right = base_offset; - node->range_left = base_offset + width - 1; - } - else { - node->range_right = base_offset + offset; - node->range_left = base_offset + offset + width - 1; - } - node->range_valid = true; - } - if (is_union) { - // check that all members have the same size - if (packed_width == -1) { - // first member - packed_width = width; - } - else { - if (packed_width != width) { - - log_file_error(node->filename, node->location.first_line, "member %s of a packed union has %d bits, expecting %d\n", node->str.c_str(), width, packed_width); - } - } - } - else { - offset += width; - } - } - return (is_union ? packed_width : offset); -} - -[[noreturn]] static void struct_op_error(AstNode *node) -{ - log_file_error(node->filename, node->location.first_line, "Unsupported operation for struct/union member %s\n", node->str.c_str()+1); -} - -static AstNode *node_int(int ival) -{ - return AstNode::mkconst_int(ival, true); -} - -static AstNode *multiply_by_const(AstNode *expr_node, int stride) -{ - return new AstNode(AST_MUL, expr_node, node_int(stride)); -} - -static AstNode *normalize_struct_index(AstNode *expr, AstNode *member_node, int dimension) -{ - expr = expr->clone(); - - if (member_node->multirange_swapped[dimension]) { - // The dimension has swapped range; swap index into the struct accordingly. - int msb = member_node->multirange_dimensions[dimension] - 1; - expr = new AstNode(AST_SUB, node_int(msb), expr); - } - - return expr; -} - -static AstNode *struct_index_lsb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *member_node, int dimension, int &stride) -{ - stride /= member_node->multirange_dimensions[dimension]; - auto right = normalize_struct_index(rnode->children.back(), member_node, dimension); - auto offset = stride > 1 ? multiply_by_const(right, stride) : right; - return new AstNode(AST_ADD, lsb_offset, offset); -} - -static AstNode *struct_index_msb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *member_node, int dimension, int stride) -{ - log_assert(rnode->children.size() <= 2); - - // Offset to add to LSB - AstNode *offset; - if (rnode->children.size() == 1) { - // Index, e.g. s.a[i] - offset = node_int(stride - 1); - } - else { - // rnode->children.size() == 2 - // Slice, e.g. s.a[i:j] - auto left = normalize_struct_index(rnode->children[0], member_node, dimension); - auto right = normalize_struct_index(rnode->children[1], member_node, dimension); - offset = new AstNode(AST_SUB, left, right); - if (stride > 1) { - // offset = (msb - lsb + 1)*stride - 1 - auto slice_width = new AstNode(AST_ADD, offset, node_int(1)); - offset = new AstNode(AST_SUB, multiply_by_const(slice_width, stride), node_int(1)); - } - } - - return new AstNode(AST_ADD, lsb_offset, offset); -} - - -AstNode *AST::make_struct_member_range(AstNode *node, AstNode *member_node) -{ - // Work out the range in the packed array that corresponds to a struct member - // taking into account any range operations applicable to the current node - // such as array indexing or slicing - int range_left = member_node->range_left; - int range_right = member_node->range_right; - if (node->children.empty()) { - // no range operations apply, return the whole width - return make_range(range_left, range_right); - } - - if (node->children.size() != 1) { - struct_op_error(node); - } - - // Range operations - auto rnode = node->children[0]; - auto lsb_offset = node_int(member_node->range_right); - int stride = range_left - range_right + 1; - size_t i = 0; - - // Calculate LSB offset for the final index / slice - if (rnode->type == AST_RANGE) { - lsb_offset = struct_index_lsb_offset(lsb_offset, rnode, member_node, i, stride); - } - else if (rnode->type == AST_MULTIRANGE) { - // Add offset for each dimension - auto mrnode = rnode; - for (i = 0; i < mrnode->children.size(); i++) { - rnode = mrnode->children[i]; - lsb_offset = struct_index_lsb_offset(lsb_offset, rnode, member_node, i, stride); - } - i--; // Step back to the final index / slice - } - else { - struct_op_error(node); - } - - // Calculate MSB offset for the final index / slice - auto msb_offset = struct_index_msb_offset(lsb_offset->clone(), rnode, member_node, i, stride); - - return new AstNode(AST_RANGE, msb_offset, lsb_offset); -} - -static void add_members_to_scope(AstNode *snode, std::string name) -{ - // add all the members in a struct or union to local scope - // in case later referenced in assignments - log_assert(snode->type==AST_STRUCT || snode->type==AST_UNION); - for (auto *node : snode->children) { - auto member_name = name + "." + node->str; - current_scope[member_name] = node; - if (node->type != AST_STRUCT_ITEM) { - // embedded struct or union - add_members_to_scope(node, name + "." + node->str); - } - } -} - -static int get_max_offset(AstNode *node) -{ - // get the width from the MS member in the struct - // as members are laid out from left to right in the packed wire - log_assert(node->type==AST_STRUCT || node->type==AST_UNION); - while (node->type != AST_STRUCT_ITEM) { - node = node->children[0]; - } - return node->range_left; -} - -static AstNode *make_packed_struct(AstNode *template_node, std::string &name) -{ - // create a wire for the packed struct - auto wnode = new AstNode(AST_WIRE); - wnode->str = name; - wnode->is_logic = true; - wnode->range_valid = true; - wnode->is_signed = template_node->is_signed; - int offset = get_max_offset(template_node); - auto range = make_range(offset, 0); - wnode->children.push_back(range); - // make sure this node is the one in scope for this name - current_scope[name] = wnode; - // add all the struct members to scope under the wire's name - add_members_to_scope(template_node, name); - return wnode; -} - -// check if a node or its children contains an assignment to the given variable -static bool node_contains_assignment_to(const AstNode* node, const AstNode* var) -{ - if (node->type == AST_ASSIGN_EQ || node->type == AST_ASSIGN_LE) { - // current node is iteslf an assignment - log_assert(node->children.size() >= 2); - const AstNode* lhs = node->children[0]; - if (lhs->type == AST_IDENTIFIER && lhs->str == var->str) - return false; - } - for (const AstNode* child : node->children) { - // if this child shadows the given variable - if (child != var && child->str == var->str && child->type == AST_WIRE) - break; // skip the remainder of this block/scope - // depth-first short circuit - if (!node_contains_assignment_to(child, var)) - return false; - } - return true; -} - -static std::string prefix_id(const std::string &prefix, const std::string &str) -{ - log_assert(!prefix.empty() && (prefix.front() == '$' || prefix.front() == '\\')); - log_assert(!str.empty() && (str.front() == '$' || str.front() == '\\')); - log_assert(prefix.back() == '.'); - if (str.front() == '\\') - return prefix + str.substr(1); - return prefix + str; -} - -// direct access to this global should be limited to the following two functions -static const RTLIL::Design *simplify_design_context = nullptr; - -void AST::set_simplify_design_context(const RTLIL::Design *design) -{ - log_assert(!simplify_design_context || !design); - simplify_design_context = design; -} - -// lookup the module with the given name in the current design context -static const RTLIL::Module* lookup_module(const std::string &name) -{ - return simplify_design_context->module(name); -} - -const RTLIL::Module* AstNode::lookup_cell_module() -{ - log_assert(type == AST_CELL); - - auto reprocess_after = [this] (const std::string &modname) { - if (!attributes.count(ID::reprocess_after)) - attributes[ID::reprocess_after] = AstNode::mkconst_str(modname); - }; - - const AstNode *celltype = nullptr; - for (const AstNode *child : children) - if (child->type == AST_CELLTYPE) { - celltype = child; - break; - } - log_assert(celltype != nullptr); - - const RTLIL::Module *module = lookup_module(celltype->str); - if (!module) - module = lookup_module("$abstract" + celltype->str); - if (!module) { - if (celltype->str.at(0) != '$') - reprocess_after(celltype->str); - return nullptr; - } - - // build a mapping from true param name to param value - size_t para_counter = 0; - dict cell_params_map; - for (AstNode *child : children) { - if (child->type != AST_PARASET) - continue; - - if (child->str.empty() && para_counter >= module->avail_parameters.size()) - return nullptr; // let hierarchy handle this error - IdString paraname = child->str.empty() ? module->avail_parameters[para_counter++] : child->str; - - const AstNode *value = child->children[0]; - if (value->type != AST_REALVALUE && value->type != AST_CONSTANT) - return nullptr; // let genrtlil handle this error - cell_params_map[paraname] = value->asParaConst(); - } - - // put the parameters in order and generate the derived module name - std::vector> named_parameters; - for (RTLIL::IdString param : module->avail_parameters) { - auto it = cell_params_map.find(param); - if (it != cell_params_map.end()) - named_parameters.emplace_back(it->first, it->second); - } - std::string modname = celltype->str; - if (cell_params_map.size()) // not named_parameters to cover hierarchical defparams - modname = derived_module_name(celltype->str, named_parameters); - - // try to find the resolved module - module = lookup_module(modname); - if (!module) { - reprocess_after(modname); - return nullptr; - } - return module; -} - -// returns whether an expression contains an unbased unsized literal; does not -// check the literal exists in a self-determined context -static bool contains_unbased_unsized(const AstNode *node) -{ - if (node->type == AST_CONSTANT) - return node->is_unsized; - for (const AstNode *child : node->children) - if (contains_unbased_unsized(child)) - return true; - return false; -} - -// adds a wire to the current module with the given name that matches the -// dimensions of the given wire reference -void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str) -{ - AstNode *left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true); - AstNode *right = AstNode::mkconst_int(ref->start_offset, true); - if (ref->upto) - std::swap(left, right); - AstNode *range = new AstNode(AST_RANGE, left, right); - - AstNode *wire = new AstNode(AST_WIRE, range); - wire->is_signed = ref->is_signed; - wire->is_logic = true; - wire->str = str; - - current_ast_mod->children.push_back(wire); - current_scope[str] = wire; -} - -enum class IdentUsage { - NotReferenced, // target variable is neither read or written in the block - Assigned, // target variable is always assigned before use - SyncRequired, // target variable may be used before it has been assigned -}; - -// determines whether a local variable a block is always assigned before it is -// used, meaning the nosync attribute can automatically be added to that -// variable -static IdentUsage always_asgn_before_use(const AstNode *node, const std::string &target) -{ - // This variable has been referenced before it has necessarily been assigned - // a value in this procedure. - if (node->type == AST_IDENTIFIER && node->str == target) - return IdentUsage::SyncRequired; - - // For case statements (which are also used for if/else), we check each - // possible branch. If the variable is assigned in all branches, then it is - // assigned, and a sync isn't required. If it used before assignment in any - // branch, then a sync is required. - if (node->type == AST_CASE) { - bool all_defined = true; - bool any_used = false; - bool has_default = false; - for (const AstNode *child : node->children) { - if (child->type == AST_COND && child->children.at(0)->type == AST_DEFAULT) - has_default = true; - IdentUsage nested = always_asgn_before_use(child, target); - if (nested != IdentUsage::Assigned && child->type == AST_COND) - all_defined = false; - if (nested == IdentUsage::SyncRequired) - any_used = true; - } - if (any_used) - return IdentUsage::SyncRequired; - else if (all_defined && has_default) - return IdentUsage::Assigned; - else - return IdentUsage::NotReferenced; - } - - // Check if this is an assignment to the target variable. For simplicity, we - // don't analyze sub-ranges of the variable. - if (node->type == AST_ASSIGN_EQ) { - const AstNode *ident = node->children.at(0); - if (ident->type == AST_IDENTIFIER && ident->str == target) - return IdentUsage::Assigned; - } - - for (const AstNode *child : node->children) { - IdentUsage nested = always_asgn_before_use(child, target); - if (nested != IdentUsage::NotReferenced) - return nested; - } - return IdentUsage::NotReferenced; -} - -static const std::string auto_nosync_prefix = "\\AutoNosync"; - -// mark a local variable in an always_comb block for automatic nosync -// consideration -static void mark_auto_nosync(AstNode *block, const AstNode *wire) -{ - log_assert(block->type == AST_BLOCK); - log_assert(wire->type == AST_WIRE); - block->attributes[auto_nosync_prefix + wire->str] = AstNode::mkconst_int(1, - false); -} - -// block names can be prefixed with an explicit scope during elaboration -static bool is_autonamed_block(const std::string &str) { - size_t last_dot = str.rfind('.'); - // unprefixed names: autonamed if the first char is a dollar sign - if (last_dot == std::string::npos) - return str.at(0) == '$'; // e.g., `$fordecl_block$1` - // prefixed names: autonamed if the final chunk begins with a dollar sign - return str.rfind(".$") == last_dot; // e.g., `\foo.bar.$fordecl_block$1` -} - -// check a procedural block for auto-nosync markings, remove them, and add -// nosync to local variables as necessary -static void check_auto_nosync(AstNode *node) -{ - std::vector attrs_to_drop; - for (const auto& elem : node->attributes) { - // skip attributes that don't begin with the prefix - if (elem.first.compare(0, auto_nosync_prefix.size(), - auto_nosync_prefix.c_str())) - continue; - - // delete and remove the attribute once we're done iterating - attrs_to_drop.push_back(elem.first); - - // find the wire based on the attribute - std::string wire_name = elem.first.substr(auto_nosync_prefix.size()); - auto it = current_scope.find(wire_name); - if (it == current_scope.end()) - continue; - - // analyze the usage of the local variable in this block - IdentUsage ident_usage = always_asgn_before_use(node, wire_name); - if (ident_usage != IdentUsage::Assigned) - continue; - - // mark the wire with `nosync` - AstNode *wire = it->second; - log_assert(wire->type == AST_WIRE); - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); - } - - // remove the attributes we've "consumed" - for (const RTLIL::IdString &str : attrs_to_drop) { - auto it = node->attributes.find(str); - delete it->second; - node->attributes.erase(it); - } - - // check local variables in any nested blocks - for (AstNode *child : node->children) - check_auto_nosync(child); -} - -// 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 overly long or deeply nested expressions, or excessive recursion?\n"); - deep_recursion_warning = false; - } - - static bool unevaluated_tern_branch = 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(), location.first_line, 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(ID::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(ID::nomem2reg)) - continue; - - if (mem->get_bool_attribute(ID::nomeminit) || get_bool_attribute(ID::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; - for (auto &it : node->attributes) - if (it.first != ID::mem2reg) - reg->attributes.emplace(it.first, it.second->clone()); - reg->filename = node->filename; - reg->location = node->location; - 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; - - // 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, location.first_line, "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, location.first_line, "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, location.first_line, "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, location.first_line, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str()); - std::string sformat = node_string->bitsAsConst().decode_string(); - std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint); - // 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_ENUM_ITEM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX || type == AST_TYPEDEF) - const_fold = true; - if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM)) - 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::set existing; - int counter = 0; - label_genblks(existing, counter); - 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(ID::dynports)) - delete attributes.at(ID::dynports); - attributes[ID::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, location.first_line, "Incompatible re-declaration of wire %s.\n", node->str.c_str()); - continue; - } - this_wire_scope[node->str] = node; - } - // these nodes appear at the top level in a module and can define names - 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 || - node->type == AST_TYPEDEF) { - backup_scope[node->str] = current_scope[node->str]; - current_scope[node->str] = node; - } - if (node->type == AST_ENUM) { - current_scope[node->str] = node; - for (auto enode : node->children) { - log_assert(enode->type==AST_ENUM_ITEM); - if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode; - else - log_file_error(filename, location.first_line, "enum item %s already exists\n", enode->str.c_str()); - } - } - } - 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 || node->type == AST_TYPEDEF) - while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) - did_something = true; - if (node->type == AST_ENUM) { - for (auto enode : node->children){ - log_assert(enode->type==AST_ENUM_ITEM); - while (node->simplify(true, false, false, 1, -1, false, in_param)) - did_something = true; - } - } - } - - for (AstNode *child : children) - if (child->type == AST_ALWAYS && - child->attributes.count(ID::always_comb)) - check_auto_nosync(child); - } - - // create name resolution entries for all objects with names - if (type == AST_PACKAGE) { - //add names to package scope - for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; - // these nodes appear at the top level in a package and can define names - if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_TYPEDEF || node->type == AST_FUNCTION || node->type == AST_TASK) { - current_scope[node->str] = node; - } - if (node->type == AST_ENUM) { - current_scope[node->str] = node; - for (auto enode : node->children) { - log_assert(enode->type==AST_ENUM_ITEM); - if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode; - else - log_file_error(filename, location.first_line, "enum item %s already exists in package\n", enode->str.c_str()); - } - } - } - } - - - 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, location.first_line, "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; - } - } - - if (type == AST_CELL) { - bool lookup_suggested = false; - - for (AstNode *child : children) { - // simplify any parameters to constants - if (child->type == AST_PARASET) - while (child->simplify(true, false, false, 1, -1, false, true)) { } - - // look for patterns which _may_ indicate ambiguity requiring - // resolution of the underlying module - if (child->type == AST_ARGUMENT) { - if (child->children.size() != 1) - continue; - const AstNode *value = child->children[0]; - if (value->type == AST_IDENTIFIER) { - const AstNode *elem = value->id2ast; - if (elem == nullptr) { - if (current_scope.count(value->str)) - elem = current_scope.at(value->str); - else - continue; - } - if (elem->type == AST_MEMORY) - // need to determine is the is a read or wire - lookup_suggested = true; - else if (elem->type == AST_WIRE && elem->is_signed && !value->children.empty()) - // this may be a fully sliced signed wire which needs - // to be indirected to produce an unsigned connection - lookup_suggested = true; - } - else if (contains_unbased_unsized(value)) - // unbased unsized literals extend to width of the context - lookup_suggested = true; - } - } - - const RTLIL::Module *module = nullptr; - if (lookup_suggested) - module = lookup_cell_module(); - if (module) { - size_t port_counter = 0; - for (AstNode *child : children) { - if (child->type != AST_ARGUMENT) - continue; - - // determine the full name of port this argument is connected to - RTLIL::IdString port_name; - if (child->str.size()) - port_name = child->str; - else { - if (port_counter >= module->ports.size()) - log_file_error(filename, location.first_line, - "Cell instance has more ports than the module!\n"); - port_name = module->ports[port_counter++]; - } - - // find the port's wire in the underlying module - const RTLIL::Wire *ref = module->wire(port_name); - if (ref == nullptr) - log_file_error(filename, location.first_line, - "Cell instance refers to port %s which does not exist in module %s!.\n", - log_id(port_name), log_id(module->name)); - - // select the argument, if present - log_assert(child->children.size() <= 1); - if (child->children.empty()) - continue; - AstNode *arg = child->children[0]; - - // plain identifiers never need indirection; this also prevents - // adding infinite levels of indirection - if (arg->type == AST_IDENTIFIER && arg->children.empty()) - continue; - - // only add indirection for standard inputs or outputs - if (ref->port_input == ref->port_output) - continue; - - did_something = true; - - // create the indirection wire - std::stringstream sstr; - sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); - std::string tmp_str = sstr.str(); - add_wire_for_ref(ref, tmp_str); - - AstNode *asgn = new AstNode(AST_ASSIGN); - current_ast_mod->children.push_back(asgn); - - AstNode *ident = new AstNode(AST_IDENTIFIER); - ident->str = tmp_str; - child->children[0] = ident->clone(); - - if (ref->port_input && !ref->port_output) { - asgn->children.push_back(ident); - asgn->children.push_back(arg); - } else { - log_assert(!ref->port_input && ref->port_output); - asgn->children.push_back(arg); - asgn->children.push_back(ident); - } - } - - - } - } - - 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.\n", children[0]->str.c_str(), loc_string().c_str()); - 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.\n", children[0]->str.c_str(), loc_string().c_str()); - } - children[0]->was_checked = true; - } - break; - - case AST_STRUCT: - case AST_UNION: - if (!basic_prep) { - for (auto *node : children) { - // resolve any ranges - while (!node->basic_prep && node->simplify(true, false, false, stage, -1, false, false)) { - did_something = true; - } - } - // determine member offsets and widths - size_packed_struct(this, 0); - - // instance rather than just a type in a typedef or outer struct? - if (!str.empty() && str[0] == '\\') { - // instance so add a wire for the packed structure - auto wnode = make_packed_struct(this, str); - log_assert(current_ast_mod); - current_ast_mod->children.push_back(wnode); - } - basic_prep = true; - } - break; - - case AST_STRUCT_ITEM: - break; - - case AST_ENUM: - //log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep); - if (!basic_prep) { - for (auto item_node : children) { - while (!item_node->basic_prep && item_node->simplify(false, false, false, stage, -1, false, in_param)) - did_something = true; - } - // allocate values (called more than once) - allocateDefaultEnumValues(); - } - break; - - case AST_PARAMETER: - case AST_LOCALPARAM: - // if parameter is implicit type which is the typename of a struct or union, - // save information about struct in wiretype attribute - if (children[0]->type == AST_IDENTIFIER && current_scope.count(children[0]->str) > 0) { - auto item_node = current_scope[children[0]->str]; - if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) { - attributes[ID::wiretype] = item_node->clone(); - size_packed_struct(attributes[ID::wiretype], 0); - add_members_to_scope(attributes[ID::wiretype], str); - } - } - 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, location.first_line, "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_ENUM_ITEM: - while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, in_param)) - 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, in_param)) - did_something = true; - if (!children[1]->range_valid) - log_file_error(filename, location.first_line, "Non-constant width range on enum item 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_SELFSZ: - case AST_CAST_SIZE: - 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: - 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) { - if (width_hint < 0) { - while (!children[0]->basic_prep && children[0]->simplify(true, false, in_lvalue, stage, -1, false, in_param)) - did_something = true; - - bool backup_unevaluated_tern_branch = unevaluated_tern_branch; - AstNode *chosen = get_tern_choice().first; - - unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[2]; - while (!children[1]->basic_prep && children[1]->simplify(false, false, in_lvalue, stage, -1, false, in_param)) - did_something = true; - - unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[1]; - while (!children[2]->basic_prep && children[2]->simplify(false, false, in_lvalue, stage, -1, false, in_param)) - did_something = true; - - unevaluated_tern_branch = backup_unevaluated_tern_branch; - detectSignWidth(width_hint, sign_hint); - } - 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) - { - detectSignWidth(width_hint, sign_hint); - 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()) { - children[0]->is_signed = sign_hint; - RTLIL::Const case_expr = children[0]->bitsAsConst(width_hint, sign_hint); - 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()) { - RTLIL::Const case_item_expr = v->bitsAsConst(width_hint, sign_hint); - RTLIL::Const match = const_eq(case_expr, case_item_expr, sign_hint, sign_hint, 1); - log_assert(match.bits.size() == 1); - if (match.bits.front() == RTLIL::State::S1) { - 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); - } - } - - dict> backup_memwr_visible; - dict> final_memwr_visible; - - if (type == AST_CASE && stage == 2) { - backup_memwr_visible = current_memwr_visible; - final_memwr_visible = current_memwr_visible; - } - - // 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; - bool backup_unevaluated_tern_branch = unevaluated_tern_branch; - 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_CELLARRAY && children[i]->type == AST_CELL) - continue; - if (type == AST_BLOCK && !str.empty()) - break; - if (type == AST_PREFIX && i >= 1) - break; - if (type == AST_DEFPARAM && i == 0) - flag_autowire = true; - if (type == AST_TERNARY && i > 0 && !unevaluated_tern_branch) { - AstNode *chosen = get_tern_choice().first; - unevaluated_tern_branch = chosen && chosen != children[i]; - } - 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 (i == 0 && (type == AST_GENIF || type == AST_GENCASE)) - in_param_here = true; - if (i == 1 && (type == AST_FOR || type == AST_GENFOR)) - 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; - unevaluated_tern_branch = backup_unevaluated_tern_branch; - if (stage == 2 && type == AST_CASE) { - for (auto &x : current_memwr_visible) { - for (int y : x.second) - final_memwr_visible[x.first].insert(y); - } - current_memwr_visible = backup_memwr_visible; - } - } - for (auto &attr : attributes) { - while (attr.second->simplify(true, false, false, stage, -1, false, true)) - did_something = true; - } - if (type == AST_CASE && stage == 2) { - current_memwr_visible = final_memwr_visible; - } - if (type == AST_ALWAYS && stage == 2) { - current_memwr_visible.clear(); - current_memwr_count.clear(); - } - - 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; - - 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, location.first_line, "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, location.first_line, "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, location.first_line, "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 typedefs - if (type == AST_TYPEDEF) { - log_assert(children.size() == 1); - auto type_node = children[0]; - log_assert(type_node->type == AST_WIRE || type_node->type == AST_MEMORY || type_node->type == AST_STRUCT || type_node->type == AST_UNION); - while (type_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { - did_something = true; - } - log_assert(!type_node->is_custom_type); - } - - // resolve types of wires - if (type == AST_WIRE || type == AST_MEMORY) { - if (is_custom_type) { - log_assert(children.size() >= 1); - log_assert(children[0]->type == AST_WIRETYPE); - auto type_name = children[0]->str; - if (!current_scope.count(type_name)) { - log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", type_name.c_str()); - } - AstNode *resolved_type_node = current_scope.at(type_name); - if (resolved_type_node->type != AST_TYPEDEF) - log_file_error(filename, location.first_line, "`%s' does not name a type\n", type_name.c_str()); - log_assert(resolved_type_node->children.size() == 1); - AstNode *template_node = resolved_type_node->children[0]; - - // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; - - if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { - // replace with wire representing the packed structure - newNode = make_packed_struct(template_node, str); - newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); - // add original input/output attribute to resolved wire - newNode->is_input = this->is_input; - newNode->is_output = this->is_output; - current_scope[str] = this; - goto apply_newNode; - } - - // Remove type reference - delete children[0]; - children.erase(children.begin()); - - if (type == AST_WIRE) - type = template_node->type; - is_reg = template_node->is_reg; - is_logic = template_node->is_logic; - is_signed = template_node->is_signed; - is_string = template_node->is_string; - is_custom_type = template_node->is_custom_type; - - range_valid = template_node->range_valid; - range_swapped = template_node->range_swapped; - range_left = template_node->range_left; - range_right = template_node->range_right; - - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); - - // if an enum then add attributes to support simulator tracing - annotateTypedEnums(template_node); - - // Insert clones children from template at beginning - for (int i = 0; i < GetSize(template_node->children); i++) - children.insert(children.begin() + i, template_node->children[i]->clone()); - - if (type == AST_MEMORY && GetSize(children) == 1) { - // Single-bit memories must have [0:0] range - AstNode *rng = make_range(0, 0); - children.insert(children.begin(), rng); - } - did_something = true; - } - log_assert(!is_custom_type); - } - - // resolve types of parameters - if (type == AST_LOCALPARAM || type == AST_PARAMETER) { - if (is_custom_type) { - log_assert(children.size() == 2); - log_assert(children[1]->type == AST_WIRETYPE); - auto type_name = children[1]->str; - if (!current_scope.count(type_name)) { - log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", type_name.c_str()); - } - AstNode *resolved_type_node = current_scope.at(type_name); - if (resolved_type_node->type != AST_TYPEDEF) - log_file_error(filename, location.first_line, "`%s' does not name a type\n", type_name.c_str()); - log_assert(resolved_type_node->children.size() == 1); - AstNode *template_node = resolved_type_node->children[0]; - - // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; - - if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { - // replace with wire representing the packed structure - newNode = make_packed_struct(template_node, str); - newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); - newNode->type = type; - current_scope[str] = this; - // copy param value, it needs to be 1st value - delete children[1]; - children.pop_back(); - newNode->children.insert(newNode->children.begin(), children[0]->clone()); - goto apply_newNode; - } - delete children[1]; - children.pop_back(); - - if (template_node->type == AST_MEMORY) - log_file_error(filename, location.first_line, "unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str()); - is_signed = template_node->is_signed; - is_string = template_node->is_string; - is_custom_type = template_node->is_custom_type; - - range_valid = template_node->range_valid; - range_swapped = template_node->range_swapped; - range_left = template_node->range_left; - range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); - for (auto template_child : template_node->children) - children.push_back(template_child->clone()); - did_something = true; - } - log_assert(!is_custom_type); - } - - // resolve constant prefixes - if (type == AST_PREFIX) { - if (children[0]->type != AST_CONSTANT) { - // dumpAst(NULL, "> "); - log_file_error(filename, location.first_line, "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, location.first_line, "Left operand of to_bits expression is not constant!\n"); - if (children[1]->type != AST_CONSTANT) - log_file_error(filename, location.first_line, "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_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; - bool force_upto = false, force_downto = false; - if (attributes.count(ID::force_upto)) { - AstNode *val = attributes[ID::force_upto]; - if (val->type != AST_CONSTANT) - log_file_error(filename, location.first_line, "Attribute `force_upto' with non-constant value!\n"); - force_upto = val->asAttrConst().as_bool(); - } - if (attributes.count(ID::force_downto)) { - AstNode *val = attributes[ID::force_downto]; - if (val->type != AST_CONSTANT) - log_file_error(filename, location.first_line, "Attribute `force_downto' with non-constant value!\n"); - force_downto = val->asAttrConst().as_bool(); - } - if (force_upto && force_downto) - log_file_error(filename, location.first_line, "Attributes `force_downto' and `force_upto' cannot be both set!\n"); - if ((force_upto && !range_swapped) || (force_downto && range_swapped)) { - std::swap(range_left, range_right); - range_swapped = force_upto; - } - } - } 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(); - multirange_swapped.clear(); - for (auto range : children[1]->children) { - if (!range->range_valid) - log_file_error(filename, location.first_line, "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); - multirange_swapped.push_back(range->range_swapped); - 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; - - integer = children[0]->children.size(); // save original number of dimensions for $size() etc. - for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++) - { - if (GetSize(children[0]->children) <= i) - log_file_error(filename, location.first_line, "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 || type == AST_ENUM_ITEM) { - if (children.size() > 1 && children[1]->type == AST_RANGE) { - if (!children[1]->range_valid) - log_file_error(filename, location.first_line, "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, location.first_line, "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; - } - } - - if (type == AST_IDENTIFIER && !basic_prep) { - // check if a plausible struct member sss.mmmm - std::string sname; - if (name_has_dot(str, sname)) { - if (current_scope.count(str) > 0) { - auto item_node = current_scope[str]; - if (item_node->type == AST_STRUCT_ITEM || item_node->type == AST_STRUCT || item_node->type == AST_UNION) { - // structure member, rewrite this node to reference the packed struct wire - auto range = make_struct_member_range(this, item_node); - newNode = new AstNode(AST_IDENTIFIER, range); - newNode->str = sname; - newNode->basic_prep = true; - if (item_node->is_signed) - newNode = new AstNode(AST_TO_SIGNED, newNode); - goto apply_newNode; - } - } - } - } - // annotate identifiers using scope resolution and create auto-wires as needed - if (type == AST_IDENTIFIER) { - if (current_scope.count(str) == 0) { - AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; - str = try_pop_module_prefix(); - for (auto node : current_scope_ast->children) { - //log("looking at mod scope child %s\n", type2str(node->type).c_str()); - switch (node->type) { - case AST_PARAMETER: - case AST_LOCALPARAM: - case AST_WIRE: - case AST_AUTOWIRE: - case AST_GENVAR: - case AST_MEMORY: - case AST_FUNCTION: - case AST_TASK: - case AST_DPI_FUNCTION: - //log("found child %s, %s\n", type2str(node->type).c_str(), node->str.c_str()); - if (str == node->str) { - //log("add %s, type %s to scope\n", str.c_str(), type2str(node->type).c_str()); - current_scope[node->str] = node; - } - break; - case AST_ENUM: - current_scope[node->str] = node; - for (auto enum_node : node->children) { - log_assert(enum_node->type==AST_ENUM_ITEM); - if (str == enum_node->str) { - //log("\nadding enum item %s to scope\n", str.c_str()); - current_scope[str] = enum_node; - } - } - break; - default: - break; - } - } - } - if (current_scope.count(str) == 0) { - if (current_ast_mod == nullptr) { - log_file_error(filename, location.first_line, "Identifier `%s' is implicitly declared outside of a module.\n", str.c_str()); - } else 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, location.first_line, "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 && stage == 2) - { - if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) - log_file_error(filename, location.first_line, "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 << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (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[ID::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->integer = integer; // save original number of dimensions for $size() etc. - newNode->id2ast = wire; - goto apply_newNode; - } - - if (type == AST_WHILE) - log_file_error(filename, location.first_line, "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, location.first_line, "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); - - const char* loop_type_str = "procedural"; - const char* var_type_str = "register"; - AstNodeType var_type = AST_WIRE; - if (type == AST_GENFOR) { - loop_type_str = "generate"; - var_type_str = "genvar"; - var_type = AST_GENVAR; - } - - if (init_ast->type != AST_ASSIGN_EQ) - log_file_error(filename, location.first_line, "Unsupported 1st expression of %s for-loop!\n", loop_type_str); - if (next_ast->type != AST_ASSIGN_EQ) - log_file_error(filename, location.first_line, "Unsupported 3rd expression of %s for-loop!\n", loop_type_str); - - if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != var_type) - log_file_error(filename, location.first_line, "Left hand side of 1st expression of %s for-loop is not a %s!\n", loop_type_str, var_type_str); - if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != var_type) - log_file_error(filename, location.first_line, "Left hand side of 3rd expression of %s for-loop is not a %s!\n", loop_type_str, var_type_str); - - if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast) - log_file_error(filename, location.first_line, "Incompatible left-hand sides in 1st and 3rd expression of %s for-loop!\n", loop_type_str); - - // 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, location.first_line, "Right hand side of 1st expression of %s for-loop is not constant!\n", loop_type_str); - - auto resolved = current_scope.at(init_ast->children[0]->str); - if (resolved->range_valid) { - int const_size = varbuf->range_left - varbuf->range_right; - int resolved_size = resolved->range_left - resolved->range_right; - if (const_size < resolved_size) { - for (int i = const_size; i < resolved_size; i++) - varbuf->bits.push_back(resolved->is_signed ? varbuf->bits.back() : State::S0); - varbuf->range_left = resolved->range_left; - varbuf->range_right = resolved->range_right; - varbuf->range_swapped = resolved->range_swapped; - varbuf->range_valid = resolved->range_valid; - } - } - - 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, location.first_line, "2nd expression of %s for-loop is not constant!\n", loop_type_str); - - if (buf->integer == 0) { - delete buf; - break; - } - delete buf; - - // expand body - int index = varbuf->children[0]->integer; - log_assert(body_ast->type == AST_GENBLOCK || body_ast->type == AST_BLOCK); - log_assert(!body_ast->str.empty()); - buf = body_ast->clone(); - - std::stringstream sstr; - sstr << buf->str << "[" << index << "]."; - std::string prefix = sstr.str(); - - // create a scoped localparam for the current value of the loop variable - AstNode *local_index = varbuf->clone(); - size_t pos = local_index->str.rfind('.'); - if (pos != std::string::npos) // remove outer prefix - local_index->str = "\\" + local_index->str.substr(pos + 1); - local_index->str = prefix_id(prefix, local_index->str); - current_scope[local_index->str] = local_index; - current_ast_mod->children.push_back(local_index); - - buf->expand_genblock(prefix); - - if (type == AST_GENFOR) { - for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, 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, location.first_line, "Right hand side of 3rd expression of %s for-loop is not constant (%s)!\n", loop_type_str, type2str(buf->type).c_str()); - - 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 || children[i]->type == AST_TYPEDEF) - { - log_assert(!VERILOG_FRONTEND::sv_mode); - log_file_error(children[i]->filename, children[i]->location.first_line, "Local declaration in unnamed block is only supported in SystemVerilog mode!\n"); - } - } - - // transform block with name - if (type == AST_BLOCK && !str.empty()) - { - expand_genblock(str + "."); - - // if this is an autonamed block is in an always_comb - if (current_always && current_always->attributes.count(ID::always_comb) - && is_autonamed_block(str)) - // track local variables in this block so we can consider adding - // nosync once the block has been fully elaborated - for (AstNode *child : children) - if (child->type == AST_WIRE && - !child->attributes.count(ID::nosync)) - mark_auto_nosync(this, child); - - 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]->type == AST_TYPEDEF) { - 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()) { - expand_genblock(str + "."); - } - - for (size_t i = 0; i < children.size(); i++) { - children[i]->simplify(const_fold, 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, location.first_line, "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()) { - buf->expand_genblock(buf->str + "."); - } - - for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, 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, location.first_line, "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, true)) { } - if (buf->type != AST_CONSTANT) { - // for (auto f : log_files) - // dumpAst(f, "verilog-ast> "); - log_file_error(filename, location.first_line, "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()) { - buf->expand_genblock(buf->str + "."); - } - - for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, 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, location.first_line, "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, location.first_line, "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, location.first_line, "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, location.first_line, "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 if (str == "buf" || str == "not") - { - AstNode *input = children_list.back(); - if (str == "not") - input = new AstNode(AST_BIT_NOT, input); - - newNode = new AstNode(AST_GENBLOCK); - for (auto it = children_list.begin(); it != std::prev(children_list.end()); it++) { - newNode->children.push_back(new AstNode(AST_ASSIGN, *it, input->clone())); - newNode->children.back()->was_checked = true; - } - delete input; - - 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; - 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]); - node->location = location; - } - 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 - // either a big case block that selects the correct single-bit assignment, or mask and - // shift operations. - 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, location.first_line, "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; - delete left_at_zero_ast; - delete right_at_zero_ast; - } - - bool use_case_method = false; - - if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { - AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); - while (node->simplify(true, false, false, stage, -1, false, false)) { } - if (node->type != AST_CONSTANT) - log_file_error(filename, location.first_line, "Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); - if (node->asAttrConst().as_bool()) - use_case_method = true; - } - - if (!use_case_method && current_always->detect_latch(children[0]->str)) - use_case_method = true; - - if (use_case_method) - { - // big case block - - did_something = true; - newNode = new AstNode(AST_CASE, shift_expr); - for (int i = 0; i < source_width; i++) { - int start_bit = children[0]->id2ast->range_right + i; - int end_bit = std::min(start_bit+result_width,source_width) - 1; - 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(end_bit, 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); - } - } - else - { - // mask and shift operations, disabled for now - - AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); - wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false); - wire_mask->is_logic = true; - while (wire_mask->simplify(true, false, false, 1, -1, false, false)) { } - current_ast_mod->children.push_back(wire_mask); - - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); - wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); - wire_data->is_logic = true; - while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } - current_ast_mod->children.push_back(wire_data); - - int shamt_width_hint = -1; - bool shamt_sign_hint = true; - shift_expr->detectSignWidth(shamt_width_hint, shamt_sign_hint); - - AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true))); - wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false); - wire_sel->is_logic = true; - wire_sel->is_signed = shamt_sign_hint; - while (wire_sel->simplify(true, false, false, 1, -1, false, false)) { } - current_ast_mod->children.push_back(wire_sel); - - did_something = true; - newNode = new AstNode(AST_BLOCK); - - AstNode *lvalue = children[0]->clone(); - lvalue->delete_children(); - - AstNode *ref_mask = new AstNode(AST_IDENTIFIER); - ref_mask->str = wire_mask->str; - ref_mask->id2ast = wire_mask; - ref_mask->was_checked = true; - - AstNode *ref_data = new AstNode(AST_IDENTIFIER); - ref_data->str = wire_data->str; - ref_data->id2ast = wire_data; - ref_data->was_checked = true; - - AstNode *ref_sel = new AstNode(AST_IDENTIFIER); - ref_sel->str = wire_sel->str; - ref_sel->id2ast = wire_sel; - ref_sel->was_checked = true; - - AstNode *old_data = lvalue->clone(); - if (type == AST_ASSIGN_LE) - old_data->lookahead = true; - - AstNode *s = new AstNode(AST_ASSIGN_EQ, ref_sel->clone(), shift_expr); - newNode->children.push_back(s); - - AstNode *shamt = ref_sel; - - // convert to signed while preserving the sign and value - shamt = new AstNode(AST_CAST_SIZE, mkconst_int(shamt_width_hint + 1, true), shamt); - shamt = new AstNode(AST_TO_SIGNED, shamt); - - // offset the shift amount by the lower bound of the dimension - int start_bit = children[0]->id2ast->range_right; - shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true)); - - // reflect the shift amount if the dimension is swapped - if (children[0]->id2ast->range_swapped) - shamt = new AstNode(AST_SUB, mkconst_int(source_width - result_width, true), shamt); - - // AST_SHIFT uses negative amounts for shifting left - shamt = new AstNode(AST_NEG, shamt); - - AstNode *t; - - t = mkconst_bits(std::vector(result_width, State::S1), false); - t = new AstNode(AST_SHIFT, t, shamt->clone()); - t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t); - newNode->children.push_back(t); - - t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector(result_width, State::S1), false), children[1]->clone()); - t = new AstNode(AST_SHIFT, t, shamt); - t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t); - newNode->children.push_back(t); - - t = new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)); - t = new AstNode(AST_BIT_OR, t, ref_data); - t = new AstNode(type, lvalue, t); - newNode->children.push_back(t); - } - - 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$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (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)) { } - - AstNode *check_defval; - if (type == AST_LIVE || type == AST_FAIR) { - check_defval = new AstNode(AST_REDUCE_BOOL, children[0]->clone()); - } else { - std::vector x_bit; - x_bit.push_back(RTLIL::State::Sx); - check_defval = mkconst_bits(x_bit, false); - } - - AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), check_defval); - 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); - - if (type == AST_LIVE || type == AST_FAIR) { - assign_check = nullptr; - } else { - 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); - if (assign_check != nullptr) - newNode->children.push_back(assign_check); - newNode->children.push_back(assign_en); - - AstNode *assertnode = new AstNode(type); - assertnode->location = location; - 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", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - current_ast_mod->children.push_back(wire_tmp); - current_scope[wire_tmp->str] = wire_tmp; - wire_tmp->attributes[ID::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 << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (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); - - newNode = new AstNode(AST_BLOCK); - AstNode *defNode = new AstNode(AST_BLOCK); - - 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); - - 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 *node_addr = nullptr; - if (children[0]->children[0]->children[0]->isConst()) { - node_addr = children[0]->children[0]->children[0]->clone(); - } else { - 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 *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); - assign_addr->children[0]->str = id_addr; - assign_addr->children[0]->was_checked = true; - defNode->children.push_back(assign_addr); - - 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; - newNode->children.push_back(assign_addr); - - node_addr = new AstNode(AST_IDENTIFIER); - node_addr->str = id_addr; - } - - AstNode *node_data = nullptr; - if (children[0]->children.size() == 1 && children[1]->isConst()) { - node_data = children[1]->clone(); - } else { - 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 *assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); - assign_data->children[0]->str = id_data; - assign_data->children[0]->was_checked = true; - defNode->children.push_back(assign_data); - - node_data = new AstNode(AST_IDENTIFIER); - node_data->str = id_data; - } - - AstNode *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)) { } - - AstNode *assign_en_first = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); - assign_en_first->children[0]->str = id_en; - assign_en_first->children[0]->was_checked = true; - defNode->children.push_back(assign_en_first); - - AstNode *node_en = new AstNode(AST_IDENTIFIER); - node_en->str = id_en; - - if (!defNode->children.empty()) - current_top_block->children.insert(current_top_block->children.begin(), defNode); - else - delete defNode; - - AstNode *assign_data = nullptr; - AstNode *assign_en = nullptr; - 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_EQ, 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; - - 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_EQ, 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, location.first_line, "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_EQ, 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; - - 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_EQ, 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 - { - if (!(children[0]->children.size() == 1 && children[1]->isConst())) { - assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[1]->clone()); - assign_data->children[0]->str = id_data; - assign_data->children[0]->was_checked = true; - } - - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - } - if (assign_data) - newNode->children.push_back(assign_data); - if (assign_en) - newNode->children.push_back(assign_en); - - AstNode *wrnode; - if (current_always->type == AST_INITIAL) - wrnode = new AstNode(AST_MEMINIT, node_addr, node_data, node_en, mkconst_int(1, false)); - else - wrnode = new AstNode(AST_MEMWR, node_addr, node_data, node_en); - wrnode->str = children[0]->str; - wrnode->id2ast = children[0]->id2ast; - wrnode->location = location; - if (wrnode->type == AST_MEMWR) { - int portid = current_memwr_count[wrnode->str]++; - wrnode->children.push_back(mkconst_int(portid, false)); - std::vector priority_mask; - for (int i = 0; i < portid; i++) { - bool has_prio = current_memwr_visible[wrnode->str].count(i); - priority_mask.push_back(State(has_prio)); - } - wrnode->children.push_back(mkconst_bits(priority_mask, false)); - current_memwr_visible[wrnode->str].insert(portid); - current_always->children.push_back(wrnode); - } else { - current_ast_mod->children.push_back(wrnode); - } - - if (newNode->children.empty()) { - delete newNode; - newNode = new AstNode(); - } - 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, location.first_line, "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, location.first_line, "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, location.first_line, "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", RTLIL::encode_filename(filename).c_str(), location.first_line, myidx, i); - reg->is_reg = true; - reg->is_signed = sign_hint; - - 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, location.first_line, "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, location.first_line, "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, location.first_line, "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, location.first_line, "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" || str == "\\$high" || str == "\\$low" || str == "\\$left" || str == "\\$right") - { - int dim = 1; - if (str == "\\$bits") { - if (children.size() != 1) - log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - } else { - if (children.size() != 1 && children.size() != 2) - log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1 or 2.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - if (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; - int result, high = 0, low = 0, left = 0, right = 0, width = 1; // defaults for a simple wire - 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, location.first_line, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str()); - // a slice of our identifier means we advance to the next dimension, e.g. $size(a[3]) - if (buf->children.size() > 0) { - // something is hanging below this identifier - if (buf->children[0]->type == AST_RANGE && buf->integer == 0) - // if integer == 0, this node was originally created as AST_RANGE so it's dimension is 1 - dim++; - // more than one range, e.g. $size(a[3][2]) - else // created an AST_MULTIRANGE, converted to AST_RANGE, but original dimension saved in 'integer' field - dim += buf->integer; // increment by multirange size - } - // We have 4 cases: - // wire x; ==> AST_WIRE, no AST_RANGE children - // wire [1:0]x; ==> AST_WIRE, AST_RANGE children - // wire [1:0]x[1:0]; ==> AST_MEMORY, two AST_RANGE children (1st for packed, 2nd for unpacked) - // wire [1:0]x[1:0][1:0]; ==> AST_MEMORY, one AST_RANGE child (0) for packed, then AST_MULTIRANGE child (1) for unpacked - // (updated: actually by the time we are here, AST_MULTIRANGE is converted into one big AST_RANGE) - // case 0 handled by default - if ((id_ast->type == AST_WIRE || id_ast->type == AST_MEMORY) && id_ast->children.size() > 0) { - // handle packed array left/right for case 1, and cases 2/3 when requesting the last dimension (packed side) - AstNode *wire_range = id_ast->children[0]; - left = wire_range->children[0]->integer; - right = wire_range->children[1]->integer; - high = max(left, right); - low = min(left, right); - } - 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, location.first_line, "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, location.first_line, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); - } else { - // $size(), $left(), $right(), $high(), $low() - int dims = 1; - if (mem_range->type == AST_RANGE) { - if (id_ast->multirange_dimensions.empty()) { - if (!mem_range->range_valid) - log_file_error(filename, location.first_line, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); - if (dim == 1) { - left = mem_range->range_right; - right = mem_range->range_left; - high = max(left, right); - low = min(left, right); - } - } else { - dims = GetSize(id_ast->multirange_dimensions)/2; - if (dim <= dims) { - width_hint = id_ast->multirange_dimensions[2*dim-1]; - high = id_ast->multirange_dimensions[2*dim-2] + id_ast->multirange_dimensions[2*dim-1] - 1; - low = id_ast->multirange_dimensions[2*dim-2]; - if (id_ast->multirange_swapped[dim-1]) { - left = low; - right = high; - } else { - right = low; - left = high; - } - } else if ((dim > dims+1) || (dim < 0)) - log_file_error(filename, location.first_line, "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, location.first_line, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); - } - } - } - width = high - low + 1; - } else { - width = width_hint; - } - delete buf; - if (str == "\\$high") - result = high; - else if (str == "\\$low") - result = low; - else if (str == "\\$left") - result = left; - else if (str == "\\$right") - result = right; - else if (str == "\\$size") - result = width; - else { - result = width * mem_depth; - } - newNode = mkconst_int(result, true); - 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, location.first_line, "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, location.first_line, "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, location.first_line, "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, location.first_line, "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 (str == "\\$sformatf") { - 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, location.first_line, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); - std::string sformat = node_string->bitsAsConst().decode_string(); - std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint); - newNode = AstNode::mkconst_str(sout); - goto apply_newNode; - } - - if (str == "\\$countbits") { - if (children.size() < 2) - log_file_error(filename, location.first_line, "System function %s got %d arguments, expected at least 2.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - - std::vector control_bits; - - // Determine which bits to count - for (size_t i = 1; i < children.size(); i++) { - AstNode *node = children[i]; - while (node->simplify(true, false, false, stage, -1, false, false)) { } - if (node->type != AST_CONSTANT) - log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant control bit argument.\n", str.c_str()); - if (node->bits.size() != 1) - log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with control bit width != 1.\n", str.c_str()); - control_bits.push_back(node->bits[0]); - } - - // Detect width of exp (first argument of $countbits) - int exp_width = -1; - bool exp_sign = false; - AstNode *exp = children[0]; - exp->detectSignWidth(exp_width, exp_sign, NULL); - - newNode = mkconst_int(0, false); - - for (int i = 0; i < exp_width; i++) { - // Generate nodes for: exp << i >> ($size(exp) - 1) - // ^^ ^^ - AstNode *lsh_node = new AstNode(AST_SHIFT_LEFT, exp->clone(), mkconst_int(i, false)); - AstNode *rsh_node = new AstNode(AST_SHIFT_RIGHT, lsh_node, mkconst_int(exp_width - 1, false)); - - AstNode *or_node = nullptr; - - for (RTLIL::State control_bit : control_bits) { - // Generate node for: (exp << i >> ($size(exp) - 1)) === control_bit - // ^^^ - AstNode *eq_node = new AstNode(AST_EQX, rsh_node->clone(), mkconst_bits({control_bit}, false)); - - // Or the result for each checked bit value - if (or_node) - or_node = new AstNode(AST_LOGIC_OR, or_node, eq_node); - else - or_node = eq_node; - } - - // We should have at least one element in control_bits, - // because we checked for the number of arguments above - log_assert(or_node != nullptr); - - delete rsh_node; - - // Generate node for adding with result of previous bit - newNode = new AstNode(AST_ADD, newNode, or_node); - } - - goto apply_newNode; - } - - if (str == "\\$countones" || str == "\\$isunknown" || str == "\\$onehot" || str == "\\$onehot0") { - if (children.size() != 1) - log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1.\n", - RTLIL::unescape_id(str).c_str(), int(children.size())); - - AstNode *countbits = clone(); - countbits->str = "\\$countbits"; - - if (str == "\\$countones") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = countbits; - } else if (str == "\\$isunknown") { - countbits->children.push_back(mkconst_bits({RTLIL::Sx}, false)); - countbits->children.push_back(mkconst_bits({RTLIL::Sz}, false)); - newNode = new AstNode(AST_GT, countbits, mkconst_int(0, false)); - } else if (str == "\\$onehot") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = new AstNode(AST_EQ, countbits, mkconst_int(1, false)); - } else if (str == "\\$onehot0") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = new AstNode(AST_LE, countbits, mkconst_int(1, false)); - } 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, location.first_line, "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, location.first_line, "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) - str = try_pop_module_prefix(); - if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION) - log_file_error(filename, location.first_line, "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, location.first_line, "System task `%s' outside initial block is unsupported.\n", str.c_str()); - - log_file_error(filename, location.first_line, "System task `%s' executed.\n", str.c_str()); - } - - if (str == "\\$readmemh" || str == "\\$readmemb") - { - if (GetSize(children) < 2 || GetSize(children) > 4) - log_file_error(filename, location.first_line, "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, location.first_line, "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, location.first_line, "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, location.first_line, "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, location.first_line, "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) - str = try_pop_module_prefix(); - if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK) - log_file_error(filename, location.first_line, "Can't resolve task name `%s'.\n", str.c_str()); - } - - - std::stringstream sstr; - sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; - std::string prefix = sstr.str(); - - AstNode *decl = current_scope[str]; - if (unevaluated_tern_branch && decl->is_recursive_function()) - goto replace_fcall_later; - decl = decl->clone(); - decl->replace_result_wire_name_in_function(str, "$result"); // enables recursion - decl->expand_genblock(prefix); - - if (decl->type == AST_FUNCTION && !decl->attributes.count(ID::via_celltype)) - { - bool require_const_eval = decl->has_const_only_constructs(); - bool all_args_const = true; - for (auto child : children) { - while (child->simplify(true, false, false, 1, -1, false, true)) { } - if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) - all_args_const = false; - } - - if (all_args_const) { - AstNode *func_workspace = decl->clone(); - func_workspace->str = prefix_id(prefix, "$result"); - newNode = func_workspace->eval_const_function(this, in_param || require_const_eval); - delete func_workspace; - if (newNode) { - delete decl; - goto apply_newNode; - } - } - - if (in_param) - log_file_error(filename, location.first_line, "Non-constant function call in constant expression.\n"); - if (require_const_eval) - log_file_error(filename, location.first_line, "Function %s can only be called with constant arguments.\n", str.c_str()); - } - - size_t arg_count = 0; - dict wire_cache; - vector new_stmts; - vector output_assignments; - - if (current_block == NULL) - { - log_assert(type == AST_FCALL); - - AstNode *wire = NULL; - std::string res_name = prefix_id(prefix, "$result"); - for (auto child : decl->children) - if (child->type == AST_WIRE && child->str == res_name) - wire = child->clone(); - log_assert(wire != NULL); - - wire->port_id = 0; - wire->is_input = false; - wire->is_output = false; - - current_scope[wire->str] = wire; - 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(ID::via_celltype)) - { - std::string celltype = decl->attributes.at(ID::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.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->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 || child->type == AST_ENUM_ITEM) - { - AstNode *wire = nullptr; - - if (wire_cache.count(child->str)) - { - wire = wire_cache.at(child->str); - bool contains_value = wire->type == AST_LOCALPARAM; - if (wire->children.size() == contains_value) { - 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) - contains_value) { - for (int i = 0; i < GetSize(child->children); i++) - if (*child->children.at(i) != *wire->children.at(i + contains_value)) - goto tcall_incompatible_wires; - } else { - tcall_incompatible_wires: - log_file_error(filename, location.first_line, "Incompatible re-declaration of wire %s.\n", child->str.c_str()); - } - } - } - else - { - wire = child->clone(); - wire->port_id = 0; - wire->is_input = false; - wire->is_output = false; - wire->is_reg = true; - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); - if (child->type == AST_ENUM_ITEM) - wire->attributes[ID::enum_base_type] = child->attributes[ID::enum_base_type]; - - wire_cache[child->str] = wire; - - current_scope[wire->str] = wire; - current_ast_mod->children.push_back(wire); - } - - while (wire->simplify(true, false, false, 1, -1, false, false)) { } - - if ((child->is_input || child->is_output) && arg_count < children.size()) - { - AstNode *arg = children[arg_count++]->clone(); - // convert purely constant arguments into localparams - if (child->is_input && child->type == AST_WIRE && arg->type == AST_CONSTANT && node_contains_assignment_to(decl, child)) { - wire->type = AST_LOCALPARAM; - if (wire->attributes.count(ID::nosync)) - delete wire->attributes.at(ID::nosync); - wire->attributes.erase(ID::nosync); - wire->children.insert(wire->children.begin(), arg->clone()); - // args without a range implicitly have width 1 - if (wire->children.back()->type != AST_RANGE) { - // check if this wire is redeclared with an explicit size - bool uses_explicit_size = false; - for (const AstNode *other_child : decl->children) - if (other_child->type == AST_WIRE && child->str == other_child->str - && !other_child->children.empty() - && other_child->children.back()->type == AST_RANGE) { - uses_explicit_size = true; - break; - } - if (!uses_explicit_size) { - AstNode* range = new AstNode(); - range->type = AST_RANGE; - wire->children.push_back(range); - range->children.push_back(mkconst_int(0, true)); - range->children.push_back(mkconst_int(0, true)); - } - } - // updates the sizing - while (wire->simplify(true, false, false, 1, -1, false, false)) { } - delete arg; - continue; - } - 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 : decl->children) - if (child->type != AST_WIRE && child->type != AST_MEMORY && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM) - new_stmts.push_back(child->clone()); - - 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: - delete decl; - if (type == AST_FCALL) { - delete_children(); - type = AST_IDENTIFIER; - str = prefix_id(prefix, "$result"); - } - 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 || current_scope[str]->type == AST_ENUM_ITEM)) { - 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) { - AstNode *node = current_scope[str]; - if (node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY) - newNode = mkconst_int(0, sign_hint, width_hint); - } - break; - case AST_MEMRD: - if (at_zero) { - 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_SELFSZ: const_func = RTLIL::const_pos; } - 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_NEG) - newNode->realvalue = -children[0]->asReal(sign_hint); - else - newNode->realvalue = +children[0]->asReal(sign_hint); - } - break; - case AST_TERNARY: - if (children[0]->isConst()) - { - auto pair = get_tern_choice(); - AstNode *choice = pair.first; - AstNode *not_choice = pair.second; - - 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_CAST_SIZE: - if (children.at(0)->type == AST_CONSTANT && children.at(1)->type == AST_CONSTANT) { - int width = children[0]->bitsAsConst().as_int(); - RTLIL::Const val; - if (children[1]->is_unsized) - val = children[1]->bitsAsUnsizedConst(width); - else - val = children[1]->bitsAsConst(width); - newNode = mkconst_bits(val.bits, children[1]->is_signed); - } - 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->location = location; - newNode->cloneInto(this); - delete newNode; - did_something = true; - } - - if (!did_something) - basic_prep = true; - - recursion_counter--; - return did_something; -} - -void AstNode::replace_result_wire_name_in_function(const std::string &from, const std::string &to) -{ - for (AstNode *child : children) - child->replace_result_wire_name_in_function(from, to); - if (str == from && type != AST_FCALL && type != AST_TCALL) - 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; - vector en_bits; - int meminit_size=0; - - for (int i = 0; i < mem_width; i++) - en_bits.push_back(State::S1); - - std::ifstream f; - f.open(mem_filename.c_str()); - if (f.fail()) { -#ifdef _WIN32 - char slash = '\\'; -#else - char slash = '/'; -#endif - std::string path = filename.substr(0, filename.find_last_of(slash)+1); - f.open(path + mem_filename.c_str()); - yosys_input_files.insert(path + mem_filename); - } else { - yosys_input_files.insert(mem_filename); - } - if (f.fail() || GetSize(mem_filename) == 0) - log_file_error(filename, location.first_line, "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.compare(i, 2, "*/") == 0) { - line[i] = ' '; - line[i+1] = ' '; - in_comment = false; - continue; - } - if (!in_comment && line.compare(i, 2, "/*") == 0) - in_comment = true; - if (in_comment) - line[i] = ' '; - } - - while (1) - { - token = next_token(line, " \t\r\n"); - if (token.empty() || token.compare(0, 2, "//") == 0) - 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, location.first_line, "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[3] = 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(AstNode::mkconst_bits(en_bits, false)); - 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[3] = AstNode::mkconst_int(meminit_size, false); - } - - return block; -} - -// annotate the names of all wires and other named objects in a named generate -// or procedural block; nested blocks are themselves annotated such that the -// prefix is carried forward, but resolution of their children is deferred -void AstNode::expand_genblock(const std::string &prefix) -{ - if (type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE || type == AST_PREFIX) { - log_assert(!str.empty()); - - // search starting in the innermost scope and then stepping outward - for (size_t ppos = prefix.size() - 1; ppos; --ppos) { - if (prefix.at(ppos) != '.') continue; - - std::string new_prefix = prefix.substr(0, ppos + 1); - auto attempt_resolve = [&new_prefix](const std::string &ident) -> std::string { - std::string new_name = prefix_id(new_prefix, ident); - if (current_scope.count(new_name)) - return new_name; - return {}; - }; - - // attempt to resolve the full identifier - std::string resolved = attempt_resolve(str); - if (!resolved.empty()) { - str = resolved; - break; - } - - // attempt to resolve hierarchical prefixes within the identifier, - // as the prefix could refer to a local scope which exists but - // hasn't yet been elaborated - for (size_t spos = str.size() - 1; spos; --spos) { - if (str.at(spos) != '.') continue; - resolved = attempt_resolve(str.substr(0, spos)); - if (!resolved.empty()) { - str = resolved + str.substr(spos); - ppos = 1; // break outer loop - break; - } - } - - } - } - - auto prefix_node = [&prefix](AstNode* child) { - if (child->str.empty()) return; - std::string new_name = prefix_id(prefix, child->str); - if (child->type == AST_FUNCTION) - child->replace_result_wire_name_in_function(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]; - - switch (child->type) { - case AST_WIRE: - case AST_MEMORY: - case AST_PARAMETER: - case AST_LOCALPARAM: - case AST_FUNCTION: - case AST_TASK: - case AST_CELL: - case AST_TYPEDEF: - case AST_ENUM_ITEM: - case AST_GENVAR: - prefix_node(child); - break; - - case AST_BLOCK: - case AST_GENBLOCK: - if (!child->str.empty()) - prefix_node(child); - break; - - case AST_ENUM: - current_scope[child->str] = child; - for (auto enode : child->children){ - log_assert(enode->type == AST_ENUM_ITEM); - prefix_node(enode); - } - break; - - default: - break; - } - } - - for (size_t i = 0; i < children.size(); i++) { - AstNode *child = children[i]; - // AST_PREFIX member names should not be prefixed; we recurse into them - // as normal to ensure indices and ranges are properly resolved, and - // then restore the previous string - if (type == AST_PREFIX && i == 1) { - std::string backup_scope_name = child->str; - child->expand_genblock(prefix); - child->str = backup_scope_name; - continue; - } - // functions/tasks may reference wires, constants, etc. in this scope - if (child->type == AST_FUNCTION || child->type == AST_TASK) - continue; - // named blocks pick up the current prefix and will expanded later - if ((child->type == AST_GENBLOCK || child->type == AST_BLOCK) && !child->str.empty()) - continue; - - child->expand_genblock(prefix); - } -} - -// add implicit AST_GENBLOCK names according to IEEE 1364-2005 Section 12.4.3 or -// IEEE 1800-2017 Section 27.6 -void AstNode::label_genblks(std::set& existing, int &counter) -{ - switch (type) { - case AST_GENIF: - case AST_GENFOR: - case AST_GENCASE: - // seeing a proper generate control flow construct increments the - // counter once - ++counter; - for (AstNode *child : children) - child->label_genblks(existing, counter); - break; - - case AST_GENBLOCK: { - // if this block is unlabeled, generate its corresponding unique name - for (int padding = 0; str.empty(); ++padding) { - std::string candidate = "\\genblk"; - for (int i = 0; i < padding; ++i) - candidate += '0'; - candidate += std::to_string(counter); - if (!existing.count(candidate)) - str = candidate; - } - // within a genblk, the counter starts fresh - std::set existing_local = existing; - int counter_local = 0; - for (AstNode *child : children) - child->label_genblks(existing_local, counter_local); - break; - } - - default: - // track names which could conflict with implicit genblk names - if (str.rfind("\\genblk", 0) == 0) - existing.insert(str); - for (AstNode *child : children) - child->label_genblks(existing, counter); - break; - } -} - -// 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", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line)); - 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_TYPEDEF) - return; // don't touch content of typedefs - - 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", RTLIL::encode_filename(filename).c_str(), location.first_line)); - 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", RTLIL::encode_filename(filename).c_str(), location.first_line)); - 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", RTLIL::encode_filename(filename).c_str(), location.first_line)); - 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", RTLIL::encode_filename(filename).c_str(), location.first_line)); - 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", RTLIL::encode_filename(filename).c_str(), location.first_line)); - 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' or 'logic' - if (type == AST_MEMORY && (get_bool_attribute(ID::mem2reg) || (flags & AstNode::MEM2REG_FL_ALL) || !(is_reg || is_logic))) - mem2reg_candidates[this] |= AstNode::MEM2REG_FL_FORCED; - - if (type == AST_MODULE && get_bool_attribute(ID::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; - } - else 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, location.first_line, "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_TYPEDEF) - 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); - log_assert(children[3]->type == AST_CONSTANT); - - int cursor = children[0]->asInt(false); - Const data = children[1]->bitsAsConst(); - Const en = children[2]->bitsAsConst(); - int length = children[3]->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++) { - int pos = 0; - while (pos < wordsz) { - if (en[pos] != State::S1) { - pos++; - } else { - int epos = pos + 1; - while (epos < wordsz && en[epos] == State::S1) - epos++; - int clen = epos - pos; - AstNode *range = new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false)); - if (pos != 0 || epos != wordsz) { - int left; - int right; - AstNode *mrange = id2ast->children[0]; - if (mrange->range_left < mrange->range_right) { - right = mrange->range_right - pos; - left = mrange->range_right - epos + 1; - } else { - right = mrange->range_right + pos; - left = mrange->range_right + epos - 1; - } - range = new AstNode(AST_MULTIRANGE, range, new AstNode(AST_RANGE, AstNode::mkconst_int(left, true), AstNode::mkconst_int(right, true))); - } - AstNode *target = new AstNode(AST_IDENTIFIER, range); - target->str = str; - target->id2ast = id2ast; - target->was_checked = true; - block->children.push_back(new AstNode(AST_ASSIGN_EQ, target, mkconst_bits(data.extract(i*wordsz + pos, clen).bits, false))); - pos = epos; - } - } - } - } - - 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 << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (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[ID::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[ID::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; - int left = id2ast->children[1]->children[0]->integer; - int right = id2ast->children[1]->children[1]->integer; - bool valid_const_access = - (left <= id && id <= right) || - (right <= id && id <= left); - if (valid_const_access) - { - str = stringf("%s[%d]", str.c_str(), id); - delete_children(); - range_valid = false; - id2ast = NULL; - } - else - { - int width; - if (bit_part_sel) - { - bit_part_sel->dumpAst(nullptr, "? "); - if (bit_part_sel->children.size() == 1) - width = 0; - else - width = bit_part_sel->children[0]->integer - - bit_part_sel->children[1]->integer; - delete bit_part_sel; - bit_part_sel = nullptr; - } - else - { - width = id2ast->children[0]->children[0]->integer - - id2ast->children[0]->children[1]->integer; - } - width = abs(width) + 1; - - delete_children(); - - std::vector x_bits; - for (int i = 0; i < width; i++) - x_bits.push_back(RTLIL::State::Sx); - AstNode *constant = AstNode::mkconst_bits(x_bits, false); - constant->cloneInto(this); - delete constant; - } - } - else - { - std::stringstream sstr; - sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (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[ID::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[ID::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::detect_latch(const std::string &var) -{ - switch (type) - { - case AST_ALWAYS: - for (auto &c : children) - { - switch (c->type) - { - case AST_POSEDGE: - case AST_NEGEDGE: - return false; - case AST_EDGE: - break; - case AST_BLOCK: - if (!c->detect_latch(var)) - return false; - break; - default: - log_abort(); - } - } - return true; - case AST_BLOCK: - for (auto &c : children) - if (!c->detect_latch(var)) - return false; - return true; - case AST_CASE: - { - bool r = true; - for (auto &c : children) { - if (c->type == AST_COND) { - if (c->children.at(1)->detect_latch(var)) - return true; - r = false; - } - if (c->type == AST_DEFAULT) { - if (c->children.at(0)->detect_latch(var)) - return true; - r = false; - } - } - return r; - } - case AST_ASSIGN_EQ: - case AST_ASSIGN_LE: - if (children.at(0)->type == AST_IDENTIFIER && - children.at(0)->children.empty() && children.at(0)->str == var) - return false; - return true; - default: - return true; - } -} - -bool AstNode::has_const_only_constructs() -{ - if (type == AST_WHILE || type == AST_REPEAT) - return true; - for (auto child : children) - if (child->has_const_only_constructs()) - 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() -bool AstNode::replace_variables(std::map &variables, AstNode *fcall, bool must_succeed) -{ - 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) { - if (!must_succeed) - return false; - log_file_error(filename, location.first_line, "Memory access in constant function is not supported\n%s: ...called from here.\n", - fcall->loc_string().c_str()); - } - if (!children.at(0)->replace_variables(variables, fcall, must_succeed)) - return false; - while (simplify(true, false, false, 1, -1, false, true)) { } - if (!children.at(0)->range_valid) { - if (!must_succeed) - return false; - log_file_error(filename, location.first_line, "Non-constant range\n%s: ... called from here.\n", - fcall->loc_string().c_str()); - } - 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; - if (variables.at(str).range_swapped) - offset = -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 true; - } - - for (auto &child : children) - if (!child->replace_variables(variables, fcall, must_succeed)) - return false; - return true; -} - -// attempt to statically evaluate a functions with all-const arguments -AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) -{ - std::map backup_scope = current_scope; - std::map variables; - std::vector to_delete; - AstNode *block = new AstNode(AST_BLOCK); - AstNode *result = nullptr; - - size_t argidx = 0; - for (auto child : children) - { - block->children.push_back(child->clone()); - } - - 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_WIRE) - { - while (stmt->simplify(true, false, false, 1, -1, false, true)) { } - if (!stmt->range_valid) { - if (!must_succeed) - goto finished; - log_file_error(stmt->filename, stmt->location.first_line, "Can't determine size of variable %s\n%s: ... called from here.\n", - stmt->str.c_str(), fcall->loc_string().c_str()); - } - AstNode::varinfo_t &variable = variables[stmt->str]; - int width = abs(stmt->range_left - stmt->range_right) + 1; - // if this variable has already been declared as an input, check the - // sizes match if it already had an explicit size - if (variable.arg && variable.explicitly_sized && variable.val.size() != width) { - log_file_error(filename, location.first_line, "Incompatible re-declaration of constant function wire %s.\n", stmt->str.c_str()); - } - variable.val = RTLIL::Const(RTLIL::State::Sx, width); - variable.offset = stmt->range_swapped ? stmt->range_left : stmt->range_right; - variable.range_swapped = stmt->range_swapped; - variable.is_signed = stmt->is_signed; - variable.explicitly_sized = stmt->children.size() && - stmt->children.back()->type == AST_RANGE; - // identify the argument corresponding to this wire, if applicable - if (stmt->is_input && argidx < fcall->children.size()) { - variable.arg = fcall->children.at(argidx++); - } - // load the constant arg's value into this variable - if (variable.arg) { - if (variable.arg->type == AST_CONSTANT) { - variable.val = variable.arg->bitsAsConst(width); - } else { - log_assert(variable.arg->type == AST_REALVALUE); - variable.val = variable.arg->realAsConst(width); - } - } - current_scope[stmt->str] = stmt; - - block->children.erase(block->children.begin()); - to_delete.push_back(stmt); - continue; - } - - log_assert(variables.count(str) != 0); - - if (stmt->type == AST_LOCALPARAM) - { - while (stmt->simplify(true, false, false, 1, -1, false, true)) { } - - current_scope[stmt->str] = stmt; - - block->children.erase(block->children.begin()); - to_delete.push_back(stmt); - continue; - } - - 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) - if (!stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall, must_succeed)) - goto finished; - if (!stmt->children.at(1)->replace_variables(variables, fcall, must_succeed)) - goto finished; - 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) { - if (!must_succeed) - goto finished; - log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s: ... called from here. X\n", - fcall->loc_string().c_str()); - } - - if (stmt->children.at(0)->type != AST_IDENTIFIER) { - if (!must_succeed) - goto finished; - log_file_error(stmt->filename, stmt->location.first_line, "Unsupported composite left hand side in constant function\n%s: ... called from here.\n", - fcall->loc_string().c_str()); - } - - if (!variables.count(stmt->children.at(0)->str)) { - if (!must_succeed) - goto finished; - log_file_error(stmt->filename, stmt->location.first_line, "Assignment to non-local variable in constant function\n%s: ... called from here.\n", - fcall->loc_string().c_str()); - } - - 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) { - if (!must_succeed) - goto finished; - log_file_error(range->filename, range->location.first_line, "Non-constant range\n%s: ... called from here.\n", - fcall->loc_string().c_str()); - } - 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++) { - int index = i + offset - v.offset; - if (v.range_swapped) - index = -index; - v.val.bits.at(index) = 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(); - if (!cond->replace_variables(variables, fcall, must_succeed)) - goto finished; - while (cond->simplify(true, false, false, 1, -1, false, true)) { } - - if (cond->type != AST_CONSTANT) { - if (!must_succeed) - goto finished; - log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s: ... called from here.\n", - fcall->loc_string().c_str()); - } - - 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(); - if (!num->replace_variables(variables, fcall, must_succeed)) - goto finished; - while (num->simplify(true, false, false, 1, -1, false, true)) { } - - if (num->type != AST_CONSTANT) { - if (!must_succeed) - goto finished; - log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s: ... called from here.\n", - fcall->loc_string().c_str()); - } - - 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(); - if (!expr->replace_variables(variables, fcall, must_succeed)) - goto finished; - 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(); - if (!cond->replace_variables(variables, fcall, must_succeed)) - goto finished; - - cond = new AstNode(AST_EQ, expr->clone(), cond); - while (cond->simplify(true, false, false, 1, -1, false, true)) { } - - if (cond->type != AST_CONSTANT) { - if (!must_succeed) - goto finished; - log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s: ... called from here.\n", - fcall->loc_string().c_str()); - } - - 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) - { - if (!stmt->str.empty()) - stmt->expand_genblock(stmt->str + "."); - - block->children.erase(block->children.begin()); - block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); - stmt->children.clear(); - delete stmt; - continue; - } - - if (!must_succeed) - goto finished; - log_file_error(stmt->filename, stmt->location.first_line, "Unsupported language construct in constant function\n%s: ... called from here.\n", - fcall->loc_string().c_str()); - log_abort(); - } - - result = AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed); - -finished: - delete block; - current_scope = backup_scope; - - for (auto it : to_delete) { - delete it; - } - to_delete.clear(); - - return result; -} - -void AstNode::allocateDefaultEnumValues() -{ - log_assert(type==AST_ENUM); - log_assert(children.size() > 0); - if (children.front()->attributes.count(ID::enum_base_type)) - return; // already elaborated - int last_enum_int = -1; - for (auto node : children) { - log_assert(node->type==AST_ENUM_ITEM); - node->attributes[ID::enum_base_type] = mkconst_str(str); - for (size_t i = 0; i < node->children.size(); i++) { - switch (node->children[i]->type) { - case AST_NONE: - // replace with auto-incremented constant - delete node->children[i]; - node->children[i] = AstNode::mkconst_int(++last_enum_int, true); - break; - case AST_CONSTANT: - // explicit constant (or folded expression) - // TODO: can't extend 'x or 'z item - last_enum_int = node->children[i]->integer; - break; - default: - // ignore ranges - break; - } - // TODO: range check - } - } -} - -bool AstNode::is_recursive_function() const -{ - std::set visited; - std::function visit = [&](const AstNode *node) { - if (visited.count(node)) - return node == this; - visited.insert(node); - if (node->type == AST_FCALL) { - auto it = current_scope.find(node->str); - if (it != current_scope.end() && visit(it->second)) - return true; - } - for (const AstNode *child : node->children) { - if (visit(child)) - return true; - } - return false; - }; - - log_assert(type == AST_FUNCTION); - return visit(this); -} - -std::pair AstNode::get_tern_choice() -{ - if (!children[0]->isConst()) - return {}; - - 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(true) != 0; - - AstNode *choice = nullptr, *not_choice = nullptr; - if (found_sure_true) - choice = children[1], not_choice = children[2]; - else if (!found_maybe_true) - choice = children[2], not_choice = children[1]; - - return {choice, not_choice}; -} - -std::string AstNode::try_pop_module_prefix() const -{ - AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; - size_t pos = str.find('.', 1); - if (str[0] == '\\' && pos != std::string::npos) { - std::string new_str = "\\" + str.substr(pos + 1); - if (current_scope.count(new_str)) { - std::string prefix = str.substr(0, pos); - auto it = current_scope_ast->attributes.find(ID::hdlname); - if ((it != current_scope_ast->attributes.end() && it->second->str == prefix) - || prefix == current_scope_ast->str) - return new_str; - } - } - return str; -} - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/blif/Makefile.inc b/yosys/frontends/blif/Makefile.inc deleted file mode 100644 index 9729184eb76..00000000000 --- 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 ebbe082a2e8..00000000000 --- a/yosys/frontends/blif/blifparse.cc +++ /dev/null @@ -1,659 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 - -const int lut_input_plane_limit = 12; - -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] != '-' && (name[i] < '0' || name[i] > '9')) - pos = -1; - else if (name[i] == '-' && ((i != pos+1) || name[i+1] == ']')) - pos = -1; - else if (i == pos+2 && name[i] == '0' && name[i-1] == '-') - 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)); - -failed: - return std::pair(RTLIL::IdString(), 0); -} - -void parse_blif(RTLIL::Design *design, std::istream &f, IdString 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; - char *name = strtok(NULL, " \t\r\n"); - if (name == nullptr) - goto error; - module->name = RTLIL::escape_id(name); - 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, ".blackbox")) - { - module->attributes[ID::blackbox] = RTLIL::Const(1); - continue; - } - - 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 == ID($lut) && cell->getParam(ID::LUT) == buffer_lut) { - module->connect(cell->getPort(ID::Y), cell->getPort(ID::A)); - remove_cells.push_back(cell); - } - - for (auto cell : remove_cells) - module->remove(cell); - - Wire *true_wire = module->wire(ID($true)); - Wire *false_wire = module->wire(ID($false)); - Wire *undef_wire = module->wire(ID($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.first.empty() && wp.second >= 0) { - wideports_cache[wp.first].first = std::max(wideports_cache[wp.first].first, wp.second + 1); - 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, RTLIL::escape_id(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[ID::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(ID::D, blif_wire(d)); - cell->setPort(ID::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); - RTLIL::Module *cell_mod = design->module(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.first.empty()) - cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec()); - else - cell_wideports_cache[wp.first][wp.second] = blif_wire(q); - } else { - cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec()); - } - } - - for (auto &it : cell_wideports_cache) - { - int width = 0; - int offset = 0; - bool upto = false; - for (auto &b : it.second) - width = std::max(width, b.first + 1); - - if (cell_mod) { - Wire *cell_port = cell_mod->wire(it.first); - if (cell_port && (cell_port->port_input || cell_port->port_output)) { - offset = cell_port->start_offset; - upto = cell_port->upto; - width = cell_port->width; - } - } - - SigSpec sig; - - for (int i = 0; i < width; i++) { - int idx = offset + (upto ? width - 1 - i: i); - if (it.second.count(idx)) - sig.append(it.second.at(idx)); - 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 == ID($undef)) - state = RTLIL::State::Sx; - module->connect(RTLIL::SigSig(output_sig, state)); - goto continue_without_read; - } - - if (sop_mode) - { - sopcell = module->addCell(NEW_ID, ID($sop)); - sopcell->parameters[ID::WIDTH] = RTLIL::Const(input_sig.size()); - sopcell->parameters[ID::DEPTH] = 0; - sopcell->parameters[ID::TABLE] = RTLIL::Const(); - sopcell->setPort(ID::A, input_sig); - sopcell->setPort(ID::Y, output_sig); - sopmode = -1; - lastcell = sopcell; - } - else if (input_sig.size() > lut_input_plane_limit) - { - err_reason = stringf("names' input plane must have fewer than %d signals.", lut_input_plane_limit + 1); - goto error_with_reason; - } - else - { - RTLIL::Cell *cell = module->addCell(NEW_ID, ID($lut)); - cell->parameters[ID::WIDTH] = RTLIL::Const(input_sig.size()); - cell->parameters[ID::LUT] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size()); - cell->setPort(ID::A, input_sig); - cell->setPort(ID::Y, output_sig); - lutptr = &cell->parameters.at(ID::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[ID::WIDTH].as_int() == input_len); - sopcell->parameters[ID::DEPTH] = sopcell->parameters[ID::DEPTH].as_int() + 1; - - for (int i = 0; i < input_len; i++) - switch (input[i]) { - case '0': - sopcell->parameters[ID::TABLE].bits.push_back(State::S1); - sopcell->parameters[ID::TABLE].bits.push_back(State::S0); - break; - case '1': - sopcell->parameters[ID::TABLE].bits.push_back(State::S0); - sopcell->parameters[ID::TABLE].bits.push_back(State::S1); - break; - default: - sopcell->parameters[ID::TABLE].bits.push_back(State::S0); - sopcell->parameters[ID::TABLE].bits.push_back(State::S0); - break; - } - - if (sopmode == -1) { - sopmode = (*output == '1'); - if (!sopmode) { - SigSpec outnet = sopcell->getPort(ID::Y); - SigSpec tempnet = module->addWire(NEW_ID); - module->addNotGate(NEW_ID, tempnet, outnet); - sopcell->setPort(ID::Y, tempnet); - } - } else - log_assert(sopmode == (*output == '1')); - } - - if (lutptr) - { - if (input_len > lut_input_plane_limit) - 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() 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) 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 d7a3c96b1fc..00000000000 --- a/yosys/frontends/blif/blifparse.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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, IdString dff_name, - bool run_clean = false, bool sop_mode = false, bool wideports = false); - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/json/Makefile.inc b/yosys/frontends/json/Makefile.inc deleted file mode 100644 index 0fe1b3722d8..00000000000 --- 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 1aab810153d..00000000000 --- a/yosys/frontends/json/jsonparse.cc +++ /dev/null @@ -1,667 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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; - int64_t 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 == '\\') { - ch = f.get(); - - switch (ch) { - case EOF: log_error("Unexpected EOF in JSON string.\n"); break; - case '"': - case '/': - case '\\': break; - case 'b': ch = '\b'; break; - case 'f': ch = '\f'; break; - case 'n': ch = '\n'; break; - case 'r': ch = '\r'; break; - case 't': ch = '\t'; break; - case 'u': - int val = 0; - for (int i = 0; i < 4; i++) { - ch = f.get(); - val <<= 4; - if (ch >= '0' && '9' >= ch) { - val += ch - '0'; - } else if (ch >= 'A' && 'F' >= ch) { - val += 10 + ch - 'A'; - } else if (ch >= 'a' && 'f' >= ch) { - val += 10 + ch - 'a'; - } else - log_error("Unexpected non-digit character in \\uXXXX sequence: %c.\n", ch); - } - if (val < 128) - ch = val; - else - log_error("Unsupported \\uXXXX sequence in JSON string: %04X.\n", val); - break; - } - } - - data_string += ch; - } - - break; - } - - if (('0' <= ch && ch <= '9') || ch == '-') - { - bool negative = false; - type = 'N'; - if (ch == '-') { - data_number = 0; - negative = true; - } else { - 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_number = negative ? -data_number : data_number; - 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; - } -}; - -Const json_parse_attr_param_value(JsonNode *node) -{ - Const value; - - if (node->type == 'S') { - string &s = node->data_string; - size_t cursor = s.find_first_not_of("01xz"); - if (cursor == string::npos) { - value = Const::from_string(s); - } else if (s.find_first_not_of(' ', cursor) == string::npos) { - value = Const(s.substr(0, GetSize(s)-1)); - } else { - value = Const(s); - } - } else - if (node->type == 'N') { - value = Const(node->data_number, 32); - if (node->data_number < 0) - value.flags |= RTLIL::CONST_FLAG_SIGNED; - } else - if (node->type == 'A') { - log_error("JSON attribute or parameter value is an array.\n"); - } else - if (node->type == 'D') { - log_error("JSON attribute or parameter value is a dict.\n"); - } else { - log_abort(); - } - - return value; -} - -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()); - Const value = json_parse_attr_param_value(it.second); - 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("signed") != 0) { - JsonNode *val = port_node->data_dict.at("signed"); - if (val->type == 'N') - port_wire->is_signed = 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")); - } - } - - if (node->data_dict.count("memories")) - { - JsonNode *memories_node = node->data_dict.at("memories"); - - if (memories_node->type != 'D') - log_error("JSON memories node is not a dictionary.\n"); - - for (auto &memory_node_it : memories_node->data_dict) - { - IdString memory_name = RTLIL::escape_id(memory_node_it.first.c_str()); - JsonNode *memory_node = memory_node_it.second; - - RTLIL::Memory *mem = new RTLIL::Memory; - mem->name = memory_name; - - if (memory_node->type != 'D') - log_error("JSON memory node '%s' is not a dictionary.\n", log_id(memory_name)); - - if (memory_node->data_dict.count("width") == 0) - log_error("JSON memory node '%s' has no width attribute.\n", log_id(memory_name)); - JsonNode *width_node = memory_node->data_dict.at("width"); - if (width_node->type != 'N') - log_error("JSON memory node '%s' has a non-number width.\n", log_id(memory_name)); - mem->width = width_node->data_number; - - if (memory_node->data_dict.count("size") == 0) - log_error("JSON memory node '%s' has no size attribute.\n", log_id(memory_name)); - JsonNode *size_node = memory_node->data_dict.at("size"); - if (size_node->type != 'N') - log_error("JSON memory node '%s' has a non-number size.\n", log_id(memory_name)); - mem->size = size_node->data_number; - - mem->start_offset = 0; - if (memory_node->data_dict.count("start_offset") != 0) { - JsonNode *val = memory_node->data_dict.at("start_offset"); - if (val->type == 'N') - mem->start_offset = val->data_number; - } - - if (memory_node->data_dict.count("attributes")) - json_parse_attr_param(mem->attributes, memory_node->data_dict.at("attributes")); - - module->memories[mem->name] = mem; - } - } - - // remove duplicates from connections array - pool unique_connections(module->connections_.begin(), module->connections_.end()); - module->connections_ = std::vector(unique_connections.begin(), unique_connections.end()); -} - -struct JsonFrontend : public Frontend { - JsonFrontend() : Frontend("json", "read JSON file") { } - void help() 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) 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 a02ef5e4535..00000000000 --- 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 cadbcaee69f..00000000000 --- a/yosys/frontends/liberty/liberty.cc +++ /dev/null @@ -1,724 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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, ID($_NOT_)); - cell->setPort(ID::A, A); - cell->setPort(ID::Y, module->addWire(NEW_ID)); - return cell->getPort(ID::Y); -} - -static RTLIL::SigSpec create_xor_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B) -{ - RTLIL::Cell *cell = module->addCell(NEW_ID, ID($_XOR_)); - cell->setPort(ID::A, A); - cell->setPort(ID::B, B); - cell->setPort(ID::Y, module->addWire(NEW_ID)); - return cell->getPort(ID::Y); -} - -static RTLIL::SigSpec create_and_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B) -{ - RTLIL::Cell *cell = module->addCell(NEW_ID, ID($_AND_)); - cell->setPort(ID::A, A); - cell->setPort(ID::B, B); - cell->setPort(ID::Y, module->addWire(NEW_ID)); - return cell->getPort(ID::Y); -} - -static RTLIL::SigSpec create_or_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B) -{ - RTLIL::Cell *cell = module->addCell(NEW_ID, ID($_OR_)); - cell->setPort(ID::A, A); - cell->setPort(ID::B, B); - cell->setPort(ID::Y, module->addWire(NEW_ID)); - return cell->getPort(ID::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 == ID($_NOT_) && it.second->getPort(ID::Y) == clk_sig) { - clk_sig = it.second->getPort(ID::A); - clk_polarity = !clk_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == clear_sig) { - clear_sig = it.second->getPort(ID::A); - clear_polarity = !clear_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == preset_sig) { - preset_sig = it.second->getPort(ID::A); - preset_polarity = !preset_polarity; - rerun_invert_rollback = true; - } - } - } - - RTLIL::Cell *cell = module->addCell(NEW_ID, ID($_NOT_)); - cell->setPort(ID::A, iq_sig); - cell->setPort(ID::Y, iqn_sig); - - cell = module->addCell(NEW_ID, ""); - cell->setPort(ID::D, data_sig); - cell->setPort(ID::Q, iq_sig); - cell->setPort(ID::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(ID::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(ID::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(ID::S, preset_sig); - cell->setPort(ID::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 == ID($_NOT_) && it.second->getPort(ID::Y) == enable_sig) { - enable_sig = it.second->getPort(ID::A); - enable_polarity = !enable_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == clear_sig) { - clear_sig = it.second->getPort(ID::A); - clear_polarity = !clear_polarity; - rerun_invert_rollback = true; - } - if (it.second->type == ID($_NOT_) && it.second->getPort(ID::Y) == preset_sig) { - preset_sig = it.second->getPort(ID::A); - preset_polarity = !preset_polarity; - rerun_invert_rollback = true; - } - } - } - - RTLIL::Cell *cell = module->addCell(NEW_ID, ID($_NOT_)); - cell->setPort(ID::A, iq_sig); - cell->setPort(ID::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, ID($_NOT_)); - inv->setPort(ID::A, clear_sig); - inv->setPort(ID::Y, module->addWire(NEW_ID)); - - if (clear_polarity == true) - clear_negative = inv->getPort(ID::Y); - if (clear_polarity != enable_polarity) - clear_enable = inv->getPort(ID::Y); - } - - RTLIL::Cell *data_gate = module->addCell(NEW_ID, ID($_AND_)); - data_gate->setPort(ID::A, data_sig); - data_gate->setPort(ID::B, clear_negative); - data_gate->setPort(ID::Y, data_sig = module->addWire(NEW_ID)); - - RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? ID($_OR_) : ID($_AND_)); - enable_gate->setPort(ID::A, enable_sig); - enable_gate->setPort(ID::B, clear_enable); - enable_gate->setPort(ID::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, ID($_NOT_)); - inv->setPort(ID::A, preset_sig); - inv->setPort(ID::Y, module->addWire(NEW_ID)); - - if (preset_polarity == false) - preset_positive = inv->getPort(ID::Y); - if (preset_polarity != enable_polarity) - preset_enable = inv->getPort(ID::Y); - } - - RTLIL::Cell *data_gate = module->addCell(NEW_ID, ID($_OR_)); - data_gate->setPort(ID::A, data_sig); - data_gate->setPort(ID::B, preset_positive); - data_gate->setPort(ID::Y, data_sig = module->addWire(NEW_ID)); - - RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? ID($_OR_) : ID($_AND_)); - enable_gate->setPort(ID::A, enable_sig); - enable_gate->setPort(ID::B, preset_enable); - enable_gate->setPort(ID::Y, data_sig = module->addWire(NEW_ID)); - } - - cell = module->addCell(NEW_ID, stringf("$_DLATCH_%c_", enable_polarity ? 'P' : 'N')); - cell->setPort(ID::D, data_sig); - cell->setPort(ID::Q, iq_sig); - cell->setPort(ID::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() 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(" -wb\n"); - log(" mark imported cells as whiteboxes\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) override - { - bool flag_lib = false; - bool flag_wb = 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; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-lib") { - flag_lib = true; - continue; - } - if (arg == "-wb") { - flag_wb = 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); - - if (flag_wb && flag_lib) - log_error("-wb and -lib cannot be specified together!\n"); - - log_header(design, "Executing Liberty frontend: %s\n", filename.c_str()); - - 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(ID::blackbox)) { - log_error("Re-definition 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(ID::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(ID::blackbox); - - if (flag_wb) - module->set_bool_attribute(ID::whitebox); - - 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/rpc/Makefile.inc b/yosys/frontends/rpc/Makefile.inc deleted file mode 100644 index fa1d068f941..00000000000 --- a/yosys/frontends/rpc/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -ifeq ($(DISABLE_SPAWN),0) -OBJS += frontends/rpc/rpc_frontend.o -endif diff --git a/yosys/frontends/rpc/rpc_frontend.cc b/yosys/frontends/rpc/rpc_frontend.cc deleted file mode 100644 index ec3952661ef..00000000000 --- a/yosys/frontends/rpc/rpc_frontend.cc +++ /dev/null @@ -1,598 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2019 whitequark - * - * 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 reason the -path mode of connect_rpc uses byte-oriented and not message-oriented sockets, even though -// it is a message-oriented interface, is that the system can place various limits on the message size, which -// are not always transparent or easy to change. Given that generated HDL code get be extremely large, it is -// unwise to rely on those limits being large enough, and using byte-oriented sockets is guaranteed to work. - -#ifndef _WIN32 -#include -#include -#include -#include -#include -extern char **environ; -#endif - -#include "libs/json11/json11.hpp" -#include "libs/sha1/sha1.h" -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -#if defined(_WIN32) -static std::wstring str2wstr(const std::string &in) { - if(in == "") return L""; - std::wstring out; - out.resize(MultiByteToWideChar(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/&in[0], /*cbMultiByte=*/(int)in.length(), /*lpWideCharStr=*/NULL, /*cchWideChar=*/0)); - int written = MultiByteToWideChar(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/&in[0], /*cbMultiByte=*/(int)in.length(), /*lpWideCharStr=*/&out[0], /*cchWideChar=*/(int)out.length()); - log_assert(written == (int)out.length()); - return out; -} - -static std::string wstr2str(const std::wstring &in) { - if(in == L"") return ""; - std::string out; - out.resize(WideCharToMultiByte(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpWideCharStr=*/&in[0], /*cchWideChar=*/(int)in.length(), /*lpMultiByteStr=*/NULL, /*cbMultiByte=*/0, /*lpDefaultChar=*/NULL, /*lpUsedDefaultChar=*/NULL)); - int written = WideCharToMultiByte(/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpWideCharStr=*/&in[0], /*cchWideChar=*/(int)in.length(), /*lpMultiByteStr=*/&out[0], /*cbMultiByte=*/(int)out.length(), /*lpDefaultChar=*/NULL, /*lpUsedDefaultChar=*/NULL); - log_assert(written == (int)out.length()); - return out; -} - -static std::string get_last_error_str() { - DWORD last_error = GetLastError(); - LPWSTR out_w; - DWORD size_w = FormatMessageW(/*dwFlags=*/FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS, /*lpSource=*/NULL, /*dwMessageId=*/last_error, /*dwLanguageId=*/0, /*lpBuffer=*/(LPWSTR)&out_w, /*nSize=*/0, /*Arguments=*/NULL); - if (size_w == 0) - return std::to_string(last_error); - std::string out = wstr2str(std::wstring(out_w, size_w)); - LocalFree(out_w); - return out; -} -#endif - -using json11::Json; - -struct RpcServer { - std::string name; - - RpcServer(const std::string &name) : name(name) { } - virtual ~RpcServer() { } - - virtual void write(const std::string &data) = 0; - virtual std::string read() = 0; - - Json call(const Json &json_request) { - std::string request; - json_request.dump(request); - request += '\n'; - log_debug("RPC frontend request: %s", request.c_str()); - write(request); - - std::string response = read(); - log_debug("RPC frontend response: %s", response.c_str()); - std::string error; - Json json_response = Json::parse(response, error); - if (json_response.is_null()) - log_cmd_error("parsing JSON failed: %s\n", error.c_str()); - if (json_response["error"].is_string()) - log_cmd_error("RPC frontend returned an error: %s\n", json_response["error"].string_value().c_str()); - return json_response; - } - - std::vector get_module_names() { - Json response = call(Json::object { - { "method", "modules" }, - }); - bool is_valid = true; - std::vector modules; - if (response["modules"].is_array()) { - for (auto &json_module : response["modules"].array_items()) { - if (json_module.is_string()) - modules.push_back(json_module.string_value()); - else is_valid = false; - } - } else is_valid = false; - if (!is_valid) - log_cmd_error("RPC frontend returned malformed response: %s\n", response.dump().c_str()); - return modules; - } - - std::pair derive_module(const std::string &module, const dict ¶meters) { - Json::object json_parameters; - for (auto ¶m : parameters) { - std::string type, value; - if (param.second.flags & RTLIL::CONST_FLAG_REAL) { - type = "real"; - value = param.second.decode_string(); - } else if (param.second.flags & RTLIL::CONST_FLAG_STRING) { - type = "string"; - value = param.second.decode_string(); - } else if ((param.second.flags & ~RTLIL::CONST_FLAG_SIGNED) == RTLIL::CONST_FLAG_NONE) { - type = (param.second.flags & RTLIL::CONST_FLAG_SIGNED) ? "signed" : "unsigned"; - value = param.second.as_string(); - } else - log_cmd_error("Unserializable constant flags 0x%x\n", param.second.flags); - json_parameters[param.first.str()] = Json::object { - { "type", type }, - { "value", value }, - }; - } - Json response = call(Json::object { - { "method", "derive" }, - { "module", module }, - { "parameters", json_parameters }, - }); - bool is_valid = true; - std::string frontend, source; - if (response["frontend"].is_string()) - frontend = response["frontend"].string_value(); - else is_valid = false; - if (response["source"].is_string()) - source = response["source"].string_value(); - else is_valid = false; - if (!is_valid) - log_cmd_error("RPC frontend returned malformed response: %s\n", response.dump().c_str()); - return std::make_pair(frontend, source); - } -}; - -struct RpcModule : RTLIL::Module { - std::shared_ptr server; - - RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool /*mayfail*/) override { - std::string stripped_name = name.str(); - if (stripped_name.compare(0, 9, "$abstract") == 0) - stripped_name = stripped_name.substr(9); - log_assert(stripped_name[0] == '\\'); - - log_header(design, "Executing RPC frontend `%s' for module `%s'.\n", server->name.c_str(), stripped_name.c_str()); - - std::string parameter_info; - for (auto ¶m : parameters) { - log("Parameter %s = %s\n", param.first.c_str(), log_signal(RTLIL::SigSpec(param.second))); - parameter_info += stringf("%s=%s", param.first.c_str(), log_signal(RTLIL::SigSpec(param.second))); - } - - std::string derived_name; - if (parameters.empty()) - derived_name = stripped_name; - else if (parameter_info.size() > 60) - derived_name = "$paramod$" + sha1(parameter_info) + stripped_name; - else - derived_name = "$paramod" + stripped_name + parameter_info; - - if (design->has(derived_name)) { - log("Found cached RTLIL representation for module `%s'.\n", derived_name.c_str()); - } else { - std::string command, input; - std::tie(command, input) = server->derive_module(stripped_name.substr(1), parameters); - - std::istringstream input_stream(input); - RTLIL::Design *derived_design = new RTLIL::Design; - Frontend::frontend_call(derived_design, &input_stream, "" + derived_name.substr(8), command); - derived_design->check(); - - dict name_mangling; - bool found_derived_top = false; - for (auto module : derived_design->modules()) { - std::string original_name = module->name.str(); - if (original_name == stripped_name) { - found_derived_top = true; - name_mangling[original_name] = derived_name; - } else { - name_mangling[original_name] = derived_name + module->name.str(); - } - } - if (!found_derived_top) - log_cmd_error("RPC frontend did not return requested module `%s`!\n", stripped_name.c_str()); - - for (auto module : derived_design->modules()) - for (auto cell : module->cells()) - if (name_mangling.count(cell->type.str())) - cell->type = name_mangling[cell->type.str()]; - - for (auto module : derived_design->modules_) { - std::string mangled_name = name_mangling[module.first.str()]; - - log("Importing `%s' as `%s'.\n", log_id(module.first), log_id(mangled_name)); - - module.second->name = mangled_name; - module.second->design = design; - module.second->attributes.erase(ID::top); - if (!module.second->has_attribute(ID::hdlname)) - module.second->set_string_attribute(ID::hdlname, module.first.str()); - design->modules_[mangled_name] = module.second; - derived_design->modules_.erase(module.first); - } - - delete derived_design; - } - - return derived_name; - } - - RTLIL::Module *clone() const override { - RpcModule *new_mod = new RpcModule; - new_mod->server = server; - cloneInto(new_mod); - return new_mod; - } -}; - -#if defined(_WIN32) - -#if defined(_MSC_VER) -#include -typedef SSIZE_T ssize_t; -#endif - -struct HandleRpcServer : RpcServer { - HANDLE hsend, hrecv; - - HandleRpcServer(const std::string &name, HANDLE hsend, HANDLE hrecv) - : RpcServer(name), hsend(hsend), hrecv(hrecv) { } - - void write(const std::string &data) override { - log_assert(data.length() >= 1 && data.find('\n') == data.length() - 1); - ssize_t offset = 0; - do { - DWORD data_written; - if (!WriteFile(hsend, &data[offset], data.length() - offset, &data_written, /*lpOverlapped=*/NULL)) - log_cmd_error("WriteFile failed: %s\n", get_last_error_str().c_str()); - offset += data_written; - } while(offset < (ssize_t)data.length()); - } - - std::string read() override { - std::string data; - ssize_t offset = 0; - while (data.length() == 0 || data[data.length() - 1] != '\n') { - data.resize(data.length() + 1024); - DWORD data_read; - if (!ReadFile(hrecv, &data[offset], data.length() - offset, &data_read, /*lpOverlapped=*/NULL)) - log_cmd_error("ReadFile failed: %s\n", get_last_error_str().c_str()); - offset += data_read; - data.resize(offset); - size_t term_pos = data.find('\n', offset); - if (term_pos != data.length() - 1 && term_pos != std::string::npos) - log_cmd_error("read failed: more than one response\n"); - } - return data; - } - - ~HandleRpcServer() { - CloseHandle(hsend); - if (hrecv != hsend) - CloseHandle(hrecv); - } -}; - -#else - -struct FdRpcServer : RpcServer { - int fdsend, fdrecv; - pid_t pid; - - FdRpcServer(const std::string &name, int fdsend, int fdrecv, pid_t pid = -1) - : RpcServer(name), fdsend(fdsend), fdrecv(fdrecv), pid(pid) { } - - void check_pid() { - if (pid == -1) return; - // If we're communicating with a process, check that it's still running, or we may get killed with SIGPIPE. - pid_t wait_result = ::waitpid(pid, NULL, WNOHANG); - if (wait_result == -1) - log_cmd_error("waitpid failed: %s\n", strerror(errno)); - if (wait_result == pid) - log_cmd_error("RPC frontend terminated unexpectedly\n"); - } - - void write(const std::string &data) override { - log_assert(data.length() >= 1 && data.find('\n') == data.length() - 1); - ssize_t offset = 0; - do { - check_pid(); - ssize_t result = ::write(fdsend, &data[offset], data.length() - offset); - if (result == -1) - log_cmd_error("write failed: %s\n", strerror(errno)); - offset += result; - } while(offset < (ssize_t)data.length()); - } - - std::string read() override { - std::string data; - ssize_t offset = 0; - while (data.length() == 0 || data[data.length() - 1] != '\n') { - data.resize(data.length() + 1024); - check_pid(); - ssize_t result = ::read(fdrecv, &data[offset], data.length() - offset); - if (result == -1) - log_cmd_error("read failed: %s\n", strerror(errno)); - offset += result; - data.resize(offset); - size_t term_pos = data.find('\n', offset); - if (term_pos != data.length() - 1 && term_pos != std::string::npos) - log_cmd_error("read failed: more than one response\n"); - } - return data; - } - - ~FdRpcServer() { - close(fdsend); - if (fdrecv != fdsend) - close(fdrecv); - } -}; - -#endif - -// RpcFrontend does not inherit from Frontend since it does not read files. -struct RpcFrontend : public Pass { - RpcFrontend() : Pass("connect_rpc", "connect to RPC frontend") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" connect_rpc -exec [args...]\n"); - log(" connect_rpc -path \n"); - log("\n"); - log("Load modules using an out-of-process frontend.\n"); - log("\n"); - log(" -exec [args...]\n"); - log(" run with arguments [args...]. send requests on stdin, read\n"); - log(" responses from stdout.\n"); - log("\n"); - log(" -path \n"); - log(" connect to Unix domain socket at . (Unix)\n"); - log(" connect to bidirectional byte-type named pipe at . (Windows)\n"); - log("\n"); - log("A simple JSON-based, newline-delimited protocol is used for communicating with\n"); - log("the frontend. Yosys requests data from the frontend by sending exactly 1 line\n"); - log("of JSON. Frontend responds with data or error message by replying with exactly\n"); - log("1 line of JSON as well.\n"); - log("\n"); - log(" -> {\"method\": \"modules\"}\n"); - log(" <- {\"modules\": [\"\", ...]}\n"); - log(" <- {\"error\": \"\"}\n"); - log(" request for the list of modules that can be derived by this frontend.\n"); - log(" the 'hierarchy' command will call back into this frontend if a cell\n"); - log(" with type is instantiated in the design.\n"); - log("\n"); - log(" -> {\"method\": \"derive\", \"module\": \", \"parameters\": {\n"); - log(" \"\": {\"type\": \"[unsigned|signed|string|real]\",\n"); - log(" \"value\": \"\"}, ...}}\n"); - log(" <- {\"frontend\": \"[rtlil|verilog|...]\",\"source\": \"\"}}\n"); - log(" <- {\"error\": \"\"}\n"); - log(" request for the module to be derived for a specific set of\n"); - log(" parameters. starts with \\ for named parameters, and with $\n"); - log(" for unnamed parameters, which are numbered starting at 1.\n"); - log(" for integer parameters is always specified as a binary string of\n"); - log(" unlimited precision. the returned by the frontend is\n"); - log(" hygienically parsedby a built-in Yosys , allowing the RPC\n"); - log(" frontend to return anyconvenient representation of the module. the\n"); - log(" derived module is cached,so the response should be the same whenever the\n"); - log(" same set of parameters is provided.\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - log_header(design, "Connecting to RPC frontend.\n"); - - std::vector command; - std::string path; - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-exec" && argidx+1 < args.size()) { - command.insert(command.begin(), args.begin() + argidx + 1, args.end()); - argidx = args.size()-1; - continue; - } - if (arg == "-path" && argidx+1 < args.size()) { - path = args[++argidx]; - continue; - } - break; - } - extra_args(args, argidx, design); - - if ((!command.empty()) + (!path.empty()) != 1) - log_cmd_error("Exactly one of -exec, -unix must be specified.\n"); - - std::shared_ptr server; - if (!command.empty()) { - std::string command_line; - bool first = true; - for (auto &arg : command) { - if (!first) command_line += ' '; - command_line += arg; - first = false; - } - -#ifdef _WIN32 - std::wstring command_w = str2wstr(command[0]); - std::wstring command_path_w; - std::wstring command_line_w = str2wstr(command_line); - DWORD command_path_len_w; - SECURITY_ATTRIBUTES pipe_attr = {}; - HANDLE send_r = NULL, send_w = NULL, recv_r = NULL, recv_w = NULL; - STARTUPINFOW startup_info = {}; - PROCESS_INFORMATION proc_info = {}; - - command_path_len_w = SearchPathW(/*lpPath=*/NULL, /*lpFileName=*/command_w.c_str(), /*lpExtension=*/L".exe", /*nBufferLength=*/0, /*lpBuffer=*/NULL, /*lpFilePart=*/NULL); - if (command_path_len_w == 0) { - log_error("SearchPathW failed: %s\n", get_last_error_str().c_str()); - goto cleanup_exec; - } - command_path_w.resize(command_path_len_w - 1); - command_path_len_w = SearchPathW(/*lpPath=*/NULL, /*lpFileName=*/command_w.c_str(), /*lpExtension=*/L".exe", /*nBufferLength=*/command_path_len_w, /*lpBuffer=*/&command_path_w[0], /*lpFilePart=*/NULL); - log_assert(command_path_len_w == command_path_w.length()); - - pipe_attr.nLength = sizeof(pipe_attr); - pipe_attr.bInheritHandle = TRUE; - pipe_attr.lpSecurityDescriptor = NULL; - if (!CreatePipe(&send_r, &send_w, &pipe_attr, /*nSize=*/0)) { - log_error("CreatePipe failed: %s\n", get_last_error_str().c_str()); - goto cleanup_exec; - } - if (!SetHandleInformation(send_w, HANDLE_FLAG_INHERIT, 0)) { - log_error("SetHandleInformation failed: %s\n", get_last_error_str().c_str()); - goto cleanup_exec; - } - if (!CreatePipe(&recv_r, &recv_w, &pipe_attr, /*nSize=*/0)) { - log_error("CreatePipe failed: %s\n", get_last_error_str().c_str()); - goto cleanup_exec; - } - if (!SetHandleInformation(recv_r, HANDLE_FLAG_INHERIT, 0)) { - log_error("SetHandleInformation failed: %s\n", get_last_error_str().c_str()); - goto cleanup_exec; - } - - startup_info.cb = sizeof(startup_info); - startup_info.hStdInput = send_r; - startup_info.hStdOutput = recv_w; - startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); - startup_info.dwFlags |= STARTF_USESTDHANDLES; - if (!CreateProcessW(/*lpApplicationName=*/command_path_w.c_str(), /*lpCommandLine=*/&command_line_w[0], /*lpProcessAttributes=*/NULL, /*lpThreadAttributes=*/NULL, /*bInheritHandles=*/TRUE, /*dwCreationFlags=*/0, /*lpEnvironment=*/NULL, /*lpCurrentDirectory=*/NULL, &startup_info, &proc_info)) { - log_error("CreateProcessW failed: %s\n", get_last_error_str().c_str()); - goto cleanup_exec; - } - CloseHandle(proc_info.hProcess); - CloseHandle(proc_info.hThread); - - server = std::make_shared(path, send_w, recv_r); - send_w = NULL; - recv_r = NULL; - -cleanup_exec: - if (send_r != NULL) CloseHandle(send_r); - if (send_w != NULL) CloseHandle(send_w); - if (recv_r != NULL) CloseHandle(recv_r); - if (recv_w != NULL) CloseHandle(recv_w); -#else - std::vector argv; - int send[2] = {-1,-1}, recv[2] = {-1,-1}; - posix_spawn_file_actions_t file_actions, *file_actions_p = NULL; - pid_t pid; - - for (auto &arg : command) - argv.push_back(&arg[0]); - argv.push_back(nullptr); - - if (pipe(send) != 0) { - log_error("pipe failed: %s\n", strerror(errno)); - goto cleanup_exec; - } - if (pipe(recv) != 0) { - log_error("pipe failed: %s\n", strerror(errno)); - goto cleanup_exec; - } - - if (posix_spawn_file_actions_init(&file_actions) != 0) { - log_error("posix_spawn_file_actions_init failed: %s\n", strerror(errno)); - goto cleanup_exec; - } - file_actions_p = &file_actions; - if (posix_spawn_file_actions_adddup2(file_actions_p, send[0], STDIN_FILENO) != 0) { - log_error("posix_spawn_file_actions_adddup2 failed: %s\n", strerror(errno)); - goto cleanup_exec; - } - if (posix_spawn_file_actions_addclose(file_actions_p, send[1]) != 0) { - log_error("posix_spawn_file_actions_addclose failed: %s\n", strerror(errno)); - goto cleanup_exec; - } - if (posix_spawn_file_actions_adddup2(file_actions_p, recv[1], STDOUT_FILENO) != 0) { - log_error("posix_spawn_file_actions_adddup2 failed: %s\n", strerror(errno)); - goto cleanup_exec; - } - if (posix_spawn_file_actions_addclose(file_actions_p, recv[0]) != 0) { - log_error("posix_spawn_file_actions_addclose failed: %s\n", strerror(errno)); - goto cleanup_exec; - } - - if (posix_spawnp(&pid, argv[0], file_actions_p, /*attrp=*/NULL, argv.data(), environ) != 0) { - log_error("posix_spawnp failed: %s\n", strerror(errno)); - goto cleanup_exec; - } - - server = std::make_shared(command_line, send[1], recv[0], pid); - send[1] = -1; - recv[0] = -1; - -cleanup_exec: - if (send[0] != -1) close(send[0]); - if (send[1] != -1) close(send[1]); - if (recv[0] != -1) close(recv[0]); - if (recv[1] != -1) close(recv[1]); - if (file_actions_p != NULL) - posix_spawn_file_actions_destroy(file_actions_p); -#endif - } else if (!path.empty()) { -#ifdef _WIN32 - std::wstring path_w = str2wstr(path); - HANDLE h; - - h = CreateFileW(path_w.c_str(), GENERIC_READ|GENERIC_WRITE, /*dwShareMode=*/0, /*lpSecurityAttributes=*/NULL, /*dwCreationDisposition=*/OPEN_EXISTING, /*dwFlagsAndAttributes=*/0, /*hTemplateFile=*/NULL); - if (h == INVALID_HANDLE_VALUE) { - log_error("CreateFileW failed: %s\n", get_last_error_str().c_str()); - goto cleanup_path; - } - - server = std::make_shared(path, h, h); - -cleanup_path: - ; -#else - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1); - - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) { - log_error("socket failed: %s\n", strerror(errno)); - goto cleanup_path; - } - - if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - log_error("connect failed: %s\n", strerror(errno)); - goto cleanup_path; - } - - server = std::make_shared(path, fd, fd); - fd = -1; - -cleanup_path: - if (fd != -1) close(fd); -#endif - } - - if (!server) - log_cmd_error("Failed to connect to RPC frontend.\n"); - - for (auto &module_name : server->get_module_names()) { - log("Linking module `%s'.\n", module_name.c_str()); - RpcModule *module = new RpcModule; - module->name = "$abstract\\" + module_name; - module->server = server; - design->add(module); - } - } -} RpcFrontend; - -YOSYS_NAMESPACE_END diff --git a/yosys/frontends/rtlil/.gitignore b/yosys/frontends/rtlil/.gitignore deleted file mode 100644 index d4a32275606..00000000000 --- a/yosys/frontends/rtlil/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -rtlil_lexer.cc -rtlil_parser.output -rtlil_parser.tab.cc -rtlil_parser.tab.hh diff --git a/yosys/frontends/rtlil/Makefile.inc b/yosys/frontends/rtlil/Makefile.inc deleted file mode 100644 index d0c0cfcf8a8..00000000000 --- a/yosys/frontends/rtlil/Makefile.inc +++ /dev/null @@ -1,19 +0,0 @@ - -GENFILES += frontends/rtlil/rtlil_parser.tab.cc -GENFILES += frontends/rtlil/rtlil_parser.tab.hh -GENFILES += frontends/rtlil/rtlil_parser.output -GENFILES += frontends/rtlil/rtlil_lexer.cc - -frontends/rtlil/rtlil_parser.tab.cc: frontends/rtlil/rtlil_parser.y - $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -o $@ -d -r all -b frontends/rtlil/rtlil_parser $< - -frontends/rtlil/rtlil_parser.tab.hh: frontends/rtlil/rtlil_parser.tab.cc - -frontends/rtlil/rtlil_lexer.cc: frontends/rtlil/rtlil_lexer.l - $(Q) mkdir -p $(dir $@) - $(P) flex -o frontends/rtlil/rtlil_lexer.cc $< - -OBJS += frontends/rtlil/rtlil_parser.tab.o frontends/rtlil/rtlil_lexer.o -OBJS += frontends/rtlil/rtlil_frontend.o - diff --git a/yosys/frontends/rtlil/rtlil_frontend.cc b/yosys/frontends/rtlil/rtlil_frontend.cc deleted file mode 100644 index 5f85ca2b88b..00000000000 --- a/yosys/frontends/rtlil/rtlil_frontend.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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. - * - */ - -#include "rtlil_frontend.h" -#include "kernel/register.h" -#include "kernel/log.h" - -void rtlil_frontend_yyerror(char const *s) -{ - YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s); -} - -YOSYS_NAMESPACE_BEGIN - -struct RTLILFrontend : public Frontend { - RTLILFrontend() : Frontend("rtlil", "read modules from RTLIL file") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" read_rtlil [filename]\n"); - log("\n"); - log("Load modules from an RTLIL file to the current design. (RTLIL 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) override - { - RTLIL_FRONTEND::flag_nooverwrite = false; - RTLIL_FRONTEND::flag_overwrite = false; - RTLIL_FRONTEND::flag_lib = false; - - log_header(design, "Executing RTLIL frontend.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-nooverwrite") { - RTLIL_FRONTEND::flag_nooverwrite = true; - RTLIL_FRONTEND::flag_overwrite = false; - continue; - } - if (arg == "-overwrite") { - RTLIL_FRONTEND::flag_nooverwrite = false; - RTLIL_FRONTEND::flag_overwrite = true; - continue; - } - if (arg == "-lib") { - RTLIL_FRONTEND::flag_lib = true; - continue; - } - break; - } - extra_args(f, filename, args, argidx); - - log("Input filename: %s\n", filename.c_str()); - - RTLIL_FRONTEND::lexin = f; - RTLIL_FRONTEND::current_design = design; - rtlil_frontend_yydebug = false; - rtlil_frontend_yyrestart(NULL); - rtlil_frontend_yyparse(); - rtlil_frontend_yylex_destroy(); - } -} RTLILFrontend; - -struct IlangFrontend : public Frontend { - IlangFrontend() : Frontend("ilang", "(deprecated) alias of read_rtlil") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log("See `help read_rtlil`.\n"); - log("\n"); - } - void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) override - { - RTLILFrontend.execute(f, filename, args, design); - } -} IlangFrontend; - -YOSYS_NAMESPACE_END - diff --git a/yosys/frontends/rtlil/rtlil_frontend.h b/yosys/frontends/rtlil/rtlil_frontend.h deleted file mode 100644 index 18926060545..00000000000 --- a/yosys/frontends/rtlil/rtlil_frontend.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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. - * - */ - -#ifndef RTLIL_FRONTEND_H -#define RTLIL_FRONTEND_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -namespace RTLIL_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_yydebug; -int rtlil_frontend_yylex(void); -void rtlil_frontend_yyerror(char const *s); -void rtlil_frontend_yyrestart(FILE *f); -int rtlil_frontend_yyparse(void); -int rtlil_frontend_yylex_destroy(void); -int rtlil_frontend_yyget_lineno(void); - -#endif - diff --git a/yosys/frontends/rtlil/rtlil_lexer.l b/yosys/frontends/rtlil/rtlil_lexer.l deleted file mode 100644 index e164132167a..00000000000 --- a/yosys/frontends/rtlil/rtlil_lexer.l +++ /dev/null @@ -1,150 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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. - * - */ - -%{ - -#ifdef __clang__ -// bison generates code using the 'register' storage class specifier -#pragma clang diagnostic ignored "-Wdeprecated-register" -#endif - -#include -#include "frontends/rtlil/rtlil_frontend.h" -#include "rtlil_parser.tab.hh" - -USING_YOSYS_NAMESPACE - -#define YY_INPUT(buf,result,max_size) \ - result = readsome(*RTLIL_FRONTEND::lexin, buf, max_size) - -%} - -%option yylineno -%option noyywrap -%option nounput -%option prefix="rtlil_frontend_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; } -"memwr" { return TOK_MEMWR; } -"process" { return TOK_PROCESS; } -"end" { return TOK_END; } - -[a-z]+ { return TOK_INVALID; } - -"\\"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } -"$"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } - -[0-9]+'[01xzm-]* { rtlil_frontend_yylval.string = strdup(yytext); return TOK_VALUE; } --?[0-9]+ { - char *end = nullptr; - errno = 0; - long value = strtol(yytext, &end, 10); - log_assert(end == yytext + strlen(yytext)); - if (errno == ERANGE) - return TOK_INVALID; // literal out of range of long - if (value < INT_MIN || value > INT_MAX) - return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms) - rtlil_frontend_yylval.integer = value; - 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_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_avoid_input_warnings() { - return (void*)&yyinput; -} diff --git a/yosys/frontends/rtlil/rtlil_parser.y b/yosys/frontends/rtlil/rtlil_parser.y deleted file mode 100644 index 7d99b2c4220..00000000000 --- a/yosys/frontends/rtlil/rtlil_parser.y +++ /dev/null @@ -1,501 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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. - * - */ - -%require "3.0" - -%{ -#include -#include "frontends/rtlil/rtlil_frontend.h" -YOSYS_NAMESPACE_BEGIN -namespace RTLIL_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 RTLIL_FRONTEND; -YOSYS_NAMESPACE_END -USING_YOSYS_NAMESPACE -%} - -%define api.prefix {rtlil_frontend_yy} - -/* The union is defined in the header, so we need to provide all the - * includes it requires - */ -%code requires { -#include -#include -#include "frontends/rtlil/rtlil_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_MEMWR 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_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(ID::blackbox) && attrbuf.at(ID::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(ID::blackbox)) { - rtlil_frontend_yyerror(stringf("RTLIL 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(ID::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_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 | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; - -param_stmt: - TOK_PARAMETER TOK_ID EOL { - current_module->avail_parameters($2); - free($2); - }; - -param_defval_stmt: - TOK_PARAMETER TOK_ID constant EOL { - current_module->avail_parameters($2); - current_module->parameter_default_values[$2] = *$3; - delete $3; - 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("$__rtlil_frontend_tmp__"); - current_wire->attributes = attrbuf; - attrbuf.clear(); - } wire_options TOK_ID EOL { - if (current_module->wire($4) != nullptr) - rtlil_frontend_yyerror(stringf("RTLIL 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_WIDTH TOK_INVALID { - rtlil_frontend_yyerror("RTLIL error: invalid wire width"); - } | - wire_options TOK_UPTO { - current_wire->upto = true; - } | - wire_options TOK_SIGNED { - current_wire->is_signed = 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_yyerror(stringf("RTLIL 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->cell($3) != nullptr) - rtlil_frontend_yyerror(stringf("RTLIL 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_yyerror(stringf("RTLIL 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_yyerror(stringf("RTLIL error: redefinition of process %s.", $2).c_str()); - current_process = current_module->addProcess($2); - current_process->attributes = attrbuf; - 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_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; - } | - update_list attr_list TOK_MEMWR TOK_ID sigspec sigspec sigspec constant EOL { - RTLIL::MemWriteAction act; - act.attributes = attrbuf; - act.memid = $4; - act.address = *$5; - act.data = *$6; - act.enable = *$7; - act.priority_mask = *$8; - current_process->syncs.back()->mem_write_actions.push_back(std::move(act)); - attrbuf.clear(); - free($4); - delete $5; - delete $6; - delete $7; - delete $8; - } | - /* 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->wire($1) == nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: wire %s not found", $1).c_str()); - $$ = new RTLIL::SigSpec(current_module->wire($1)); - free($1); - } | - sigspec '[' TOK_INT ']' { - if ($3 >= $1->size() || $3 < 0) - rtlil_frontend_yyerror("bit index out of range"); - $$ = new RTLIL::SigSpec($1->extract($3)); - delete $1; - } | - sigspec '[' TOK_INT ':' TOK_INT ']' { - if ($3 >= $1->size() || $3 < 0 || $3 < $5) - rtlil_frontend_yyerror("invalid slice"); - $$ = 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_yyerror("dangling attribute"); - current_module->connect(*$2, *$3); - delete $2; - delete $3; - }; diff --git a/yosys/frontends/verific/Makefile.inc b/yosys/frontends/verific/Makefile.inc deleted file mode 100644 index c82428613af..00000000000 --- a/yosys/frontends/verific/Makefile.inc +++ /dev/null @@ -1,22 +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 -ifneq ($(DISABLE_VERIFIC_VHDL),1) - $(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 -endif - $(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 921873af315..00000000000 --- a/yosys/frontends/verific/README +++ /dev/null @@ -1,37 +0,0 @@ - -This directory contains Verific bindings for Yosys. - -Use Tabby CAD Suite from YosysHQ if you need Yosys+Verific. -https://www.yosyshq.com/ - -Contact YosysHQ at contact@yosyshq.com for free evaluation -binaries of Tabby CAD Suite. - - -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 ffbf33cab3d..00000000000 --- 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 21a5d42c85c..00000000000 --- 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 index c1e9fc7d027..5d93954a73a 100644 --- a/yosys/frontends/verific/verific.cc +++ b/yosys/frontends/verific/verific.cc @@ -200,14 +200,6 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) return s; } -static bool isNumber(const string& str) -{ - for (auto &c : str) { - if (std::isdigit(c) == 0) return false; - } - return true; -} - // When used as attributes or parameter values Verific constants come already processed. // - Real string values are already under quotes // - Numeric values with specified width are always converted to binary @@ -215,19 +207,37 @@ static bool isNumber(const string& str) // - There could be some internal values that are strings without quotes // so we check if value is all digits or not // -static const RTLIL::Const verific_const(const char *value) +// Note: For signed values, verific uses 'sb and decimal values can +// also be negative. +static const RTLIL::Const verific_const(const char *value, bool allow_string = true, bool output_signed = false) { + size_t found; + char *end; + int decimal; + bool is_signed = false; + RTLIL::Const c; std::string val = std::string(value); - if (val.size()>1 && val[0]=='\"' && val.back()=='\"') - return RTLIL::Const(val.substr(1,val.size()-2)); - else - if (val.find("'b") != std::string::npos) - return RTLIL::Const::from_string(val.substr(val.find("'b") + 2)); - else - if (isNumber(val)) - return RTLIL::Const(std::stoi(val),32); - else - return RTLIL::Const(val); + if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') { + c = RTLIL::Const(val.substr(1,val.size()-2)); + } else if ((found = val.find("'sb")) != std::string::npos) { + is_signed = output_signed; + c = RTLIL::Const::from_string(val.substr(found + 3)); + } else if ((found = val.find("'b")) != std::string::npos) { + c = RTLIL::Const::from_string(val.substr(found + 2)); + } else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) && + ((decimal = std::strtol(value, &end, 10)), !end[0])) { + is_signed = output_signed; + c = RTLIL::Const((int)decimal, 32); + } else if (allow_string) { + c = RTLIL::Const(val); + } else { + log_error("expected numeric constant but found '%s'", value); + } + + if (is_signed) + c.flags |= RTLIL::CONST_FLAG_SIGNED; + + return c; } void VerificImporter::import_attributes(dict &attributes, DesignObj *obj, Netlist *nl) @@ -263,21 +273,9 @@ void VerificImporter::import_attributes(dict &att const char *k, *v; FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mi, &k, &v) { if (nl->IsFromVerilog()) { - // Expect 'b - auto p = strchr(v, '\''); - if (p) { - if (*(p+1) != 'b') - p = nullptr; - else - for (auto q = p+2; *q != '\0'; q++) - if (*q != '0' && *q != '1' && *q != 'x' && *q != 'z') { - p = nullptr; - break; - } - } - if (p == nullptr) - log_error("Expected TypeRange value '%s' to be of form 'b.\n", v); - attributes.emplace(stringf("\\enum_value_%s", p+2), RTLIL::escape_id(k)); + auto const value = verific_const(v, false); + + attributes.emplace(stringf("\\enum_value_%s", value.as_string().c_str()), RTLIL::escape_id(k)); } #ifdef VERIFIC_VHDL_SUPPORT else if (nl->IsFromVhdl()) { @@ -1043,21 +1041,49 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr sw->signal = sig_select; current_case->switches.push_back(sw); - int select_width = inst->InputSize(); - int data_width = inst->OutputSize(); - int select_num = inst->Input1Size() / inst->InputSize(); + unsigned select_width = inst->InputSize(); + unsigned data_width = inst->OutputSize(); + unsigned offset_data = 0; + unsigned offset_select = 0; - int offset_select = 0; - int offset_data = 0; + OperWideCaseSelector* selector = (OperWideCaseSelector*) inst->View(); - for (int i = 0; i < select_num; i++) { - RTLIL::CaseRule *cs = new RTLIL::CaseRule; - cs->compare.push_back(sig_select_values.extract(offset_select, select_width)); - cs->actions.push_back(SigSig(sig_out_val, sig_data_values.extract(offset_data, data_width))); - sw->cases.push_back(cs); - - offset_select += select_width; + for (unsigned i = 0 ; i < selector->GetNumBranches() ; ++i) { + + SigSig action(sig_out_val, sig_data_values.extract(offset_data, data_width)); offset_data += data_width; + + for (unsigned j = 0 ; j < selector->GetNumConditions(i) ; ++j) { + Array left_bound, right_bound ; + selector->GetCondition(i, j, &left_bound, &right_bound); + + SigSpec sel_left = sig_select_values.extract(offset_select, select_width); + offset_select += select_width; + + if (right_bound.Size()) { + SigSpec sel_right = sig_select_values.extract(offset_select, select_width); + offset_select += select_width; + + log_assert(sel_right.is_fully_const() && sel_right.is_fully_def()); + log_assert(sel_left.is_fully_const() && sel_right.is_fully_def()); + + int32_t left = sel_left.as_int(); + int32_t right = sel_right.as_int(); + int width = sel_left.size(); + + for (int32_t i = right; icompare.push_back(RTLIL::Const(i,width)); + cs->actions.push_back(action); + sw->cases.push_back(cs); + } + } + + RTLIL::CaseRule *cs = new RTLIL::CaseRule; + cs->compare.push_back(sel_left); + cs->actions.push_back(action); + sw->cases.push_back(cs); + } } RTLIL::CaseRule *cs_default = new RTLIL::CaseRule; cs_default->actions.push_back(SigSig(sig_out_val, sig_data_default)); @@ -1439,6 +1465,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma import_attributes(wire->attributes, net, nl); break; } + import_attributes(wire->attributes, netbus, nl); RTLIL::Const initval = Const(State::Sx, GetSize(wire)); bool initval_valid = false; @@ -1984,6 +2011,28 @@ VerificClocking::VerificClocking(VerificImporter *importer, Net *net, bool sva_a Instance *inst = net->Driver(); + // Detect condition expression in sva_at_only mode + if (sva_at_only) + do { + Instance *inst_mux = net->Driver(); + if (inst_mux->Type() != PRIM_MUX) + break; + + bool pwr1 = inst_mux->GetInput1()->IsPwr(); + bool pwr2 = inst_mux->GetInput2()->IsPwr(); + + if (!pwr1 && !pwr2) + break; + + Net *sva_net = pwr1 ? inst_mux->GetInput2() : inst_mux->GetInput1(); + if (!verific_is_sva_net(importer, sva_net)) + break; + + inst = sva_net->Driver(); + cond_net = inst_mux->GetControl(); + cond_pol = pwr1; + } while (0); + if (inst != nullptr && inst->Type() == PRIM_SVA_AT) { net = inst->GetInput1(); @@ -2419,6 +2468,7 @@ std::string verific_import(Design *design, const std::mapAddAtt(new Att(" \\top", NULL)); nl_todo.emplace(nl->CellBaseName(), nl); + cell_name = nl->Owner()->Name(); } + if (top.empty()) cell_name = top; delete netlists; @@ -2446,7 +2498,7 @@ std::string verific_import(Design *design, const std::mapfirst) == 0) { VerificImporter importer(false, false, false, false, false, false, false); nl_done[it->first] = it->second; - importer.import_netlist(design, nl, nl_todo, nl->Owner()->Name() == top); + importer.import_netlist(design, nl, nl_todo, nl->Owner()->Name() == cell_name); } nl_todo.erase(it); } diff --git a/yosys/frontends/verific/verific.h b/yosys/frontends/verific/verific.h deleted file mode 100644 index 44485751c7e..00000000000 --- a/yosys/frontends/verific/verific.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 std::string 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; - bool cond_pol = true; - - 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); - RTLIL::Cell *addAldff(IdString name, RTLIL::SigSpec sig_aload, RTLIL::SigSpec sig_adata, 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, mode_fullinit; - - VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover, bool mode_fullinit); - - RTLIL::SigBit net_map_at(Verific::Net *net); - - RTLIL::IdString new_verific_id(Verific::DesignObj *obj); - void import_attributes(dict &attributes, Verific::DesignObj *obj, Verific::Netlist *nl = nullptr); - - 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 operatorInportCase(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::map &nl_todo, bool norename = false); -}; - -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 986a9864326..00000000000 --- a/yosys/frontends/verific/verificsva.cc +++ /dev/null @@ -1,1877 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 -// nexttime basic_property -// nexttime[N] 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], State::S0); - } 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) - { - std::string msg; - if (inst->Type() == PRIM_SVA_MATCH_ITEM_TRIGGER || inst->Type() == PRIM_SVA_MATCH_ITEM_ASSIGN) - { - msg = "SVA sequences with local variable assignments are currently not supported.\n"; - } - - parser_error(stringf("%sVerific SVA primitive %s (%s) is currently unsupported in this context", - msg.c_str(), 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_NEXTTIME || inst->Type() == PRIM_SVA_S_NEXTTIME) - { - 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); - log_assert(sva_low == sva_high); - - int node = start_node; - - for (int i = 0; i < sva_low; i++) { - int next_node = fsm.createNode(); - fsm.createEdge(node, next_node); - node = next_node; - } - - return parse_sequence(fsm, node, inst->GetInput()); - } - - 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); - if (!clocking.cond_pol) - trig = module->Not(NEW_ID, trig); - } 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 (!clocking.cond_pol) - trig = module->Not(NEW_ID, trig); - } - - 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 || - consequent_inst->Type() == PRIM_SVA_ALWAYS || consequent_inst->Type() == PRIM_SVA_S_ALWAYS)) - { - bool until_with = consequent_inst->Type() == PRIM_SVA_UNTIL_WITH || consequent_inst->Type() == PRIM_SVA_S_UNTIL_WITH; - - Net *until_net = nullptr; - if (consequent_inst->Type() == PRIM_SVA_ALWAYS || consequent_inst->Type() == PRIM_SVA_S_ALWAYS) - { - consequent_net = consequent_inst->GetInput(); - consequent_inst = net_to_ast_driver(consequent_net); - } - else - { - until_net = consequent_inst->GetInput2(); - consequent_net = consequent_inst->GetInput1(); - consequent_inst = net_to_ast_driver(consequent_net); - } - - SigBit until_sig = until_net ? parse_expression(until_net) : RTLIL::S0; - 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); - } - - // accept in disable case - - if (clocking.disable_sig != State::S0) - sig_a_q = module->Or(NEW_ID, sig_a_q, clocking.disable_sig); - - // 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); - - if (c) 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); - - if (c) 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 aadbcdcdd51..00000000000 --- 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 2c923f0b74a..00000000000 --- 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) -Wall -Werror -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 frontends/verilog/verilog_parser.tab.cc - $(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 a4dfbc7ec7c..00000000000 --- a/yosys/frontends/verilog/const2ast.cc +++ /dev/null @@ -1,248 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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' || *str == '?') - digits.push_back(0xf1); - 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) ? State::S1 : State::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 - data.push_back((*it & bitmask) ? State::S1 : State::S0); - } - } - } - - int len = GetSize(data); - RTLIL::State msb = data.empty() ? State::S0 : data.back(); - - if (len_in_bits < 0) { - if (len < 32) - data.resize(32, msb == State::S0 || msb == State::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] == State::S1) - break; - if (msb == State::S0 || msb == State::S1) { - len += 1; - data.resize(len_in_bits, State::S0); - } else { - len += 2; - data.resize(len_in_bits, msb); - } - - if (len_in_bits == 0) - log_file_error(current_filename, get_line_num(), "Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n"); - - 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) ? State::S1 : State::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() == State::S1) - data.push_back(State::S0); - return AstNode::mkconst_bits(data, true); - } - - // unsized constant - if (str == endptr) - len_in_bits = -1; - - // The "'[sS]?[bodhBODH]" syntax - if (*endptr == '\'') - { - std::vector data; - bool is_signed = false; - bool is_unsized = len_in_bits < 0; - if (*(endptr+1) == 's' || *(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() == State::S1) - data.push_back(State::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 e33b0a2c326..00000000000 --- a/yosys/frontends/verilog/preproc.cc +++ /dev/null @@ -1,1000 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 verilog_lexer.l). - * - */ - -#include "preproc.h" -#include "verilog_frontend.h" -#include "kernel/log.h" -#include -#include -#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 == '\\') - { - while ((ch = next_char()) != 0) { - if (ch < 33 || ch > 126) { - return_char(ch); - break; - } - token += 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; -} - -struct macro_arg_t -{ - macro_arg_t(const std::string &name_, const char *default_value_) - : name(name_), - has_default(default_value_ != nullptr), - default_value(default_value_ ? default_value_ : "") - {} - - std::string name; - bool has_default; - std::string default_value; -}; - -static bool all_white(const std::string &str) -{ - for (char c : str) - if (!isspace(c)) - return false; - return true; -} - -struct arg_map_t -{ - arg_map_t() - {} - - void add_arg(const std::string &name, const char *default_value) - { - if (find(name)) { - log_error("Duplicate macro arguments with name `%s'.\n", name.c_str()); - } - - name_to_pos[name] = args.size(); - args.push_back(macro_arg_t(name, default_value)); - } - - // Find an argument by name; return nullptr if it doesn't exist. If pos is not null, write - // the argument's position to it on success. - const macro_arg_t *find(const std::string &name, int *pos = nullptr) const - { - auto it = name_to_pos.find(name); - if (it == name_to_pos.end()) - return nullptr; - - if (pos) *pos = it->second; - return &args[it->second]; - } - - // Construct the name for the local macro definition we use for the given argument - // (something like macro_foobar_arg2). This doesn't include the leading backtick. - static std::string str_token(const std::string ¯o_name, int pos) - { - return stringf("macro_%s_arg%d", macro_name.c_str(), pos); - } - - // Return definitions for the macro arguments (so that substituting in the macro body and - // then performing macro expansion will do argument substitution properly). - std::vector> - get_vals(const std::string ¯o_name, const std::vector &arg_vals) const - { - std::vector> ret; - for (int i = 0; i < GetSize(args); ++ i) { - // The SystemVerilog rules are: - // - // - If the call site specifies an argument and it's not whitespace, use - // it. - // - // - Otherwise, if the argument has a default value, use it. - // - // - Otherwise, if the call site specified whitespace, use that. - // - // - Otherwise, error. - const std::string *dflt = nullptr; - if (args[i].has_default) - dflt = &args[i].default_value; - - const std::string *given = nullptr; - if (i < GetSize(arg_vals)) - given = &arg_vals[i]; - - const std::string *val = nullptr; - if (given && (! (dflt && all_white(*given)))) - val = given; - else if (dflt) - val = dflt; - else if (given) - val = given; - else - log_error("Cannot expand macro `%s by giving only %d argument%s " - "(argument %d has no default).\n", - macro_name.c_str(), GetSize(arg_vals), - (GetSize(arg_vals) == 1 ? "" : "s"), i + 1); - - assert(val); - ret.push_back(std::make_pair(str_token(macro_name, i), * val)); - } - return ret; - } - - - std::vector args; - std::map name_to_pos; -}; - -struct define_body_t -{ - define_body_t(const std::string &body, const arg_map_t *args = nullptr) - : body(body), - has_args(args != nullptr), - args(args ? *args : arg_map_t()) - {} - - std::string body; - bool has_args; - arg_map_t args; -}; - -define_map_t::define_map_t() -{ - add("YOSYS", "1"); -} - -// We must define this destructor here (rather than relying on the default), because we need to -// define it somewhere we've got a complete definition of define_body_t. -define_map_t::~define_map_t() -{} - -void -define_map_t::add(const std::string &name, const std::string &txt, const arg_map_t *args) -{ - defines[name] = std::unique_ptr(new define_body_t(txt, args)); -} - -void define_map_t::add(const std::string &name, const define_body_t &body) -{ - defines[name] = std::unique_ptr(new define_body_t(body)); -} - -void define_map_t::merge(const define_map_t &map) -{ - for (const auto &pr : map.defines) { - // These contortions are so that we take a copy of each definition body in - // map.defines. - defines[pr.first] = std::unique_ptr(new define_body_t(*pr.second)); - } -} - -const define_body_t *define_map_t::find(const std::string &name) const -{ - auto it = defines.find(name); - return (it == defines.end()) ? nullptr : it->second.get(); -} - -void define_map_t::erase(const std::string &name) -{ - defines.erase(name); -} - -void define_map_t::clear() -{ - defines.clear(); -} - -void define_map_t::log() const -{ - for (auto &it : defines) { - const std::string &name = it.first; - const define_body_t &body = *it.second; - Yosys::log("`define %s%s %s\n", - name.c_str(), body.has_args ? "()" : "", body.body.c_str()); - } -} - -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"); -} - -// Read tokens to get one argument (either a macro argument at a callsite or a default argument in a -// macro definition). Writes the argument to dest. Returns true if we finished with ')' (the end of -// the argument list); false if we finished with ','. -static bool read_argument(std::string &dest) -{ - skip_spaces(); - std::vector openers; - for (;;) { - std::string tok = next_token(true); - if (tok == ")") { - if (openers.empty()) { - while (dest.size() && (dest.back() == ' ' || dest.back() == '\t')) - dest = dest.substr(0, dest.size() - 1); - return true; - } - if (openers.back() != '(') - log_error("Mismatched brackets in macro argument: %c and %c.\n", - openers.back(), tok[0]); - - openers.pop_back(); - dest += tok; - continue; - } - if (tok == "]") { - char opener = openers.empty() ? '(' : openers.back(); - if (opener != '[') - log_error("Mismatched brackets in macro argument: %c and %c.\n", - opener, tok[0]); - - openers.pop_back(); - dest += tok; - continue; - } - if (tok == "}") { - char opener = openers.empty() ? '(' : openers.back(); - if (opener != '{') - log_error("Mismatched brackets in macro argument: %c and %c.\n", - opener, tok[0]); - - openers.pop_back(); - dest += tok; - continue; - } - - if (tok == "," && openers.empty()) { - return false; - } - - if (tok == "(" || tok == "[" || tok == "{") - openers.push_back(tok[0]); - - dest += tok; - } -} - -using macro_arg_stack_t = std::stack>; - -static void restore_macro_arg(define_map_t &defines, macro_arg_stack_t ¯o_arg_stack) -{ - log_assert(!macro_arg_stack.empty()); - auto &overwritten_arg = macro_arg_stack.top(); - defines.add(overwritten_arg.first, overwritten_arg.second); - macro_arg_stack.pop(); -} - -static bool try_expand_macro(define_map_t &defines, macro_arg_stack_t ¯o_arg_stack, 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, macro_arg_stack, ntok)) { - literal += ntok; - } - } - return false; // error - unmatched `" - } - - if (tok == "``") { - // Swallow `` in macro expansion - return true; - } - - if (tok.size() <= 1 || tok[0] != '`') - return false; - - // This token looks like a macro name (`foo). - std::string macro_name = tok.substr(1); - const define_body_t *body = defines.find(tok.substr(1)); - - if (! body) { - // Apparently not a name we know. - return false; - } - - std::string name = tok.substr(1); - std::string skipped_spaces = skip_spaces(); - tok = next_token(false); - if (body->has_args) { - if (tok != "(") { - if (tok.size() == 1 && iscntrl(tok[0])) { - char buf[5]; - snprintf(buf, sizeof(buf), "\\x%02x", tok[0]); - tok = buf; - } - log_error("Expected to find '(' to begin macro arguments for '%s', but instead found '%s'\n", - name.c_str(), tok.c_str()); - } - std::vector args; - bool done = false; - while (!done) { - std::string arg; - done = read_argument(arg); - args.push_back(arg); - } - for (const auto &pr : body->args.get_vals(name, args)) { - if (const define_body_t *existing = defines.find(pr.first)) { - macro_arg_stack.push({pr.first, *existing}); - insert_input("`__restore_macro_arg "); - } - defines.add(pr.first, pr.second); - } - } else { - insert_input(tok); - insert_input(skipped_spaces); - } - insert_input(body->body); - return true; -} - -// Read the arguments for a `define preprocessor directive with formal arguments. This is called -// just after reading the token containing "(". Returns the number of newlines to emit afterwards to -// keep line numbers in sync, together with the map from argument name to data (pos and default -// value). -static std::pair -read_define_args() -{ - // Each argument looks like one of the following: - // - // identifier - // identifier = default_text - // identifier = - // - // The first example is an argument with no default value. The second is an argument whose - // default value is default_text. The third is an argument with default value the empty - // string. - - int newline_count = 0; - arg_map_t args; - - // FSM state. - // - // 0: At start of identifier - // 1: After identifier (stored in arg_name) - // 2: After closing paren - int state = 0; - - std::string arg_name, default_val; - - skip_spaces(); - for (;;) { - if (state == 2) - // We've read the closing paren. - break; - - std::string tok = next_token(); - - // Cope with escaped EOLs - if (tok == "\\") { - char ch = next_char(); - if (ch == '\n') { - // Eat the \, the \n and any trailing space and keep going. - skip_spaces(); - continue; - } else { - // There aren't any other situations where a backslash makes sense. - log_error("Backslash in macro arguments (not at end of line).\n"); - } - } - - switch (state) { - case 0: - // At start of argument. If the token is ')', we've presumably just seen - // something like "`define foo() ...". Set state to 2 to finish. Otherwise, - // the token should be a valid simple identifier, but we'll allow anything - // here. - if (tok == ")") { - state = 2; - } else { - arg_name = tok; - state = 1; - } - skip_spaces(); - break; - - case 1: - // After argument. The token should either be an equals sign or a comma or - // closing paren. - if (tok == "=") { - std::string default_val; - //Read an argument into default_val and set state to 2 if we're at - // the end; 0 if we hit a comma. - state = read_argument(default_val) ? 2 : 0; - args.add_arg(arg_name, default_val.c_str()); - skip_spaces(); - break; - } - if (tok == ",") { - // Take the identifier as an argument with no default value. - args.add_arg(arg_name, nullptr); - state = 0; - skip_spaces(); - break; - } - if (tok == ")") { - // As with comma, but set state to 2 (end of args) - args.add_arg(arg_name, nullptr); - state = 2; - skip_spaces(); - break; - } - log_error("Trailing contents after identifier in macro argument `%s': " - "expected '=', ',' or ')'.\n", - arg_name.c_str()); - - default: - // The only FSM states are 0-2 and we dealt with 2 at the start of the loop. - log_assert(false); - } - } - - return std::make_pair(newline_count, args); -} - -// Read a `define preprocessor directive. This is called just after reading the token containing -// "`define". -static void -read_define(const std::string &filename, - define_map_t &defines_map, - define_map_t &global_defines_cache) -{ - std::string name, value; - arg_map_t args; - - skip_spaces(); - name = next_token(true); - - bool here_doc_mode = false; - int newline_count = 0; - - // The FSM state starts at 0. If it sees space (or enters here_doc_mode), it assumes this is - // a macro without formal arguments and jumps to state 1. - // - // In state 0, if it sees an opening parenthesis, it assumes this is a macro with formal - // arguments. It reads the arguments with read_define_args() and then jumps to state 2. - // - // In states 1 or 2, the FSM reads tokens to the end of line (or end of here_doc): this is - // the body of the macro definition. - int state = 0; - - if (skip_spaces() != "") - state = 1; - - for (;;) { - std::string tok = next_token(); - if (tok.empty()) - break; - - // printf("define-tok: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE"); - - if (tok == "\"\"\"") { - here_doc_mode = !here_doc_mode; - continue; - } - - if (state == 0 && tok == "(") { - auto pr = read_define_args(); - newline_count += pr.first; - args = pr.second; - - state = 2; - continue; - } - - // This token isn't an opening parenthesis immediately following the macro name, so - // it's presumably at or after the start of the macro body. If state isn't already 2 - // (which would mean we'd parsed an argument list), set it to 1. - if (state == 0) { - state = 1; - } - - if (tok == "\n") { - if (here_doc_mode) { - value += " "; - newline_count++; - } else { - return_char('\n'); - break; - } - continue; - } - - if (tok == "\\") { - char ch = next_char(); - if (ch == '\n') { - value += " "; - newline_count++; - } else { - value += std::string("\\"); - return_char(ch); - } - continue; - } - - // Is this token the name of a macro argument? If so, replace it with a magic symbol - // that we'll replace with the argument value. - int arg_pos; - if (args.find(tok, &arg_pos)) { - value += '`' + args.str_token(name, arg_pos); - continue; - } - - // This token is nothing special. Insert it verbatim into the macro body. - value += tok; - } - - // Append some newlines so that we don't mess up line counts in error messages. - while (newline_count-- > 0) - return_char('\n'); - - if (strchr("abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789", name[0])) { - // printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str()); - defines_map.add(name, value, (state == 2) ? &args : nullptr); - global_defines_cache.add(name, value, (state == 2) ? &args : nullptr); - } else { - log_file_error(filename, 0, "Invalid name for macro definition: >>%s<<.\n", name.c_str()); - } -} - -std::string -frontend_verilog_preproc(std::istream &f, - std::string filename, - const define_map_t &pre_defines, - define_map_t &global_defines_cache, - const std::list &include_dirs) -{ - define_map_t defines; - defines.merge(pre_defines); - defines.merge(global_defines_cache); - - macro_arg_stack_t macro_arg_stack; - std::vector filename_stack; - // We are inside pass_level levels of satisfied ifdefs, and then within - // fail_level levels of unsatisfied ifdefs. The unsatisfied ones are - // always within satisfied ones — even if some condition within is true, - // the parent condition failing renders it moot. - int ifdef_fail_level = 0; - int ifdef_pass_level = 0; - // For the outermost unsatisfied ifdef, true iff that ifdef already - // had a satisfied branch, and further elsif/else branches should be - // considered unsatisfied even if the condition is true. - // Meaningless if ifdef_fail_level == 0. - bool ifdef_already_satisfied = false; - - output_code.clear(); - input_buffer.clear(); - input_buffer_charp = 0; - - input_file(f, filename); - - 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--; - else if (ifdef_pass_level > 0) - ifdef_pass_level--; - else - log_error("Found %s outside of macro conditional branch!\n", tok.c_str()); - continue; - } - - if (tok == "`else") { - if (ifdef_fail_level == 0) { - if (ifdef_pass_level == 0) - log_error("Found %s outside of macro conditional branch!\n", tok.c_str()); - ifdef_pass_level--; - ifdef_fail_level = 1; - ifdef_already_satisfied = true; - } else if (ifdef_fail_level == 1 && !ifdef_already_satisfied) { - ifdef_fail_level = 0; - ifdef_pass_level++; - ifdef_already_satisfied = true; - } - continue; - } - - if (tok == "`elsif") { - skip_spaces(); - std::string name = next_token(true); - if (ifdef_fail_level == 0) { - if (ifdef_pass_level == 0) - log_error("Found %s outside of macro conditional branch!\n", tok.c_str()); - ifdef_pass_level--; - ifdef_fail_level = 1; - ifdef_already_satisfied = true; - } else if (ifdef_fail_level == 1 && !ifdef_already_satisfied && defines.find(name)) { - ifdef_fail_level = 0; - ifdef_pass_level++; - ifdef_already_satisfied = true; - } - continue; - } - - if (tok == "`ifdef") { - skip_spaces(); - std::string name = next_token(true); - if (ifdef_fail_level > 0 || !defines.find(name)) { - ifdef_fail_level++; - } else { - ifdef_pass_level++; - ifdef_already_satisfied = true; - } - if (ifdef_fail_level == 1) - ifdef_already_satisfied = false; - continue; - } - - if (tok == "`ifndef") { - skip_spaces(); - std::string name = next_token(true); - if (ifdef_fail_level > 0 || defines.find(name)) { - ifdef_fail_level++; - } else { - ifdef_pass_level++; - ifdef_already_satisfied = true; - } - if (ifdef_fail_level == 1) - ifdef_already_satisfied = false; - 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, macro_arg_stack, 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") { - read_define(filename, defines, global_defines_cache); - continue; - } - - if (tok == "`undef") { - std::string name; - skip_spaces(); - name = next_token(true); - // printf("undef: >>%s<<\n", name.c_str()); - defines.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") { - default_nettype_wire = true; - continue; - } - - if (tok == "`undefineall" && sv_mode) { - defines.clear(); - global_defines_cache.clear(); - continue; - } - - if (tok == "`__restore_macro_arg") { - restore_macro_arg(defines, macro_arg_stack); - continue; - } - - if (try_expand_macro(defines, macro_arg_stack, tok)) - continue; - - output_code.push_back(tok); - } - - if (ifdef_fail_level > 0 || ifdef_pass_level > 0) { - log_error("Unterminated preprocessor conditional!\n"); - } - - 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/preproc.h b/yosys/frontends/verilog/preproc.h deleted file mode 100644 index 330855a92af..00000000000 --- a/yosys/frontends/verilog/preproc.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 preprocessor. - * - */ -#ifndef VERILOG_PREPROC_H -#define VERILOG_PREPROC_H - -#include "kernel/yosys.h" - -#include -#include -#include -#include - -YOSYS_NAMESPACE_BEGIN - -struct define_body_t; -struct arg_map_t; - -struct define_map_t -{ - define_map_t(); - ~ define_map_t(); - - // Add a definition, overwriting any existing definition for name. - void add(const std::string &name, const std::string &txt, const arg_map_t *args = nullptr); - void add(const std::string &name, const define_body_t &body); - - // Merge in another map of definitions (which take precedence - // over anything currently defined). - void merge(const define_map_t &map); - - // Find a definition by name. If no match, returns null. - const define_body_t *find(const std::string &name) const; - - // Erase a definition by name (no effect if not defined). - void erase(const std::string &name); - - // Clear any existing definitions - void clear(); - - // Print a list of definitions, using the log function - void log() const; - - std::map> defines; -}; - - -struct define_map_t; - -std::string -frontend_verilog_preproc(std::istream &f, - std::string filename, - const define_map_t &pre_defines, - define_map_t &global_defines_cache, - const std::list &include_dirs); - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/frontends/verilog/verilog_frontend.cc b/yosys/frontends/verilog/verilog_frontend.cc deleted file mode 100644 index 9b277c6b977..00000000000 --- a/yosys/frontends/verilog/verilog_frontend.cc +++ /dev/null @@ -1,678 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 "preproc.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->location.first_line, "Found DPI function %s.\n", node->str.c_str()); - for (auto child : node->children) - error_on_dpi_function(child); -} - -static void add_package_types(dict &user_types, std::vector &package_list) -{ - // prime the parser's user type lookup table with the package qualified names - // of typedefed names in the packages seen so far. - for (const auto &pkg : package_list) { - log_assert(pkg->type==AST::AST_PACKAGE); - for (const auto &node: pkg->children) { - if (node->type == AST::AST_TYPEDEF) { - std::string s = pkg->str + "::" + node->str.substr(1); - user_types[s] = node; - } - } - } -} - -struct VerilogFrontend : public Frontend { - VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } - void help() 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(" -nosynthesis\n"); - log(" don't add implicit -D SYNTHESIS\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, unless -nosynthesis is used.\n"); - log("In addition, read_verilog 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) 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; - bool flag_nosynthesis = false; - define_map_t 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 == "-nosynthesis") { - flag_nosynthesis = 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.add("BLACKBOX", ""); - 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.add(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.add(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; - } - - if (formal_mode || !flag_nosynthesis) - defines_map.add(formal_mode ? "FORMAL" : "SYNTHESIS", "1"); - - 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); - } - - // make package typedefs available to parser - add_package_types(pkg_user_types, design->verilog_packages); - - UserTypeMap global_types_map; - for (auto def : design->verilog_globals) { - if (def->type == AST::AST_TYPEDEF) { - global_types_map[def->str] = def; - } - } - - log_assert(user_type_stack.empty()); - // use previous global typedefs as bottom level of user type stack - user_type_stack.push_back(std::move(global_types_map)); - // add a new empty type map to allow overriding existing global definitions - user_type_stack.push_back(UserTypeMap()); - - 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; - - // only the previous and new global type maps remain - log_assert(user_type_stack.size() == 2); - user_type_stack.clear(); - - 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() 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*) 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() 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"); - log(" -reset\n"); - log(" clear list of defined preprocessor symbols\n"); - log("\n"); - log(" -list\n"); - log(" list currently defined preprocessor symbols\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) 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->add(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); - design->verilog_defines->add(name, value); - 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; - } - if (arg == "-reset") { - design->verilog_defines->clear(); - continue; - } - if (arg == "-list") { - design->verilog_defines->log(); - 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 8454e7999e7..00000000000 --- a/yosys/frontends/verilog/verilog_frontend.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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); - - // names of locally typedef'ed types in a stack - typedef std::map UserTypeMap; - extern std::vector user_type_stack; - - // names of package typedef'ed types - extern dict pkg_user_types; - - // 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; -} - -YOSYS_NAMESPACE_END - -// the usual bison/flex stuff -extern int frontend_verilog_yydebug; -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 958809319ef..00000000000 --- a/yosys/frontends/verilog/verilog_lexer.l +++ /dev/null @@ -1,604 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 verilog_parser.y). - * - */ - -%{ - -#ifdef __clang__ -// bison generates code using the 'register' storage class specifier -#pragma clang diagnostic ignored "-Wdeprecated-register" -// flex generates weirdly-indented code -#pragma clang diagnostic ignored "-Wmisleading-indentation" -#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; - -#define YYSTYPE FRONTEND_VERILOG_YYSTYPE -#define YYLTYPE FRONTEND_VERILOG_YYLTYPE - -YOSYS_NAMESPACE_BEGIN -namespace VERILOG_FRONTEND { - std::vector fn_stack; - std::vector ln_stack; - YYLTYPE real_location; - YYLTYPE old_location; -} -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()); \ - yylval->string = new std::string(std::string("\\") + yytext); \ - return TOK_ID; - -#define NON_KEYWORD() \ - 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) - -#define YY_USER_ACTION \ - old_location = real_location; \ - real_location.first_line = real_location.last_line; \ - real_location.first_column = real_location.last_column; \ - for(int i = 0; yytext[i] != '\0'; ++i){ \ - if(yytext[i] == '\n') { \ - real_location.last_line++; \ - real_location.last_column = 1; \ - } \ - else { \ - real_location.last_column++; \ - } \ - } \ - (*yylloc) = real_location; - -#define YY_BREAK \ - (*yylloc) = old_location; \ - break; - -#undef YY_BUF_SIZE -#define YY_BUF_SIZE 65536 - -extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); - -static bool isUserType(std::string &s) -{ - // check current scope then outer scopes for a name - for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { - if (it->count(s) > 0) { - return true; - } - } - return false; -} - -%} - -%option yylineno -%option noyywrap -%option nounput -%option bison-locations -%option bison-bridge -%option prefix="frontend_verilog_yy" - -%x COMMENT -%x STRING -%x SYNOPSYS_TRANSLATE_OFF -%x SYNOPSYS_FLAGS -%x IMPORT_DPI -%x BASED_CONST - -UNSIGNED_NUMBER [0-9][0-9_]* -FIXED_POINT_NUMBER_DEC [0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? -FIXED_POINT_NUMBER_NO_DEC [0-9][0-9_]*[eE][-+]?[0-9_]+ -TIME_SCALE_SUFFIX [munpf]?s - -%% - // Initialise comment_caller to something to avoid a "maybe undefined" - // warning from GCC. - int comment_caller = INITIAL; - -"`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); - yylloc->first_line = yylloc->last_line = 0; - real_location.first_line = real_location.last_line = 0; -} - -"`file_pop"[^\n]*\n { - current_filename = fn_stack.back(); - fn_stack.pop_back(); - frontend_verilog_yyset_lineno(ln_stack.back()); - yylloc->first_line = yylloc->last_line = ln_stack.back(); - real_location.first_line = real_location.last_line = 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)); - yylloc->first_line = yylloc->last_line = atoi(p); - real_location.first_line = real_location.last_line = 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_UNIQUE0); } -"priority" { SV_KEYWORD(TOK_PRIORITY); } - -"always_comb" { SV_KEYWORD(TOK_ALWAYS_COMB); } -"always_ff" { SV_KEYWORD(TOK_ALWAYS_FF); } -"always_latch" { SV_KEYWORD(TOK_ALWAYS_LATCH); } - - /* 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; - 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); } -"bind" { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); } -"final" { SV_KEYWORD(TOK_FINAL); } -"logic" { SV_KEYWORD(TOK_LOGIC); } -"var" { SV_KEYWORD(TOK_VAR); } -"bit" { SV_KEYWORD(TOK_LOGIC); } -"int" { SV_KEYWORD(TOK_INT); } -"byte" { SV_KEYWORD(TOK_BYTE); } -"shortint" { SV_KEYWORD(TOK_SHORTINT); } -"longint" { SV_KEYWORD(TOK_LONGINT); } - -"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; } -"tri" { return TOK_WIRE; } -"wor" { return TOK_WOR; } -"trior" { return TOK_WOR; } -"wand" { return TOK_WAND; } -"triand" { return TOK_WAND; } -"reg" { return TOK_REG; } -"integer" { return TOK_INTEGER; } -"signed" { return TOK_SIGNED; } -"unsigned" { SV_KEYWORD(TOK_UNSIGNED); } -"genvar" { return TOK_GENVAR; } -"real" { return TOK_REAL; } - -"enum" { SV_KEYWORD(TOK_ENUM); } -"typedef" { SV_KEYWORD(TOK_TYPEDEF); } -"struct" { SV_KEYWORD(TOK_STRUCT); } -"union" { SV_KEYWORD(TOK_UNION); } -"packed" { SV_KEYWORD(TOK_PACKED); } - -{UNSIGNED_NUMBER} { - yylval->string = new std::string(yytext); - return TOK_CONSTVAL; -} - -\'[01zxZX] { - yylval->string = new std::string(yytext); - return TOK_UNBASED_UNSIZED_CONSTVAL; -} - -\'[sS]?[bodhBODH] { - BEGIN(BASED_CONST); - yylval->string = new std::string(yytext); - return TOK_BASE; -} - -[0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* { - BEGIN(0); - yylval->string = new std::string(yytext); - return TOK_BASED_CONSTVAL; -} - -{FIXED_POINT_NUMBER_DEC} { - yylval->string = new std::string(yytext); - return TOK_REALVAL; -} - -{FIXED_POINT_NUMBER_NO_DEC} { - yylval->string = new std::string(yytext); - return TOK_REALVAL; -} - -\" { BEGIN(STRING); } -\\. { yymore(); real_location = old_location; } -\" { - 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; - yylval->string = new std::string(yystr, j); - free(yystr); - return TOK_STRING; -} -. { yymore(); real_location = old_location; } - -and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { - 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) { - yylval->string = new std::string(yytext); - return TOK_ID; -} - -"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { - if (!specify_mode) REJECT; - yylval->string = new std::string(yytext); - return TOK_ID; -} - -"$"(info|warning|error|fatal) { - 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_]*::[a-zA-Z_$][a-zA-Z0-9_$]* { - // package qualifier - auto s = std::string("\\") + yytext; - if (pkg_user_types.count(s) > 0) { - // package qualified typedefed name - yylval->string = new std::string(s); - return TOK_PKG_USER_TYPE; - } - else { - // backup before :: just return first part - size_t len = strchr(yytext, ':') - yytext; - yyless(len); - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; - } -} - -[a-zA-Z_$][a-zA-Z0-9_$]* { - auto s = std::string("\\") + yytext; - if (isUserType(s)) { - // previously typedefed name - yylval->string = new std::string(s); - return TOK_USER_TYPE; - } - else { - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; - } -} - -[a-zA-Z_$][a-zA-Z0-9_$\.]* { - 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( - "Encountered `translate_off' comment! Such legacy hot " - "comments are supported by Yosys, but are not part of " - "any formal language specification. Using a portable " - "and standards-compliant construct such as `ifdef is " - "recommended!\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( - "Encountered `full_case' comment! Such legacy hot " - "comments are supported by Yosys, but are not part of " - "any formal language specification. Using the Verilog " - "`full_case' attribute or the SystemVerilog `unique' " - "or `unique0' keywords is recommended!\n" - ); - printed_warning = true; - } - return TOK_SYNOPSYS_FULL_CASE; -} -parallel_case { - static bool printed_warning = false; - if (!printed_warning) { - log_warning( - "Encountered `parallel_case' comment! Such legacy hot " - "comments are supported by Yosys, but are not part of " - "any formal language specification. Using the Verilog " - "`parallel_case' attribute or the SystemVerilog " - "`unique' or `priority' keywords is recommended!\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_$]* { - 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]+ { - 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 OP_CAST; } - -"::" { return TOK_PACKAGESEP; } -"++" { return TOK_INCREMENT; } -"--" { return TOK_DECREMENT; } - -"+:" { return TOK_POS_INDEXED; } -"-:" { return TOK_NEG_INDEXED; } - -".*" { return TOK_WILDCARD_CONNECT; } - -"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); } -"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); } -"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); } -"-=" { SV_KEYWORD(TOK_SUB_ASSIGN); } -"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); } -"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); } -"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); } -"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); } -"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); } -">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); } -"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); } -">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); } - -[-+]?[=*]> { - if (!specify_mode) REJECT; - yylval->string = new std::string(yytext); - return TOK_SPECIFY_OPER; -} - -"&&&" { - if (!specify_mode) return TOK_IGNORED_SPECIFY_AND; - return TOK_SPECIFY_AND; -} - -{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } -{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } -{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } - -"/*" { comment_caller=YY_START; BEGIN(COMMENT); } -. /* ignore comment body */ -\n /* ignore comment body */ -"*/" { BEGIN(comment_caller); } - -[ \t\r\n] /* ignore whitespaces */ -\\[\r\n] /* ignore continuation sequence */ -"//"[^\r\n]* /* ignore one-line comments */ - -. { return *yytext; } -<*>. { BEGIN(0); 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 87b50438a5f..00000000000 --- a/yosys/frontends/verilog/verilog_parser.y +++ /dev/null @@ -1,3486 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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. - * - */ - -%require "3.0" - -%{ -#include -#include -#include -#include "frontends/verilog/verilog_frontend.h" -#include "frontends/verilog/verilog_parser.tab.hh" -#include "kernel/log.h" - -#define YYLEX_PARAM &yylval, &yylloc - -USING_YOSYS_NAMESPACE -using namespace AST; -using namespace VERILOG_FRONTEND; - -YOSYS_NAMESPACE_BEGIN -namespace VERILOG_FRONTEND { - int port_counter; - dict port_stubs; - dict *attr_list, default_attr_list; - std::stack *> attr_list_stack; - dict *albuf; - std::vector user_type_stack; - dict pkg_user_types; - 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 - -#define SET_AST_NODE_LOC(WHICH, BEGIN, END) \ - do { (WHICH)->location.first_line = (BEGIN).first_line; \ - (WHICH)->location.first_column = (BEGIN).first_column; \ - (WHICH)->location.last_line = (END).last_line; \ - (WHICH)->location.last_column = (END).last_column; } while(0) - -#define SET_RULE_LOC(LHS, BEGIN, END) \ - do { (LHS).first_line = (BEGIN).first_line; \ - (LHS).first_column = (BEGIN).first_column; \ - (LHS).last_line = (END).last_line; \ - (LHS).last_column = (END).last_column; } while(0) - -int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); - -static void append_attr(AstNode *ast, dict *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, dict *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(dict *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; -}; - -static void addWiretypeNode(std::string *name, AstNode *node) -{ - log_assert(node); - node->is_custom_type = true; - node->children.push_back(new AstNode(AST_WIRETYPE)); - node->children.back()->str = *name; - delete name; -} - -static void addTypedefNode(std::string *name, AstNode *node) -{ - log_assert(node); - auto *tnode = new AstNode(AST_TYPEDEF, node); - tnode->str = *name; - auto &user_types = user_type_stack.back(); - user_types[*name] = tnode; - if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) { - // typedef inside a package so we need the qualified name - auto qname = current_ast_mod->str + "::" + (*name).substr(1); - pkg_user_types[qname] = tnode; - } - delete name; - ast_stack.back()->children.push_back(tnode); -} - -static void enterTypeScope() -{ - user_type_stack.push_back(UserTypeMap()); -} - -static void exitTypeScope() -{ - user_type_stack.pop_back(); -} - -static bool isInLocalScope(const std::string *name) -{ - // tests if a name was declared in the current block scope - auto &user_types = user_type_stack.back(); - return (user_types.count(*name) > 0); -} - -static AstNode *getTypeDefinitionNode(std::string type_name) -{ - // check package types - if (type_name.find("::") != std::string::npos && pkg_user_types.count(type_name) > 0) { - auto typedef_node = pkg_user_types[type_name]; - log_assert(typedef_node->type == AST_TYPEDEF); - return typedef_node->children[0]; - } - - // check current scope then outer scopes for a name - for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { - if (it->count(type_name) > 0) { - // return the definition nodes from the typedef statement - auto typedef_node = (*it)[type_name]; - log_assert(typedef_node->type == AST_TYPEDEF); - return typedef_node->children[0]; - } - } - - // The lexer recognized the name as a TOK_USER_TYPE, but now we can't find it anymore? - log_error("typedef for user type `%s' not found", type_name.c_str()); -} - -static AstNode *copyTypeDefinition(std::string type_name) -{ - // return a copy of the template from a typedef definition - auto typedef_node = getTypeDefinitionNode(type_name); - return typedef_node->clone(); -} - -static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true) -{ - auto range = new AstNode(AST_RANGE); - range->children.push_back(AstNode::mkconst_int(msb, true)); - range->children.push_back(AstNode::mkconst_int(lsb, true)); - range->is_signed = isSigned; - return range; -} - -static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true) -{ - auto range = makeRange(msb, lsb, isSigned); - parent->children.push_back(range); -} - -static AstNode *checkRange(AstNode *type_node, AstNode *range_node) -{ - if (type_node->range_left >= 0 && type_node->range_right >= 0) { - // type already restricts the range - if (range_node) { - frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions."); - } - else { - range_node = makeRange(type_node->range_left, type_node->range_right, false); - } - } - if (range_node && range_node->children.size() != 2) { - frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [:], [+:], or [-:]"); - } - return range_node; -} - -static void rewriteRange(AstNode *rangeNode) -{ - if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { - // SV array size [n], rewrite as [0:n-1] - rangeNode->children.push_back(new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true))); - rangeNode->children[0] = AstNode::mkconst_int(0, false); - } -} - -static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) -{ - node->type = AST_MEMORY; - if (rangeNode->type == AST_MULTIRANGE) { - for (auto *itr : rangeNode->children) - rewriteRange(itr); - } else - rewriteRange(rangeNode); - node->children.push_back(rangeNode); -} - -static void checkLabelsMatch(const char *element, const std::string *before, const std::string *after) -{ - if (!before && after) - frontend_verilog_yyerror("%s missing where end label (%s) was given.", - element, after->c_str() + 1); - if (before && after && *before != *after) - frontend_verilog_yyerror("%s (%s) and end label (%s) don't match.", - element, before->c_str() + 1, after->c_str() + 1); -} - -// This transforms a loop like -// for (genvar i = 0; i < 10; i++) begin : blk -// to -// genvar _i; -// for (_i = 0; _i < 10; _i++) begin : blk -// localparam i = _i; -// where `_i` is actually some auto-generated name. -static void rewriteGenForDeclInit(AstNode *loop) -{ - // check if this generate for loop contains an inline declaration - log_assert(loop->type == AST_GENFOR); - AstNode *decl = loop->children[0]; - if (decl->type == AST_ASSIGN_EQ) - return; - log_assert(decl->type == AST_GENVAR); - log_assert(loop->children.size() == 5); - - // identify each component of the loop - AstNode *init = loop->children[1]; - AstNode *cond = loop->children[2]; - AstNode *incr = loop->children[3]; - AstNode *body = loop->children[4]; - log_assert(init->type == AST_ASSIGN_EQ); - log_assert(incr->type == AST_ASSIGN_EQ); - log_assert(body->type == AST_GENBLOCK); - - // create a unique name for the genvar - std::string old_str = decl->str; - std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str()); - - // rename and move the genvar declaration to the containing description - decl->str = new_str; - loop->children.erase(loop->children.begin()); - log_assert(current_ast_mod != nullptr); - current_ast_mod->children.push_back(decl); - - // create a new localparam with old name so that the items in the loop - // can simply use the old name and shadow it as necessary - AstNode *indirect = new AstNode(AST_LOCALPARAM); - indirect->str = old_str; - AstNode *ident = new AstNode(AST_IDENTIFIER); - ident->str = new_str; - indirect->children.push_back(ident); - - body->children.insert(body->children.begin(), indirect); - - // only perform the renaming for the initialization, guard, and - // incrementation to enable proper shadowing of the synthetic localparam - std::function substitute = [&](AstNode *node) { - if (node->type == AST_IDENTIFIER && node->str == old_str) - node->str = new_str; - for (AstNode *child : node->children) - substitute(child); - }; - substitute(init); - substitute(cond); - substitute(incr); -} - -%} - -%define api.prefix {frontend_verilog_yy} -%define api.pure - -/* 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; - YOSYS_NAMESPACE_PREFIX dict *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; - int integer; - YOSYS_NAMESPACE_PREFIX AST::AstNodeType ast_node_type; -} - -%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE -%token TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS -%token TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL -%token TOK_USER_TYPE TOK_PKG_USER_TYPE -%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 TOK_WILDCARD_CONNECT -%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_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH -%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 TOK_IGNORED_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_UNIQUE0 TOK_PRIORITY -%token TOK_STRUCT TOK_PACKED TOK_UNSIGNED TOK_INT TOK_BYTE TOK_SHORTINT TOK_LONGINT TOK_UNION -%token TOK_BIT_OR_ASSIGN TOK_BIT_AND_ASSIGN TOK_BIT_XOR_ASSIGN TOK_ADD_ASSIGN -%token TOK_SUB_ASSIGN TOK_DIV_ASSIGN TOK_MOD_ASSIGN TOK_MUL_ASSIGN -%token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN -%token TOK_BIND TOK_TIME_SCALE - -%type range range_or_multirange non_opt_range non_opt_multirange -%type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type -%type opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number -%type type_name -%type opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type -%type opt_property always_comb_or_latch always_or_always_ff -%type opt_signedness_default_signed opt_signedness_default_unsigned -%type integer_atom_type integer_vector_type -%type attr case_attr -%type struct_union -%type asgn_binop -%type genvar_identifier - -%type specify_target -%type specify_triple specify_opt_triple -%type specify_rise_fall -%type specify_if specify_condition -%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 -%precedence OP_CAST -%precedence UNARY_OPS - -%define parse.error verbose -%define parse.lac full - -%precedence FAKE_THEN -%precedence TOK_ELSE - -%debug -%locations - -%% - -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 | - typedef_decl design | - package design | - interface design | - bind_directive design | - %empty; - -attr: - { - if (attr_list != nullptr) - attr_list_stack.push(attr_list); - attr_list = new dict; - 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 { - SET_RULE_LOC(@$, @2, @$); - }| - %empty; - -defattr: - DEFATTR_BEGIN { - if (attr_list != nullptr) - attr_list_stack.push(attr_list); - attr_list = new dict; - 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->compare(0, 1, "\\") == 0) - *$1 += "::" + $3->substr(1); - else - *$1 += "::" + *$3; - delete $3; - $$ = $1; - } | - hierarchical_id '.' TOK_ID { - if ($3->compare(0, 1, "\\") == 0) - *$1 += "." + $3->substr(1); - else - *$1 += "." + *$3; - delete $3; - $$ = $1; - }; - -hierarchical_type_id: - TOK_USER_TYPE - | TOK_PKG_USER_TYPE // package qualified type name - | '(' TOK_USER_TYPE ')' { $$ = $2; } // non-standard grammar - ; - -module: - attr TOK_MODULE { - enterTypeScope(); - } 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 = *$4; - append_attr(mod, $1); - } module_para_opt module_args_opt ';' module_body TOK_ENDMODULE opt_label { - if (port_stubs.size() != 0) - frontend_verilog_yyerror("Missing details for module port `%s'.", - port_stubs.begin()->first.c_str()); - SET_AST_NODE_LOC(ast_stack.back(), @2, @$); - ast_stack.pop_back(); - log_assert(ast_stack.size() == 1); - checkLabelsMatch("Module name", $4, $11); - current_ast_mod = NULL; - delete $4; - delete $11; - exitTypeScope(); - }; - -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_type 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_type 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) { - if (ast_stack.back()->children.back()->is_input) { - AstNode *n = ast_stack.back()->children.back(); - if (n->attributes.count(ID::defaultvalue)) - delete n->attributes.at(ID::defaultvalue); - n->attributes[ID::defaultvalue] = $2; - } else { - AstNode *wire = new AstNode(AST_IDENTIFIER); - wire->str = ast_stack.back()->children.back()->str; - 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); - SET_AST_NODE_LOC(node, @1, @1); - } 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; - SET_AST_NODE_LOC(node, @4, @4); - node->port_id = ++port_counter; - AstNode *range = checkRange(node, $3); - if (range != NULL) - node->children.push_back(range); - 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 { - enterTypeScope(); - } 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 = *$4; - append_attr(mod, $1); - } ';' package_body TOK_ENDPACKAGE opt_label { - ast_stack.pop_back(); - checkLabelsMatch("Package name", $4, $9); - current_ast_mod = NULL; - delete $4; - delete $9; - exitTypeScope(); - }; - -package_body: - package_body package_body_stmt | %empty; - -package_body_stmt: - typedef_decl | localparam_decl | param_decl | task_func_decl; - -interface: - TOK_INTERFACE { - enterTypeScope(); - } 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 = *$3; - delete $3; - } 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; - exitTypeScope(); - }; - -interface_body: - interface_body interface_body_stmt | %empty; - -interface_body_stmt: - param_decl | localparam_decl | typedef_decl | defparam_decl | wire_decl | always_stmt | assign_stmt | - modport_stmt | bind_directive; - -bind_directive: - TOK_BIND { - AstNode *bnode = new AstNode(AST_BIND); - ast_stack.back()->children.push_back(bnode); - ast_stack.push_back(bnode); - } - bind_target { - // bind_target should have added at least one child - log_assert(ast_stack.back()->children.size() >= 1); - } - TOK_ID { - // The single_cell parser in cell_list_no_array uses astbuf1 as - // a sort of template for constructing cells. - astbuf1 = new AstNode(AST_CELL); - astbuf1->children.push_back(new AstNode(AST_CELLTYPE)); - astbuf1->children[0]->str = *$5; - delete $5; - } - cell_parameter_list_opt cell_list_no_array ';' { - // cell_list should have added at least one more child - log_assert(ast_stack.back()->children.size() >= 2); - delete astbuf1; - ast_stack.pop_back(); - }; - -// bind_target matches the target of the bind (everything before -// bind_instantiation in the IEEE 1800 spec). -// -// We can't use the BNF from the spec directly because it's ambiguous: -// something like "bind foo bar_i (.*)" can either be interpreted with "foo" as -// a module or interface identifier (matching bind_target_scope in the spec) or -// by considering foo as a degenerate hierarchical identifier with no '.' -// characters, followed by no bit select (which matches bind_target_instance in -// the spec). -// -// Instead, we resolve everything as an instance name and then deal with the -// ambiguity when converting to RTLIL / in the hierarchy pass. -bind_target: - bind_target_instance opt_bind_target_instance_list; - -// An optional list of target instances for a bind statement, introduced by a -// colon. -opt_bind_target_instance_list: - ':' bind_target_instance_list | - %empty; - -bind_target_instance_list: - bind_target_instance | - bind_target_instance_list ',' bind_target_instance; - -// A single target instance for a bind statement. The top of ast_stack will be -// the bind node where we should add it. -bind_target_instance: - hierarchical_id { - auto *node = new AstNode(AST_IDENTIFIER); - node->str = *$1; - delete $1; - ast_stack.back()->children.push_back(node); - }; - -mintypmax_expr: - expr { delete $1; } | - expr ':' expr ':' expr { delete $1; delete $3; delete $5; }; - -non_opt_delay: - '#' TOK_ID { delete $2; } | - '#' TOK_CONSTVAL { delete $2; } | - '#' TOK_REALVAL { delete $2; } | - // our `expr` doesn't have time_scale, so we need the parenthesized variant - '#' TOK_TIME_SCALE | - '#' '(' TOK_TIME_SCALE ')' | - '#' '(' mintypmax_expr ')' | - '#' '(' mintypmax_expr ',' mintypmax_expr ')' | - '#' '(' mintypmax_expr ',' mintypmax_expr ',' mintypmax_expr ')'; - -delay: - non_opt_delay | %empty; - -io_wire_type: - { astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; } - wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness - { $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); }; - -non_io_wire_type: - { astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; } - wire_type_const_rand wire_type_token wire_type_signedness - { $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); }; - -wire_type: - io_wire_type | - non_io_wire_type; - -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_signedness: - TOK_SIGNED { astbuf3->is_signed = true; } | - TOK_UNSIGNED { astbuf3->is_signed = false; } | - %empty; - -wire_type_const_rand: - TOK_RAND TOK_CONST { - current_wire_rand = true; - current_wire_const = true; - } | - TOK_CONST { - current_wire_const = true; - } | - TOK_RAND { - current_wire_rand = true; - } | - %empty; - -opt_wire_type_token: - wire_type_token | %empty; - -wire_type_token: - // nets - net_type { - } | - net_type logic_type { - } | - // regs - TOK_REG { - astbuf3->is_reg = true; - } | - TOK_VAR TOK_REG { - astbuf3->is_reg = true; - } | - // logics - TOK_VAR { - astbuf3->is_logic = true; - } | - TOK_VAR logic_type { - astbuf3->is_logic = true; - } | - logic_type { - astbuf3->is_logic = true; - } | - TOK_GENVAR { - astbuf3->type = AST_GENVAR; - astbuf3->is_reg = true; - astbuf3->is_signed = true; - astbuf3->range_left = 31; - astbuf3->range_right = 0; - }; - -net_type: - TOK_WOR { - astbuf3->is_wor = true; - } | - TOK_WAND { - astbuf3->is_wand = true; - } | - TOK_WIRE; - -logic_type: - TOK_LOGIC { - } | - integer_atom_type { - astbuf3->range_left = $1 - 1; - astbuf3->range_right = 0; - astbuf3->is_signed = true; - } | - hierarchical_type_id { - addWiretypeNode($1, astbuf3); - }; - -integer_atom_type: - TOK_INTEGER { $$ = 32; } | - TOK_INT { $$ = 32; } | - TOK_SHORTINT { $$ = 16; } | - TOK_LONGINT { $$ = 64; } | - TOK_BYTE { $$ = 8; } ; - -integer_vector_type: - TOK_LOGIC { $$ = TOK_LOGIC; } | - TOK_REG { $$ = TOK_REG; } ; - -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); - AstNode *expr = new AstNode(AST_SELFSZ, $2); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); - $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); - } | - '[' expr TOK_NEG_INDEXED expr ']' { - $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_SELFSZ, $2); - $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->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; }; - -module_body: - module_body module_body_stmt | - /* the following line makes the generate..endgenrate keywords optional */ - module_body gen_stmt | - module_body gen_block | - module_body ';' | - %empty; - -module_body_stmt: - task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | - enum_decl | struct_decl | bind_directive | - 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 func_return_type TOK_ID { - current_function_or_task = new AstNode(AST_FUNCTION); - current_function_or_task->str = *$5; - 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 = *$5; - outreg->is_signed = false; - outreg->is_reg = true; - if ($4 != NULL) { - outreg->children.push_back($4); - outreg->is_signed = $4->is_signed; - $4->is_signed = false; - outreg->is_custom_type = $4->type == AST_WIRETYPE; - } - current_function_or_task->children.push_back(outreg); - current_function_or_task_port_id = 1; - delete $5; - } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION { - current_function_or_task = NULL; - ast_stack.pop_back(); - }; - -func_return_type: - hierarchical_type_id { - $$ = new AstNode(AST_WIRETYPE); - $$->str = *$1; - delete $1; - } | - opt_type_vec opt_signedness_default_unsigned { - $$ = makeRange(0, 0, $2); - } | - opt_type_vec opt_signedness_default_unsigned non_opt_range { - $$ = $3; - $$->is_signed = $2; - } | - integer_atom_type opt_signedness_default_signed { - $$ = makeRange($1 - 1, 0, $2); - }; - -opt_type_vec: - %empty - | TOK_REG - | TOK_LOGIC - ; - -opt_signedness_default_signed: - %empty { $$ = true; } - | TOK_SIGNED { $$ = true; } - | TOK_UNSIGNED { $$ = false; } - ; -opt_signedness_default_unsigned: - %empty { $$ = false; } - | TOK_SIGNED { $$ = true; } - | TOK_UNSIGNED { $$ = false; } - ; - -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; - -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 { - bool prev_was_input = true; - bool prev_was_output = false; - if (albuf) { - prev_was_input = astbuf1->is_input; - prev_was_output = astbuf1->is_output; - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); - } - albuf = $1; - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); - if (!astbuf1->is_input && !astbuf1->is_output) { - if (!sv_mode) - frontend_verilog_yyerror("task/function argument direction missing"); - astbuf1->is_input = prev_was_input; - astbuf1->is_output = prev_was_output; - } - } wire_name | - { - if (!astbuf1) { - if (!sv_mode) - frontend_verilog_yyerror("task/function argument direction missing"); - albuf = new dict; - astbuf1 = new AstNode(AST_WIRE); - current_wire_rand = false; - current_wire_const = false; - astbuf1->is_input = true; - astbuf2 = NULL; - } - } 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"; - SET_AST_NODE_LOC(cell, en_expr ? @1 : @2, @10); - - 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 ',' specify_triple specify_opt_triple ')' ';' { - 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); - - specify_triple *limit = $11; - specify_triple *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"; - SET_AST_NODE_LOC(cell, @1, @14); - - 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->t_min)); - cell->children.back()->str = "\\T_LIMIT_MIN"; - - cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg)); - cell->children.back()->str = "\\T_LIMIT_TYP"; - - cell->children.push_back(new AstNode(AST_PARASET, limit->t_max)); - cell->children.back()->str = "\\T_LIMIT_MAX"; - - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_min : AstNode::mkconst_int(0, true))); - cell->children.back()->str = "\\T_LIMIT2_MIN"; - - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_avg : AstNode::mkconst_int(0, true))); - cell->children.back()->str = "\\T_LIMIT2_TYP"; - - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_max : AstNode::mkconst_int(0, true))); - cell->children.back()->str = "\\T_LIMIT2_MAX"; - - 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; - delete limit; - delete limit2; - }; - -specify_opt_triple: - ',' specify_triple { - $$ = $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'; } | - %empty { $$ = 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 ',' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; - delete $6; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); - } | - '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; - delete $6; - delete $8; - delete $10; - delete $12; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); - } | - '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; - delete $6; - delete $8; - delete $10; - delete $12; - delete $14; - delete $16; - delete $18; - delete $20; - delete $22; - delete $24; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); - } - -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 '=' ignspec_expr ; - -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 : - '(' ignspec_expr list_of_path_delay_extra_expressions ')' - | ignspec_expr - | ignspec_expr list_of_path_delay_extra_expressions - ; - -list_of_path_delay_extra_expressions : - ',' ignspec_expr - | ',' ignspec_expr 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 : - '+' | '-' | %empty; - -// 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 TOK_IGNORED_SPECIFY_AND system_timing_arg | - system_timing_args ',' system_timing_arg ; - -// 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; } | - expr ':' expr ':' expr { - delete $1; - delete $3; - delete $5; - }; - -ignspec_id: - TOK_ID { delete $1; } - range_or_multirange { delete $3; }; - -/**********************************************************************/ - -param_signed: - TOK_SIGNED { - astbuf1->is_signed = true; - } | TOK_UNSIGNED { - astbuf1->is_signed = false; - } | %empty; - -param_integer: - type_atom { - astbuf1->is_reg = false; - }; - -param_real: - TOK_REAL { - astbuf1->children.push_back(new AstNode(AST_REALVALUE)); - }; - -param_range: - range { - if ($1 != NULL) { - astbuf1->children.push_back($1); - } - }; - -param_integer_type: param_integer param_signed; -param_range_type: - type_vec param_signed { - addRange(astbuf1, 0, 0); - } | - type_vec param_signed non_opt_range { - astbuf1->children.push_back($3); - }; -param_implicit_type: param_signed param_range; - -param_type: - param_integer_type | param_real | param_range_type | param_implicit_type | - hierarchical_type_id { - astbuf1->is_custom_type = true; - astbuf1->children.push_back(new AstNode(AST_WIRETYPE)); - astbuf1->children.back()->str = *$1; - delete $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_type 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_type param_decl_list ';' { - delete astbuf1; - }; - -param_decl_list: - single_param_decl | param_decl_list ',' single_param_decl; - -single_param_decl: - single_param_decl_ident '=' expr { - AstNode *decl = ast_stack.back()->children.back(); - log_assert(decl->type == AST_PARAMETER || decl->type == AST_LOCALPARAM); - delete decl->children[0]; - decl->children[0] = $3; - } | - single_param_decl_ident { - AstNode *decl = ast_stack.back()->children.back(); - if (decl->type != AST_PARAMETER) { - log_assert(decl->type == AST_LOCALPARAM); - frontend_verilog_yyerror("localparam initialization is missing!"); - } - if (!sv_mode) - frontend_verilog_yyerror("Parameter defaults can only be omitted in SystemVerilog mode!"); - delete decl->children[0]; - decl->children.erase(decl->children.begin()); - }; - -single_param_decl_ident: - TOK_ID { - 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; - ast_stack.back()->children.push_back(node); - delete $1; - SET_AST_NODE_LOC(node, @1, @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); - }; - -///////// -// enum -///////// - -enum_type: TOK_ENUM { - static int enum_count; - // create parent node for the enum - astbuf2 = new AstNode(AST_ENUM); - ast_stack.back()->children.push_back(astbuf2); - astbuf2->str = std::string("$enum"); - astbuf2->str += std::to_string(enum_count++); - // create the template for the names - astbuf1 = new AstNode(AST_ENUM_ITEM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - } enum_base_type '{' enum_name_list optional_comma '}' { - // create template for the enum vars - auto tnode = astbuf1->clone(); - delete astbuf1; - astbuf1 = tnode; - tnode->type = AST_WIRE; - tnode->attributes[ID::enum_type] = AstNode::mkconst_str(astbuf2->str); - // drop constant but keep any range - delete tnode->children[0]; - tnode->children.erase(tnode->children.begin()); - $$ = astbuf1; - }; - -enum_base_type: type_atom type_signing - | type_vec type_signing range { if ($3) astbuf1->children.push_back($3); } - | %empty { astbuf1->is_reg = true; addRange(astbuf1); } - ; - -type_atom: - integer_atom_type { - astbuf1->is_reg = true; - astbuf1->is_signed = true; - addRange(astbuf1, $1 - 1, 0); - }; - -type_vec: TOK_REG { astbuf1->is_reg = true; } // unsigned - | TOK_LOGIC { astbuf1->is_logic = true; } // unsigned - ; - -type_signing: - TOK_SIGNED { astbuf1->is_signed = true; } - | TOK_UNSIGNED { astbuf1->is_signed = false; } - | %empty - ; - -enum_name_list: enum_name_decl - | enum_name_list ',' enum_name_decl - ; - -enum_name_decl: - TOK_ID opt_enum_init { - // put in fn - log_assert(astbuf1); - log_assert(astbuf2); - auto node = astbuf1->clone(); - node->str = *$1; - delete $1; - SET_AST_NODE_LOC(node, @1, @1); - delete node->children[0]; - node->children[0] = $2 ? $2 : new AstNode(AST_NONE); - astbuf2->children.push_back(node); - } - ; - -opt_enum_init: - '=' basic_expr { $$ = $2; } // TODO: restrict this - | %empty { $$ = NULL; } - ; - -enum_var_list: - enum_var - | enum_var_list ',' enum_var - ; - -enum_var: TOK_ID { - log_assert(astbuf1); - log_assert(astbuf2); - auto node = astbuf1->clone(); - ast_stack.back()->children.push_back(node); - node->str = *$1; - delete $1; - SET_AST_NODE_LOC(node, @1, @1); - node->is_enum = true; - } - ; - -enum_decl: enum_type enum_var_list ';' { delete $1; } - ; - -////////////////// -// struct or union -////////////////// - -struct_decl: struct_type struct_var_list ';' { delete astbuf2; } - ; - -struct_type: struct_union { astbuf2 = $1; } struct_body { $$ = astbuf2; } - ; - -struct_union: - TOK_STRUCT { $$ = new AstNode(AST_STRUCT); } - | TOK_UNION { $$ = new AstNode(AST_UNION); } - ; - -struct_body: opt_packed '{' struct_member_list '}' - ; - -opt_packed: - TOK_PACKED opt_signed_struct | - %empty { frontend_verilog_yyerror("Only PACKED supported at this time"); }; - -opt_signed_struct: - TOK_SIGNED { astbuf2->is_signed = true; } - | TOK_UNSIGNED { astbuf2->is_signed = false; } - | %empty // default is unsigned - ; - -struct_member_list: struct_member - | struct_member_list struct_member - ; - -struct_member: struct_member_type member_name_list ';' { delete astbuf1; } - ; - -member_name_list: - member_name - | member_name_list ',' member_name - ; - -member_name: TOK_ID { - astbuf1->str = $1->substr(1); - delete $1; - astbuf3 = astbuf1->clone(); - SET_AST_NODE_LOC(astbuf3, @1, @1); - astbuf2->children.push_back(astbuf3); - } range { if ($3) astbuf3->children.push_back($3); } - ; - -struct_member_type: { astbuf1 = new AstNode(AST_STRUCT_ITEM); } member_type_token - ; - -member_type_token: - member_type - | hierarchical_type_id { - // use a clone of the typedef definition nodes - auto template_node = copyTypeDefinition(*$1); - delete $1; - switch (template_node->type) { - case AST_WIRE: - template_node->type = AST_STRUCT_ITEM; - break; - case AST_STRUCT: - case AST_UNION: - break; - default: - frontend_verilog_yyerror("Invalid type for struct member: %s", type2str(template_node->type).c_str()); - } - delete astbuf1; - astbuf1 = template_node; - } - | { - delete astbuf1; - } struct_union { - // stash state on ast_stack - ast_stack.push_back(astbuf2); - astbuf2 = $2; - } struct_body { - astbuf1 = astbuf2; - // recover state - astbuf2 = ast_stack.back(); - ast_stack.pop_back(); - } - ; - -member_type: type_atom type_signing - | type_vec type_signing range_or_multirange { if ($3) astbuf1->children.push_back($3); } - ; - -struct_var_list: struct_var - | struct_var_list ',' struct_var - ; - -struct_var: TOK_ID { auto *var_node = astbuf2->clone(); - var_node->str = *$1; - delete $1; - SET_AST_NODE_LOC(var_node, @1, @1); - ast_stack.back()->children.push_back(var_node); - } - ; - -///////// -// wire -///////// - -wire_decl: - attr wire_type range { - albuf = $1; - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); - } delay 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(ID::anyconst)) { - delete ast_stack.back()->children.back()->attributes.at(ID::anyconst); - ast_stack.back()->children.back()->attributes.erase(ID::anyconst); - attr_anyconst = true; - } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::anyseq)) { - delete ast_stack.back()->children.back()->attributes.at(ID::anyseq); - ast_stack.back()->children.back()->attributes.erase(ID::anyseq); - attr_anyseq = true; - } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::allconst)) { - delete ast_stack.back()->children.back()->attributes.at(ID::allconst); - ast_stack.back()->children.back()->attributes.erase(ID::allconst); - attr_allconst = true; - } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::allseq)) { - delete ast_stack.back()->children.back()->attributes.at(ID::allseq); - ast_stack.back()->children.back()->attributes.erase(ID::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[ID::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(ID::defaultvalue)) - delete astbuf1->attributes.at(ID::defaultvalue); - astbuf1->attributes[ID::defaultvalue] = $3; - } - else if (astbuf1->is_reg || astbuf1->is_logic){ - AstNode *assign = new AstNode(AST_ASSIGN_LE, wire, $3); - AstNode *block = new AstNode(AST_BLOCK, assign); - AstNode *init = new AstNode(AST_INITIAL, block); - - SET_AST_NODE_LOC(assign, @1, @3); - SET_AST_NODE_LOC(block, @1, @3); - SET_AST_NODE_LOC(init, @1, @3); - - ast_stack.back()->children.push_back(init); - } - else { - AstNode *assign = new AstNode(AST_ASSIGN, wire, $3); - SET_AST_NODE_LOC(assign, @1, @3); - ast_stack.back()->children.push_back(assign); - } - - }; - -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 && !node->is_custom_type) { - addRange(node, 0, 0, false); - } - rewriteAsMemoryNode(node, $2); - } - if (current_function_or_task) { - if (node->is_input || node->is_output) - node->port_id = current_function_or_task_port_id++; - } else if (ast_stack.back()->type == AST_GENBLOCK) { - if (node->is_input || node->is_output) - frontend_verilog_yyerror("Cannot declare module port `%s' within a generate block.", $1->c_str()); - } else { - 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()); - } - } - //FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column... - SET_AST_NODE_LOC(node, @1, @1); - 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 { - AstNode *node = new AstNode(AST_ASSIGN, $1, $3); - SET_AST_NODE_LOC(node, @$, @$); - ast_stack.back()->children.push_back(node); - }; - -type_name: TOK_ID // first time seen - | TOK_USER_TYPE { if (isInLocalScope($1)) frontend_verilog_yyerror("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); } - ; - -typedef_decl: - TOK_TYPEDEF typedef_base_type range type_name range_or_multirange ';' { - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); - if (astbuf2) - astbuf1->children.push_back(astbuf2); - - if ($5 != NULL) { - if (!astbuf2) { - addRange(astbuf1, 0, 0, false); - } - rewriteAsMemoryNode(astbuf1, $5); - } - addTypedefNode($4, astbuf1); } - | TOK_TYPEDEF enum_struct_type type_name ';' { addTypedefNode($3, $2); } - ; - -typedef_base_type: - hierarchical_type_id { - $$ = new AstNode(AST_WIRE); - $$->is_logic = true; - addWiretypeNode($1, $$); - } | - integer_vector_type opt_signedness_default_unsigned { - $$ = new AstNode(AST_WIRE); - if ($1 == TOK_REG) { - $$->is_reg = true; - } else { - $$->is_logic = true; - } - $$->is_signed = $2; - } | - integer_atom_type opt_signedness_default_signed { - $$ = new AstNode(AST_WIRE); - $$->is_logic = true; - $$->is_signed = $2; - $$->range_left = $1 - 1; - $$->range_right = 0; - }; - -enum_struct_type: - enum_type - | struct_type - ; - -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: - single_cell_no_array | single_cell_arraylist; - -single_cell_no_array: - 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 ')' { - SET_AST_NODE_LOC(astbuf2, @1, @$); - } - -single_cell_arraylist: - 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 ')'{ - SET_AST_NODE_LOC(astbuf2, @1, @$); - }; - -cell_list_no_array: - single_cell_no_array | - cell_list_no_array ',' single_cell_no_array; - -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 ')' { - SET_AST_NODE_LOC(astbuf2, @1, @$); - } - -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 '(' ')' { - // just ignore empty parameters - } | - '.' 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); - } | - attr TOK_WILDCARD_CONNECT { - if (!sv_mode) - frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode."); - astbuf2->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); - free_attr($1); - }; - -always_comb_or_latch: - TOK_ALWAYS_COMB { - $$ = false; - } | - TOK_ALWAYS_LATCH { - $$ = true; - }; - -always_or_always_ff: - TOK_ALWAYS { - $$ = false; - } | - TOK_ALWAYS_FF { - $$ = true; - }; - -always_stmt: - attr always_or_always_ff { - AstNode *node = new AstNode(AST_ALWAYS); - append_attr(node, $1); - if ($2) - node->attributes[ID::always_ff] = AstNode::mkconst_int(1, false); - 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 { - SET_AST_NODE_LOC(ast_stack.back(), @6, @6); - ast_stack.pop_back(); - - SET_AST_NODE_LOC(ast_stack.back(), @2, @$); - ast_stack.pop_back(); - - SET_RULE_LOC(@$, @2, @$); - } | - attr always_comb_or_latch { - AstNode *node = new AstNode(AST_ALWAYS); - append_attr(node, $1); - if ($2) - node->attributes[ID::always_latch] = AstNode::mkconst_int(1, false); - else - node->attributes[ID::always_comb] = AstNode::mkconst_int(1, false); - 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(); - } | - 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); - SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); - node->children.push_back($2); - } | - TOK_NEGEDGE expr { - AstNode *node = new AstNode(AST_NEGEDGE); - SET_AST_NODE_LOC(node, @1, @1); - 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); - SET_AST_NODE_LOC(node, @1, @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 '(' expr ')' ';' { - if (noassume_mode) { - delete $5; - } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); - SET_AST_NODE_LOC(node, @1, @6); - 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); - SET_AST_NODE_LOC(node, @1, @7); - 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); - SET_AST_NODE_LOC(node, @1, @7); - 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); - SET_AST_NODE_LOC(node, @1, @6); - 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)); - SET_AST_NODE_LOC(node, @1, @5); - 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)); - SET_AST_NODE_LOC(node, @1, @2); - 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); - SET_AST_NODE_LOC(node, @1, @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; - } | - opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) { - delete $6; - } else { - AstNode *node = new AstNode(AST_FAIR, $6); - SET_AST_NODE_LOC(node, @1, @7); - 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 ')' ';' { - AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); - SET_AST_NODE_LOC(node, @1, @6); - ast_stack.back()->children.push_back(node); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { - AstNode *node = new AstNode(AST_ASSUME, $5); - SET_AST_NODE_LOC(node, @1, @6); - ast_stack.back()->children.push_back(node); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); - SET_AST_NODE_LOC(node, @1, @7); - ast_stack.back()->children.push_back(node); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - AstNode *node = new AstNode(AST_FAIR, $6); - SET_AST_NODE_LOC(node, @1, @7); - ast_stack.back()->children.push_back(node); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } | - opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { - AstNode *node = new AstNode(AST_COVER, $5); - SET_AST_NODE_LOC(node, @1, @6); - ast_stack.back()->children.push_back(node); - 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 { - AstNode *node = new AstNode(AST_ASSUME, $5); - SET_AST_NODE_LOC(node, @1, @6); - ast_stack.back()->children.push_back(node); - 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 { - AstNode *node = new AstNode(AST_FAIR, $6); - SET_AST_NODE_LOC(node, @1, @7); - ast_stack.back()->children.push_back(node); - if ($1 != nullptr) { - ast_stack.back()->children.back()->str = *$1; - delete $1; - } - } - }; - -simple_behavioral_stmt: - attr lvalue '=' delay expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $5); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @5); - append_attr(node, $1); - } | - attr lvalue TOK_INCREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @3); - append_attr(node, $1); - } | - attr lvalue TOK_DECREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_SUB, $2->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @3); - append_attr(node, $1); - } | - attr lvalue OP_LE delay expr { - AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @5); - append_attr(node, $1); - } | - attr lvalue asgn_binop delay expr { - AstNode *expr_node = $5; - if ($3 == AST_SHIFT_LEFT || $3 == AST_SHIFT_RIGHT || - $3 == AST_SHIFT_SLEFT || $3 == AST_SHIFT_SRIGHT) { - expr_node = new AstNode(AST_TO_UNSIGNED, expr_node); - SET_AST_NODE_LOC(expr_node, @5, @5); - } - AstNode *op_node = new AstNode($3, $2->clone(), expr_node); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, op_node); - SET_AST_NODE_LOC(op_node, @2, @5); - SET_AST_NODE_LOC(node, @2, @5); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); - }; - -asgn_binop: - TOK_BIT_OR_ASSIGN { $$ = AST_BIT_OR; } | - TOK_BIT_AND_ASSIGN { $$ = AST_BIT_AND; } | - TOK_BIT_XOR_ASSIGN { $$ = AST_BIT_XOR; } | - TOK_ADD_ASSIGN { $$ = AST_ADD; } | - TOK_SUB_ASSIGN { $$ = AST_SUB; } | - TOK_DIV_ASSIGN { $$ = AST_DIV; } | - TOK_MOD_ASSIGN { $$ = AST_MOD; } | - TOK_MUL_ASSIGN { $$ = AST_MUL; } | - TOK_SHL_ASSIGN { $$ = AST_SHIFT_LEFT; } | - TOK_SHR_ASSIGN { $$ = AST_SHIFT_RIGHT; } | - TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } | - TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ; - -for_initialization: - TOK_ID '=' expr { - AstNode *ident = new AstNode(AST_IDENTIFIER); - ident->str = *$1; - AstNode *node = new AstNode(AST_ASSIGN_EQ, ident, $3); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @3); - delete $1; - } | - non_io_wire_type range TOK_ID { - frontend_verilog_yyerror("For loop variable declaration is missing initialization!"); - } | - non_io_wire_type range TOK_ID '=' expr { - if (!sv_mode) - frontend_verilog_yyerror("For loop inline variable declaration is only supported in SystemVerilog mode!"); - - // loop variable declaration - AstNode *wire = $1; - AstNode *range = checkRange(wire, $2); - if (range != nullptr) - wire->children.push_back(range); - SET_AST_NODE_LOC(wire, @1, @3); - SET_AST_NODE_LOC(range, @2, @2); - - AstNode *ident = new AstNode(AST_IDENTIFIER); - ident->str = *$3; - wire->str = *$3; - delete $3; - - AstNode *loop = ast_stack.back(); - AstNode *parent = ast_stack.at(ast_stack.size() - 2); - log_assert(parent->children.back() == loop); - - // loop variable initialization - AstNode *asgn = new AstNode(AST_ASSIGN_EQ, ident, $5); - loop->children.push_back(asgn); - SET_AST_NODE_LOC(asgn, @3, @5); - SET_AST_NODE_LOC(ident, @3, @3); - - // inject a wrapping block to declare the loop variable and - // contain the current loop - AstNode *wrapper = new AstNode(AST_BLOCK); - wrapper->str = "$fordecl_block$" + std::to_string(autoidx++); - wrapper->children.push_back(wire); - wrapper->children.push_back(loop); - parent->children.back() = wrapper; // replaces `loop` - }; - -// this production creates the obligatory if-else shift/reduce conflict -behavioral_stmt: - defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | - non_opt_delay behavioral_stmt | - simple_behavioral_stmt ';' | - attr ';' { - free_attr($1); - } | - attr hierarchical_id { - AstNode *node = new AstNode(AST_TCALL); - node->str = *$2; - delete $2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $1); - } opt_arg_list ';'{ - ast_stack.pop_back(); - } | - attr TOK_MSG_TASKS { - AstNode *node = new AstNode(AST_TCALL); - node->str = *$2; - delete $2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - append_attr(node, $1); - } opt_arg_list ';'{ - ast_stack.pop_back(); - } | - attr TOK_BEGIN { - enterTypeScope(); - } 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 ($4 != NULL) - node->str = *$4; - } behavioral_stmt_list TOK_END opt_label { - exitTypeScope(); - checkLabelsMatch("Begin label", $4, $8); - AstNode *node = ast_stack.back(); - // In SystemVerilog, unnamed blocks with block item declarations - // create an implicit hierarchy scope - if (sv_mode && node->str.empty()) - for (const AstNode* child : node->children) - if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER - || child->type == AST_LOCALPARAM || child->type == AST_TYPEDEF) { - node->str = "$unnamed_block$" + std::to_string(autoidx++); - break; - } - SET_AST_NODE_LOC(ast_stack.back(), @2, @8); - delete $4; - delete $8; - 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); - } for_initialization ';' expr { - ast_stack.back()->children.push_back($7); - } ';' simple_behavioral_stmt ')' { - AstNode *block = new AstNode(AST_BLOCK); - block->str = "$for_loop$" + std::to_string(autoidx++); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @13, @13); - ast_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @2, @13); - 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 { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); - 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 { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); - 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); - SET_AST_NODE_LOC(cond, @4, @4); - 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 { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); - } optional_else { - ast_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @2, @9); - 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); - SET_AST_NODE_LOC(ast_stack.back(), @4, @4); - } opt_synopsys_attr case_body TOK_ENDCASE { - SET_AST_NODE_LOC(ast_stack.back(), @2, @9); - case_type_stack.pop_back(); - ast_stack.pop_back(); - }; - -case_attr: - attr { - $$ = $1; - } | - attr TOK_UNIQUE0 { - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); - $$ = $1; - } | - attr TOK_PRIORITY { - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); - $$ = $1; - } | - attr TOK_UNIQUE { - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); - (*$1)[ID::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(ID::full_case) == 0) - ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(1, false); - } | - opt_synopsys_attr TOK_SYNOPSYS_PARALLEL_CASE { - if (ast_stack.back()->attributes.count(ID::parallel_case) == 0) - ast_stack.back()->attributes[ID::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); - SET_AST_NODE_LOC(cond, @1, @1); - - ast_stack.pop_back(); - ast_stack.back()->children.push_back(cond); - ast_stack.push_back(block); - } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @3, @3); - } | - %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(); - SET_AST_NODE_LOC(ast_stack.back(), @4, @4); - 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); - SET_AST_NODE_LOC(ast_stack.back(), @2, @2); - } gen_stmt_block { - case_type_stack.pop_back(); - ast_stack.pop_back(); - }; - -case_select: - case_expr_list ':' | - TOK_DEFAULT; - -case_expr_list: - TOK_DEFAULT { - AstNode *node = new AstNode(AST_DEFAULT); - SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); - } | - TOK_SVA_LABEL { - AstNode *node = new AstNode(AST_IDENTIFIER); - SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); - 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; - SET_AST_NODE_LOC($$, @1, @6); - delete $1; - } | - hierarchical_id range { - $$ = new AstNode(AST_IDENTIFIER, $2); - $$->str = *$1; - SET_AST_NODE_LOC($$, @1, @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; - SET_AST_NODE_LOC($$, @1, @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 | - module_gen_body gen_block | - %empty; - -gen_stmt_or_module_body_stmt: - gen_stmt | module_body_stmt | - attr ';' { - free_attr($1); - }; - -genvar_identifier: - TOK_ID { - $$ = new AstNode(AST_IDENTIFIER); - $$->str = *$1; - delete $1; - }; - -genvar_initialization: - TOK_GENVAR genvar_identifier { - frontend_verilog_yyerror("Generate for loop variable declaration is missing initialization!"); - } | - TOK_GENVAR genvar_identifier '=' expr { - if (!sv_mode) - frontend_verilog_yyerror("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); - AstNode *node = new AstNode(AST_GENVAR); - node->is_reg = true; - node->is_signed = true; - node->range_left = 31; - node->range_right = 0; - node->str = $2->str; - node->children.push_back(checkRange(node, nullptr)); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @4); - node = new AstNode(AST_ASSIGN_EQ, $2, $4); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @4); - } | - genvar_identifier '=' expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @3); - }; - -// 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); - } genvar_initialization ';' expr { - ast_stack.back()->children.push_back($6); - } ';' simple_behavioral_stmt ')' gen_stmt_block { - SET_AST_NODE_LOC(ast_stack.back(), @1, @11); - rewriteGenForDeclInit(ast_stack.back()); - 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 { - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - 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(); - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - 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 ';'{ - SET_AST_NODE_LOC(ast_stack.back(), @1, @3); - ast_stack.pop_back(); - }; - -gen_block: - TOK_BEGIN { - enterTypeScope(); - } opt_label { - AstNode *node = new AstNode(AST_GENBLOCK); - node->str = $3 ? *$3 : std::string(); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } module_gen_body TOK_END opt_label { - exitTypeScope(); - checkLabelsMatch("Begin label", $3, $7); - delete $3; - delete $7; - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - ast_stack.pop_back(); - }; - -// result is wrapped in a genblock only if necessary -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 { - SET_AST_NODE_LOC(ast_stack.back(), @2, @2); - ast_stack.pop_back(); - } | gen_block; - -opt_gen_else: - TOK_ELSE gen_stmt_block | %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); - SET_AST_NODE_LOC($$, @1, @$); - append_attr($$, $3); - }; - -basic_expr: - rvalue { - $$ = $1; - } | - '(' expr ')' integral_number { - if ($4->compare(0, 1, "'") != 0) - 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 integral_number { - if ($2->compare(0, 1, "'") != 0) - 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; - SET_AST_NODE_LOC(bits, @1, @1); - AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - SET_AST_NODE_LOC(val, @2, @2); - if (val == NULL) - log_error("Value conversion failed: `%s'\n", $2->c_str()); - $$ = new AstNode(AST_TO_BITS, bits, val); - delete $1; - delete $2; - } | - integral_number { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - SET_AST_NODE_LOC($$, @1, @1); - 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); - SET_AST_NODE_LOC($$, @1, @1); - log_assert(*q == 0); - delete $1; - free(p); - } | - TOK_STRING { - $$ = AstNode::mkconst_str(*$1); - SET_AST_NODE_LOC($$, @1, @1); - delete $1; - } | - hierarchical_id attr { - AstNode *node = new AstNode(AST_FCALL); - node->str = *$1; - delete $1; - ast_stack.push_back(node); - SET_AST_NODE_LOC(node, @1, @1); - 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); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - } | - basic_expr '&' attr basic_expr { - $$ = new AstNode(AST_BIT_AND, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_NAND attr basic_expr { - $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_AND, $1, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '|' attr basic_expr { - $$ = new AstNode(AST_BIT_OR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_NOR attr basic_expr { - $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_OR, $1, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '^' attr basic_expr { - $$ = new AstNode(AST_BIT_XOR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_XNOR attr basic_expr { - $$ = new AstNode(AST_BIT_XNOR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - '&' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_AND, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - } | - OP_NAND attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_AND, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - $$ = new AstNode(AST_LOGIC_NOT, $$); - } | - '|' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_OR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - } | - OP_NOR attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_OR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - $$ = new AstNode(AST_LOGIC_NOT, $$); - SET_AST_NODE_LOC($$, @1, @3); - } | - '^' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_XOR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - } | - OP_XNOR attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_XNOR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - } | - basic_expr OP_SHL attr basic_expr { - $$ = new AstNode(AST_SHIFT_LEFT, $1, new AstNode(AST_TO_UNSIGNED, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_SHR attr basic_expr { - $$ = new AstNode(AST_SHIFT_RIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_SSHL attr basic_expr { - $$ = new AstNode(AST_SHIFT_SLEFT, $1, new AstNode(AST_TO_UNSIGNED, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_SSHR attr basic_expr { - $$ = new AstNode(AST_SHIFT_SRIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4)); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '<' attr basic_expr { - $$ = new AstNode(AST_LT, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_LE attr basic_expr { - $$ = new AstNode(AST_LE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_EQ attr basic_expr { - $$ = new AstNode(AST_EQ, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_NE attr basic_expr { - $$ = new AstNode(AST_NE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_EQX attr basic_expr { - $$ = new AstNode(AST_EQX, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_NEX attr basic_expr { - $$ = new AstNode(AST_NEX, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_GE attr basic_expr { - $$ = new AstNode(AST_GE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '>' attr basic_expr { - $$ = new AstNode(AST_GT, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '+' attr basic_expr { - $$ = new AstNode(AST_ADD, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '-' attr basic_expr { - $$ = new AstNode(AST_SUB, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '*' attr basic_expr { - $$ = new AstNode(AST_MUL, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '/' attr basic_expr { - $$ = new AstNode(AST_DIV, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr '%' attr basic_expr { - $$ = new AstNode(AST_MOD, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_POW attr basic_expr { - $$ = new AstNode(AST_POW, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - '+' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_POS, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - } | - '-' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_NEG, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - } | - basic_expr OP_LAND attr basic_expr { - $$ = new AstNode(AST_LOGIC_AND, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - basic_expr OP_LOR attr basic_expr { - $$ = new AstNode(AST_LOGIC_OR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); - } | - '!' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_LOGIC_NOT, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); - } | - TOK_SIGNED OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_TO_SIGNED, $4); - SET_AST_NODE_LOC($$, @1, @4); - } | - TOK_UNSIGNED OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_TO_UNSIGNED, $4); - SET_AST_NODE_LOC($$, @1, @4); - } | - basic_expr OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_CAST_SIZE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - }; - -concat_list: - expr { - $$ = new AstNode(AST_CONCAT, $1); - } | - expr ',' concat_list { - $$ = $3; - $$->children.push_back($1); - }; - -integral_number: - TOK_CONSTVAL { $$ = $1; } | - TOK_UNBASED_UNSIZED_CONSTVAL { $$ = $1; } | - TOK_BASE TOK_BASED_CONSTVAL { - $1->append(*$2); - $$ = $1; - delete $2; - } | - TOK_CONSTVAL TOK_BASE TOK_BASED_CONSTVAL { - $1->append(*$2).append(*$3); - $$ = $1; - delete $2; - delete $3; - }; diff --git a/yosys/guidelines/Checklists b/yosys/guidelines/Checklists deleted file mode 100644 index 75af12fa9e4..00000000000 --- a/yosys/guidelines/Checklists +++ /dev/null @@ -1,116 +0,0 @@ -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 docs/source/CHAPTER_CellLib.rst (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 docs - - sanity check the figures in docs/images - - if there are any odd things -> investigate - - cd ~yosys - vi README guidelines/* - - 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 guidelines/GettingStarted - - -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}": - - 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 - - remove "bumpversion" target from 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 install - - cd ~yosys-web - make update_show - git commit -am update - make push - - - Read the Docs updates handled by Jenkins on source change diff --git a/yosys/guidelines/CodeOfConduct b/yosys/guidelines/CodeOfConduct deleted file mode 100644 index 92decd3b6a5..00000000000 --- a/yosys/guidelines/CodeOfConduct +++ /dev/null @@ -1,72 +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 contact@yosyshq.com and/or -claire@clairexen.net. 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/guidelines/CodingStyle b/yosys/guidelines/CodingStyle deleted file mode 100644 index ee1e1a2b6a1..00000000000 --- a/yosys/guidelines/CodingStyle +++ /dev/null @@ -1,34 +0,0 @@ -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. - -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. \ No newline at end of file diff --git a/yosys/guidelines/GettingStarted b/yosys/guidelines/GettingStarted deleted file mode 100644 index d27b285fce4..00000000000 --- a/yosys/guidelines/GettingStarted +++ /dev/null @@ -1,249 +0,0 @@ -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: - - docs/source/CHAPTER_Prog/stubnets.cc - manual/PRESENTATION_Prog/my_cmd.cc - - -Script Passes -------------- - -The ScriptPass base class can be used to implement passes that just call other passes, -like a script. Examples for such passes are: - - techlibs/common/prep.cc - techlibs/common/synth.cc - -In some cases it is easier to implement such a pass as regular pass, for example when -ScriptPass doesn't provide the type of flow control desired. (But many of the -script passes in Yosys that don't use ScriptPass simply predate the ScriptPass base -class.) Examples for such passes are: - - passes/opt/opt.cc - passes/proc/proc.cc - -Whether they use the ScriptPass base-class or not, a pass should always either -call other passes without doing any non-trivial work itself, or should implement -a non-trivial algorithm but not call any other passes. The reason for this is that -this helps containing complexity in individual passes and simplifies debugging the -entire system. - -Exceptions to this rule should be rare and limited to cases where calling other -passes is optional and only happens when requested by the user (such as for -example `techmap -autoproc`), or where it is about commands that are "top-level -commands" in their own right, not components to be used in regular synthesis -flows (such as the `bugpoint` command). - -A pass that would "naturally" call other passes and also do some work itself -should be re-written in one of two ways: - -1) It could be re-written as script pass with the parts that are not calls -to other passes factored out into individual new passes. Usually in those -cases the new sub passes share the same prefix as the top-level script pass. - -2) It could be re-written so that it already expects the design in a certain -state, expecting the calling script to set up this state before calling the -pass in questions. - -Many back-ends are examples for the 2nd approach. For example, `write_aiger` -does not convert the design into AIG representation, but expects the design -to be already in this form, and prints an `Unsupported cell type` error -message otherwise. - - -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. \ No newline at end of file diff --git a/yosys/guidelines/UnitTests b/yosys/guidelines/UnitTests deleted file mode 100644 index d42a63ce587..00000000000 --- a/yosys/guidelines/UnitTests +++ /dev/null @@ -1,69 +0,0 @@ -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/guidelines/Windows b/yosys/guidelines/Windows deleted file mode 100644 index 2af0620fae9..00000000000 --- a/yosys/guidelines/Windows +++ /dev/null @@ -1,83 +0,0 @@ -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 - -Compiling with Visual Studio -============================ - -Visual Studio builds are not directly supported by build scripts, but they are still possible. - -1. Easy way - - - Go to https://github.com/YosysHQ/yosys/actions/workflows/vs.yml?query=branch%3Amaster - - Click on the most recent completed run - - In Artifacts region find vcxsrc and click on it to download - - Unpack downloaded ZIP file - - Open YosysVS.sln with Visual Studio - -2. Using WSL or MSYS2 - - - Make sure to have make, python3 and git available - - Git clone yosys repository - - Execute ```make vcxsrc YOSYS_VER=latest``` - - File yosys-win32-vcxsrc-latest.zip will be created - - Transfer that file to location visible by Windows application - - Unpack ZIP - - Open YosysVS.sln with Visual Studio - -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/YosysHQ/yosys.git yosys-win32 - cd yosys-win32 - make config-mxe - make -j$(nproc) mxebin diff --git a/yosys/kernel/binding.cc b/yosys/kernel/binding.cc deleted file mode 100644 index 621f7007bfa..00000000000 --- a/yosys/kernel/binding.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 "binding.h" - -YOSYS_NAMESPACE_BEGIN - -RTLIL::Binding::Binding(RTLIL::IdString target_type, - RTLIL::IdString target_name) - : target_type(target_type), target_name(target_name) -{} - -YOSYS_NAMESPACE_END diff --git a/yosys/kernel/binding.h b/yosys/kernel/binding.h deleted file mode 100644 index 3b64e76dac3..00000000000 --- a/yosys/kernel/binding.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 BINDING_H -#define BINDING_H - -#include "kernel/rtlil.h" - -YOSYS_NAMESPACE_BEGIN - -struct RTLIL::Binding -{ - // Represents a bind construct. - // - // The target of the binding is represented by target_type and - // target_name (see comments above the fields). - - Binding(RTLIL::IdString target_type, - RTLIL::IdString target_name); - - virtual ~Binding() {} - - // Return a string describing the binding - virtual std::string describe() const = 0; - -protected: - // May be empty. If not, it's the name of the module or interface to - // bind to. - RTLIL::IdString target_type; - - // If target_type is nonempty (the usual case), this is a hierarchical - // reference to the bind target. If target_type is empty, we have to - // wait until the hierarchy pass to figure out whether this was the name - // of a module/interface type or an instance. - RTLIL::IdString target_name; - - // An attribute name which contains an ID that's unique across binding - // instances (used to ensure we don't apply a binding twice to a module) - RTLIL::IdString attr_name; -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/bitpattern.h b/yosys/kernel/bitpattern.h deleted file mode 100644 index 7a8eb39f9f2..00000000000 --- a/yosys/kernel/bitpattern.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 9b02a6e30c8..00000000000 --- a/yosys/kernel/calc.cc +++ /dev/null @@ -1,717 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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; -} - -// Shift `arg1` by `arg2` bits. -// If `direction` is +1, `arg1` is shifted right by `arg2` bits; if `direction` is -1, `arg1` is shifted left by `arg2` bits. -// If `signed2` is true, `arg2` is interpreted as a signed integer; a negative `arg2` will cause a shift in the opposite direction. -// Any required bits outside the bounds of `arg1` are padded with `vacant_bits` unless `sign_ext` is true, in which case any bits outside the left -// bounds are filled with the leftmost bit of `arg1` (arithmetic shift). -static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, bool signed2, int direction, int result_len, RTLIL::State vacant_bits = RTLIL::State::S0) -{ - int undef_bit_pos = -1; - BigInteger offset = const2big(arg2, signed2, 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] = vacant_bits; - else if (pos >= BigInteger(int(arg1.bits.size()))) - result.bits[i] = sign_ext ? arg1.bits.back() : vacant_bits; - 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, 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, false, +1, result_len); -} - -RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len) -{ - return const_shift_worker(arg1, arg2, signed1, false, -1, result_len); -} - -RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len) -{ - return const_shift_worker(arg1, arg2, signed1, false, +1, result_len); -} - -RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, 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, signed2, +1, result_len); -} - -RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len) -{ - return const_shift_worker(arg1, arg2, false, signed2, +1, 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)); -} - -// truncating division -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)); -} - -// truncating modulo -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_divfloor(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_pos = (a.getSign() == BigInteger::negative) == (b.getSign() == BigInteger::negative); - a = a.getSign() == BigInteger::negative ? -a : a; - b = b.getSign() == BigInteger::negative ? -b : b; - BigInteger result; - - if (result_pos || a == 0) { - result = a / b; - } else { - // bigint division with negative numbers is wonky, make sure we only negate at the very end - result = -((a + b - 1) / b); - } - return big2const(result, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); -} - -RTLIL::Const RTLIL::const_modfloor(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); - - BigInteger::Sign a_sign = a.getSign(); - BigInteger::Sign b_sign = b.getSign(); - a = a_sign == BigInteger::negative ? -a : a; - b = b_sign == BigInteger::negative ? -b : b; - BigInteger truncated = a_sign == BigInteger::negative ? -(a % b) : (a % b); - BigInteger modulo; - - if (truncated == 0 || (a_sign == b_sign)) { - modulo = truncated; - } else { - modulo = b_sign == BigInteger::negative ? truncated - b : truncated + b; - } - return big2const(modulo, 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); -} - -RTLIL::Const RTLIL::const_mux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) -{ - log_assert(arg2.size() == arg1.size()); - if (arg3[0] == State::S0) - return arg1; - else if (arg3[0] == State::S1) - return arg2; - - RTLIL::Const ret = arg1; - for (int i = 0; i < ret.size(); i++) - if (ret[i] != arg2[i]) - ret[i] = State::Sx; - return ret; -} - -RTLIL::Const RTLIL::const_pmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) -{ - if (arg3.is_fully_zero()) - return arg1; - - if (!arg3.is_onehot()) - return RTLIL::Const(State::Sx, arg1.size()); - - for (int i = 0; i < arg3.size(); i++) - if (arg3[i] == State::S1) - return RTLIL::Const(std::vector(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size())); - - log_abort(); // unreachable -} - -RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2) -{ - std::vector t = arg1.bits; - - for (int i = GetSize(arg2)-1; i >= 0; i--) - { - RTLIL::State sel = arg2.bits.at(i); - std::vector new_t; - if (sel == State::S0) - new_t = std::vector(t.begin(), t.begin() + GetSize(t)/2); - else if (sel == State::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); - } - - return t; -} - -RTLIL::Const RTLIL::const_demux(const RTLIL::Const &arg1, const RTLIL::Const &arg2) -{ - int width = GetSize(arg1); - int s_width = GetSize(arg2); - std::vector res; - for (int i = 0; i < (1 << s_width); i++) - { - bool ne = false; - bool x = false; - for (int j = 0; j < s_width; j++) { - bool bit = i & 1 << j; - if (arg2[j] == (bit ? RTLIL::S0 : RTLIL::S1)) - ne = true; - else if (arg2[j] != RTLIL::S0 && arg2[j] != RTLIL::S1) - x = true; - } - if (ne) { - for (int j = 0; j < width; j++) - res.push_back(State::S0); - } else if (x) { - for (int j = 0; j < width; j++) - res.push_back(arg1.bits[j] == State::S0 ? State::S0 : State::Sx); - } else { - for (int j = 0; j < width; j++) - res.push_back(arg1.bits[j]); - } - } - return res; -} - -RTLIL::Const RTLIL::const_bweqx(const RTLIL::Const &arg1, const RTLIL::Const &arg2) -{ - log_assert(arg2.size() == arg1.size()); - RTLIL::Const result(RTLIL::State::S0, arg1.size()); - for (int i = 0; i < arg1.size(); i++) - result[i] = arg1[i] == arg2[i] ? State::S1 : State::S0; - - return result; -} - -RTLIL::Const RTLIL::const_bwmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) -{ - log_assert(arg2.size() == arg1.size()); - log_assert(arg3.size() == arg1.size()); - RTLIL::Const result(RTLIL::State::Sx, arg1.size()); - for (int i = 0; i < arg1.size(); i++) { - if (arg3[i] != State::Sx || arg1[i] == arg2[i]) - result[i] = arg3[i] == State::S1 ? arg2[i] : arg1[i]; - } - - return result; -} - -YOSYS_NAMESPACE_END - diff --git a/yosys/kernel/cellaigs.cc b/yosys/kernel/cellaigs.cc deleted file mode 100644 index 292af3f51b0..00000000000 --- a/yosys/kernel/cellaigs.cc +++ /dev/null @@ -1,495 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 == ID::A_WIDTH && mkname_a_signed) { - name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); - } else if (p.first == ID::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 == ID::A_SIGNED) { - mkname_a_signed = true; - mkname_is_signed = p.second.as_bool(); - } - if (p.first == ID::B_SIGNED) { - mkname_b_signed = true; - mkname_is_signed = p.second.as_bool(); - } - } - - if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($_BUF_))) - { - for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { - int A = mk.inport(ID::A, i); - int Y = cell->type.in(ID($not), ID($_NOT_)) ? mk.not_gate(A) : A; - mk.outport(Y, ID::Y, i); - } - goto optimize; - } - - if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_), ID($or), ID($_OR_), ID($_NOR_), ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) - { - for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { - int A = mk.inport(ID::A, i); - int B = mk.inport(ID::B, i); - int Y = cell->type.in(ID($and), ID($_AND_)) ? mk.and_gate(A, B) : - cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) : - cell->type.in(ID($or), ID($_OR_)) ? mk.or_gate(A, B) : - cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) : - cell->type.in(ID($xor), ID($_XOR_)) ? mk.xor_gate(A, B) : - cell->type.in(ID($xnor), ID($_XNOR_)) ? mk.xnor_gate(A, B) : - cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) : - cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1; - mk.outport(Y, ID::Y, i); - } - goto optimize; - } - - if (cell->type.in(ID($mux), ID($_MUX_))) - { - int S = mk.inport(ID::S); - for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { - int A = mk.inport(ID::A, i); - int B = mk.inport(ID::B, i); - int Y = mk.mux_gate(A, B, S); - if (cell->type == ID($_NMUX_)) - Y = mk.not_gate(Y); - mk.outport(Y, ID::Y, i); - } - goto optimize; - } - - if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool))) - { - int Y = mk.inport(ID::A, 0); - for (int i = 1; i < GetSize(cell->getPort(ID::A)); i++) { - int A = mk.inport(ID::A, i); - if (cell->type == ID($reduce_and)) Y = mk.and_gate(A, Y); - if (cell->type == ID($reduce_or)) Y = mk.or_gate(A, Y); - if (cell->type == ID($reduce_bool)) Y = mk.or_gate(A, Y); - if (cell->type == ID($reduce_xor)) Y = mk.xor_gate(A, Y); - if (cell->type == ID($reduce_xnor)) Y = mk.xor_gate(A, Y); - } - if (cell->type == ID($reduce_xnor)) - Y = mk.not_gate(Y); - mk.outport(Y, ID::Y, 0); - for (int i = 1; i < GetSize(cell->getPort(ID::Y)); i++) - mk.outport(mk.bool_node(false), ID::Y, i); - goto optimize; - } - - if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or))) - { - int A = mk.inport(ID::A, 0), Y = -1; - for (int i = 1; i < GetSize(cell->getPort(ID::A)); i++) - A = mk.or_gate(mk.inport(ID::A, i), A); - if (cell->type.in(ID($logic_and), ID($logic_or))) { - int B = mk.inport(ID::B, 0); - for (int i = 1; i < GetSize(cell->getPort(ID::B)); i++) - B = mk.or_gate(mk.inport(ID::B, i), B); - if (cell->type == ID($logic_and)) Y = mk.and_gate(A, B); - if (cell->type == ID($logic_or)) Y = mk.or_gate(A, B); - } else { - if (cell->type == ID($logic_not)) Y = mk.not_gate(A); - } - mk.outport_bool(Y, ID::Y); - goto optimize; - } - - if (cell->type.in(ID($add), ID($sub))) - { - int width = GetSize(cell->getPort(ID::Y)); - vector A = mk.inport_vec(ID::A, width); - vector B = mk.inport_vec(ID::B, width); - int carry = mk.bool_node(false); - if (cell->type == ID($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, ID::Y); - goto optimize; - } - - if (cell->type == ID($alu)) - { - int width = GetSize(cell->getPort(ID::Y)); - vector A = mk.inport_vec(ID::A, width); - vector B = mk.inport_vec(ID::B, width); - int carry = mk.inport(ID::CI); - int binv = mk.inport(ID::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, ID::Y); - mk.outport_vec(X, ID::X); - mk.outport_vec(CO, ID::CO); - goto optimize; - } - - if (cell->type.in(ID($eq), ID($ne))) - { - int width = max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::B))); - vector A = mk.inport_vec(ID::A, width); - vector B = mk.inport_vec(ID::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 == ID($eq)) - Y = mk.not_gate(Y); - mk.outport_bool(Y, ID::Y); - goto optimize; - } - - if (cell->type == ID($_AOI3_)) - { - int A = mk.inport(ID::A); - int B = mk.inport(ID::B); - int C = mk.inport(ID::C); - int Y = mk.nor_gate(mk.and_gate(A, B), C); - mk.outport(Y, ID::Y); - goto optimize; - } - - if (cell->type == ID($_OAI3_)) - { - int A = mk.inport(ID::A); - int B = mk.inport(ID::B); - int C = mk.inport(ID::C); - int Y = mk.nand_gate(mk.or_gate(A, B), C); - mk.outport(Y, ID::Y); - goto optimize; - } - - if (cell->type == ID($_AOI4_)) - { - int A = mk.inport(ID::A); - int B = mk.inport(ID::B); - int C = mk.inport(ID::C); - int D = mk.inport(ID::D); - int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D)); - mk.outport(Y, ID::Y); - goto optimize; - } - - if (cell->type == ID($_OAI4_)) - { - int A = mk.inport(ID::A); - int B = mk.inport(ID::B); - int C = mk.inport(ID::C); - int D = mk.inport(ID::D); - int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D)); - mk.outport(Y, ID::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 8f6d69ba62b..00000000000 --- a/yosys/kernel/cellaigs.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 c43ba8db330..00000000000 --- a/yosys/kernel/celledges.cc +++ /dev/null @@ -1,235 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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) -{ - bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); - int a_width = GetSize(cell->getPort(ID::A)); - int y_width = GetSize(cell->getPort(ID::Y)); - - for (int i = 0; i < y_width; i++) - { - if (i < a_width) - db->add_edge(cell, ID::A, i, ID::Y, i, -1); - else if (is_signed && a_width > 0) - db->add_edge(cell, ID::A, a_width-1, ID::Y, i, -1); - } -} - -void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); - int a_width = GetSize(cell->getPort(ID::A)); - int b_width = GetSize(cell->getPort(ID::B)); - int y_width = GetSize(cell->getPort(ID::Y)); - - if (cell->type == ID($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, ID::A, i, ID::Y, i, -1); - else if (is_signed && a_width > 0) - db->add_edge(cell, ID::A, a_width-1, ID::Y, i, -1); - - if (i < b_width) - db->add_edge(cell, ID::B, i, ID::Y, i, -1); - else if (is_signed && b_width > 0) - db->add_edge(cell, ID::B, b_width-1, ID::Y, i, -1); - } -} - -void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); - int a_width = GetSize(cell->getPort(ID::A)); - int y_width = GetSize(cell->getPort(ID::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, ID::A, k, ID::Y, i, -1); -} - -void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); - int a_width = GetSize(cell->getPort(ID::A)); - int b_width = GetSize(cell->getPort(ID::B)); - int y_width = GetSize(cell->getPort(ID::Y)); - - if (!is_signed && cell->type != ID($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, ID::A, k, ID::Y, i, -1); - - if (k < b_width) - db->add_edge(cell, ID::B, k, ID::Y, i, -1); - } - } -} - -void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - int a_width = GetSize(cell->getPort(ID::A)); - - for (int i = 0; i < a_width; i++) - db->add_edge(cell, ID::A, i, ID::Y, 0, -1); -} - -void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - int a_width = GetSize(cell->getPort(ID::A)); - int b_width = GetSize(cell->getPort(ID::B)); - - for (int i = 0; i < a_width; i++) - db->add_edge(cell, ID::A, i, ID::Y, 0, -1); - - for (int i = 0; i < b_width; i++) - db->add_edge(cell, ID::B, i, ID::Y, 0, -1); -} - -void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - int a_width = GetSize(cell->getPort(ID::A)); - int b_width = GetSize(cell->getPort(ID::B)); - int s_width = GetSize(cell->getPort(ID::S)); - - for (int i = 0; i < a_width; i++) - { - db->add_edge(cell, ID::A, i, ID::Y, i, -1); - - for (int k = i; k < b_width; k += a_width) - db->add_edge(cell, ID::B, k, ID::Y, i, -1); - - for (int k = 0; k < s_width; k++) - db->add_edge(cell, ID::S, k, ID::Y, i, -1); - } -} - -void bmux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - int width = GetSize(cell->getPort(ID::Y)); - int a_width = GetSize(cell->getPort(ID::A)); - int s_width = GetSize(cell->getPort(ID::S)); - - for (int i = 0; i < width; i++) - { - for (int k = i; k < a_width; k += width) - db->add_edge(cell, ID::A, k, ID::Y, i, -1); - - for (int k = 0; k < s_width; k++) - db->add_edge(cell, ID::S, k, ID::Y, i, -1); - } -} - -void demux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) -{ - int width = GetSize(cell->getPort(ID::Y)); - int a_width = GetSize(cell->getPort(ID::A)); - int s_width = GetSize(cell->getPort(ID::S)); - - for (int i = 0; i < width; i++) - { - db->add_edge(cell, ID::A, i % a_width, ID::Y, i, -1); - for (int k = 0; k < s_width; k++) - db->add_edge(cell, ID::S, k, ID::Y, i, -1); - } -} - -PRIVATE_NAMESPACE_END - -bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell) -{ - if (cell->type.in(ID($not), ID($pos))) { - bitwise_unary_op(this, cell); - return true; - } - - if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) { - bitwise_binary_op(this, cell); - return true; - } - - if (cell->type == ID($neg)) { - arith_neg_op(this, cell); - return true; - } - - if (cell->type.in(ID($add), ID($sub))) { - arith_binary_op(this, cell); - return true; - } - - if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) { - reduce_op(this, cell); - return true; - } - - // FIXME: - // if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) { - // shift_op(this, cell); - // return true; - // } - - if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) { - compare_op(this, cell); - return true; - } - - if (cell->type.in(ID($mux), ID($pmux))) { - mux_op(this, cell); - return true; - } - - if (cell->type == ID($bmux)) { - bmux_op(this, cell); - return true; - } - - if (cell->type == ID($demux)) { - demux_op(this, cell); - return true; - } - - // FIXME: $mul $div $mod $divfloor $modfloor $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 d5e374f050c..00000000000 --- a/yosys/kernel/celledges.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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) 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) 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 63e7408c142..00000000000 --- a/yosys/kernel/celltypes.h +++ /dev/null @@ -1,529 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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_internals_anyinit(); - 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(); - - setup_type(ID($tribuf), {ID::A, ID::EN}, {ID::Y}, true); - - setup_type(ID($assert), {ID::A, ID::EN}, pool(), true); - setup_type(ID($assume), {ID::A, ID::EN}, pool(), true); - setup_type(ID($live), {ID::A, ID::EN}, pool(), true); - setup_type(ID($fair), {ID::A, ID::EN}, pool(), true); - setup_type(ID($cover), {ID::A, ID::EN}, pool(), true); - setup_type(ID($initstate), pool(), {ID::Y}, true); - setup_type(ID($anyconst), pool(), {ID::Y}, true); - setup_type(ID($anyseq), pool(), {ID::Y}, true); - setup_type(ID($allconst), pool(), {ID::Y}, true); - setup_type(ID($allseq), pool(), {ID::Y}, true); - setup_type(ID($equiv), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool(), true); - setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool(), true); - setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool(), true); - } - - void setup_internals_eval() - { - std::vector unary_ops = { - ID($not), ID($pos), ID($neg), - ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), - ID($logic_not), ID($slice), ID($lut), ID($sop) - }; - - std::vector binary_ops = { - ID($and), ID($or), ID($xor), ID($xnor), - ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), - ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), - ID($logic_and), ID($logic_or), ID($concat), ID($macc), - ID($bweqx) - }; - - for (auto type : unary_ops) - setup_type(type, {ID::A}, {ID::Y}, true); - - for (auto type : binary_ops) - setup_type(type, {ID::A, ID::B}, {ID::Y}, true); - - for (auto type : std::vector({ID($mux), ID($pmux), ID($bwmux)})) - setup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true); - - for (auto type : std::vector({ID($bmux), ID($demux)})) - setup_type(type, {ID::A, ID::S}, {ID::Y}, true); - - setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true); - setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true); - setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true); - } - - void setup_internals_ff() - { - setup_type(ID($sr), {ID::SET, ID::CLR}, {ID::Q}); - setup_type(ID($ff), {ID::D}, {ID::Q}); - setup_type(ID($dff), {ID::CLK, ID::D}, {ID::Q}); - setup_type(ID($dffe), {ID::CLK, ID::EN, ID::D}, {ID::Q}); - setup_type(ID($dffsr), {ID::CLK, ID::SET, ID::CLR, ID::D}, {ID::Q}); - setup_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($adff), {ID::CLK, ID::ARST, ID::D}, {ID::Q}); - setup_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($aldff), {ID::CLK, ID::ALOAD, ID::AD, ID::D}, {ID::Q}); - setup_type(ID($aldffe), {ID::CLK, ID::ALOAD, ID::AD, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($sdff), {ID::CLK, ID::SRST, ID::D}, {ID::Q}); - setup_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q}); - setup_type(ID($dlatch), {ID::EN, ID::D}, {ID::Q}); - setup_type(ID($adlatch), {ID::EN, ID::D, ID::ARST}, {ID::Q}); - setup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q}); - } - - void setup_internals_anyinit() - { - setup_type(ID($anyinit), {ID::D}, {ID::Q}); - } - - void setup_internals_mem() - { - setup_internals_ff(); - - setup_type(ID($memrd), {ID::CLK, ID::EN, ID::ADDR}, {ID::DATA}); - setup_type(ID($memrd_v2), {ID::CLK, ID::EN, ID::ARST, ID::SRST, ID::ADDR}, {ID::DATA}); - setup_type(ID($memwr), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool()); - setup_type(ID($memwr_v2), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool()); - setup_type(ID($meminit), {ID::ADDR, ID::DATA}, pool()); - setup_type(ID($meminit_v2), {ID::ADDR, ID::DATA, ID::EN}, pool()); - setup_type(ID($mem), {ID::RD_CLK, ID::RD_EN, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA}); - setup_type(ID($mem_v2), {ID::RD_CLK, ID::RD_EN, ID::RD_ARST, ID::RD_SRST, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA}); - - setup_type(ID($fsm), {ID::CLK, ID::ARST, ID::CTRL_IN}, {ID::CTRL_OUT}); - } - - void setup_stdcells() - { - setup_stdcells_eval(); - - setup_type(ID($_TBUF_), {ID::A, ID::E}, {ID::Y}, true); - } - - void setup_stdcells_eval() - { - setup_type(ID($_BUF_), {ID::A}, {ID::Y}, true); - setup_type(ID($_NOT_), {ID::A}, {ID::Y}, true); - setup_type(ID($_AND_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_NAND_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_OR_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_NOR_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_XOR_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_XNOR_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_ANDNOT_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_ORNOT_), {ID::A, ID::B}, {ID::Y}, true); - setup_type(ID($_MUX_), {ID::A, ID::B, ID::S}, {ID::Y}, true); - setup_type(ID($_NMUX_), {ID::A, ID::B, ID::S}, {ID::Y}, true); - setup_type(ID($_MUX4_), {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T}, {ID::Y}, true); - setup_type(ID($_MUX8_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U}, {ID::Y}, true); - setup_type(ID($_MUX16_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V}, {ID::Y}, true); - setup_type(ID($_AOI3_), {ID::A, ID::B, ID::C}, {ID::Y}, true); - setup_type(ID($_OAI3_), {ID::A, ID::B, ID::C}, {ID::Y}, true); - setup_type(ID($_AOI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}, true); - setup_type(ID($_OAI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}, true); - } - - void setup_stdcells_mem() - { - 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), {ID::S, ID::R}, {ID::Q}); - - setup_type(ID($_FF_), {ID::D}, {ID::Q}); - - for (auto c1 : list_np) - setup_type(stringf("$_DFF_%c_", c1), {ID::C, ID::D}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - setup_type(stringf("$_DFFE_%c%c_", c1, c2), {ID::C, ID::D, ID::E}, {ID::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), {ID::C, ID::R, ID::D}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_01) - for (auto c4 : list_np) - setup_type(stringf("$_DFFE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - setup_type(stringf("$_ALDFF_%c%c_", c1, c2), {ID::C, ID::L, ID::AD, ID::D}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_np) - setup_type(stringf("$_ALDFFE_%c%c%c_", c1, c2, c3), {ID::C, ID::L, ID::AD, ID::D, ID::E}, {ID::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), {ID::C, ID::S, ID::R, ID::D}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_np) - for (auto c4 : list_np) - setup_type(stringf("$_DFFSRE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::S, ID::R, ID::D, ID::E}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_01) - setup_type(stringf("$_SDFF_%c%c%c_", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_01) - for (auto c4 : list_np) - setup_type(stringf("$_SDFFE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_01) - for (auto c4 : list_np) - setup_type(stringf("$_SDFFCE_%c%c%c%c_", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q}); - - for (auto c1 : list_np) - setup_type(stringf("$_DLATCH_%c_", c1), {ID::E, ID::D}, {ID::Q}); - - for (auto c1 : list_np) - for (auto c2 : list_np) - for (auto c3 : list_01) - setup_type(stringf("$_DLATCH_%c%c%c_", c1, c2, c3), {ID::E, ID::R, ID::D}, {ID::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), {ID::E, ID::S, ID::R, ID::D}, {ID::Q}); - } - - void clear() - { - cell_types.clear(); - } - - bool cell_known(RTLIL::IdString type) const - { - return cell_types.count(type) != 0; - } - - bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const - { - 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) const - { - auto it = cell_types.find(type); - return it != cell_types.end() && it->second.inputs.count(port) != 0; - } - - bool cell_evaluable(RTLIL::IdString type) const - { - 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 == State::S0) bit = State::S1; - else if (bit == State::S1) bit = State::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 == ID($sshr) && !signed1) - type = ID($shr); - if (type == ID($sshl) && !signed1) - type = ID($shl); - - if (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) && - type != ID($pos) && type != ID($neg) && type != ID($not)) { - if (!signed1 || !signed2) - signed1 = false, signed2 = false; - } - -#define HANDLE_CELL_TYPE(_t) if (type == ID($##_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(divfloor) - HANDLE_CELL_TYPE(modfloor) - HANDLE_CELL_TYPE(pow) - HANDLE_CELL_TYPE(pos) - HANDLE_CELL_TYPE(neg) -#undef HANDLE_CELL_TYPE - - if (type == ID($_BUF_)) - return arg1; - if (type == ID($_NOT_)) - return eval_not(arg1); - if (type == ID($_AND_)) - return const_and(arg1, arg2, false, false, 1); - if (type == ID($_NAND_)) - return eval_not(const_and(arg1, arg2, false, false, 1)); - if (type == ID($_OR_)) - return const_or(arg1, arg2, false, false, 1); - if (type == ID($_NOR_)) - return eval_not(const_or(arg1, arg2, false, false, 1)); - if (type == ID($_XOR_)) - return const_xor(arg1, arg2, false, false, 1); - if (type == ID($_XNOR_)) - return const_xnor(arg1, arg2, false, false, 1); - if (type == ID($_ANDNOT_)) - return const_and(arg1, eval_not(arg2), false, false, 1); - if (type == ID($_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 == ID($slice)) { - RTLIL::Const ret; - int width = cell->parameters.at(ID::Y_WIDTH).as_int(); - int offset = cell->parameters.at(ID::OFFSET).as_int(); - ret.bits.insert(ret.bits.end(), arg1.bits.begin()+offset, arg1.bits.begin()+offset+width); - return ret; - } - - if (cell->type == ID($concat)) { - RTLIL::Const ret = arg1; - ret.bits.insert(ret.bits.end(), arg2.bits.begin(), arg2.bits.end()); - return ret; - } - - if (cell->type == ID($bmux)) - { - return const_bmux(arg1, arg2); - } - - if (cell->type == ID($demux)) - { - return const_demux(arg1, arg2); - } - - if (cell->type == ID($bweqx)) - { - return const_bweqx(arg1, arg2); - } - - if (cell->type == ID($lut)) - { - int width = cell->parameters.at(ID::WIDTH).as_int(); - - std::vector t = cell->parameters.at(ID::LUT).bits; - while (GetSize(t) < (1 << width)) - t.push_back(State::S0); - t.resize(1 << width); - - return const_bmux(t, arg1); - } - - if (cell->type == ID($sop)) - { - int width = cell->parameters.at(ID::WIDTH).as_int(); - int depth = cell->parameters.at(ID::DEPTH).as_int(); - std::vector t = cell->parameters.at(ID::TABLE).bits; - - while (GetSize(t) < width*depth*2) - t.push_back(State::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(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool(); - bool signed_b = cell->parameters.count(ID::B_SIGNED) > 0 && cell->parameters[ID::B_SIGNED].as_bool(); - int result_len = cell->parameters.count(ID::Y_WIDTH) > 0 ? cell->parameters[ID::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(ID($mux), ID($_MUX_))) - return const_mux(arg1, arg2, arg3); - if (cell->type == ID($bwmux)) - return const_bwmux(arg1, arg2, arg3); - if (cell->type == ID($pmux)) - return const_pmux(arg1, arg2, arg3); - if (cell->type == ID($_AOI3_)) - return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1)); - if (cell->type == ID($_OAI3_)) - 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 == ID($_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 == ID($_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 4c0c26049f4..00000000000 --- a/yosys/kernel/consteval.h +++ /dev/null @@ -1,425 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 == ID($lcu)) - { - RTLIL::SigSpec sig_p = cell->getPort(ID::P); - RTLIL::SigSpec sig_g = cell->getPort(ID::G); - RTLIL::SigSpec sig_ci = cell->getPort(ID::CI); - RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort(ID::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] == State::S1) || (sig_p[i] == RTLIL::S1 && carry); - coval.bits[i] = carry ? State::S1 : State::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(ID::Y)); - sig_y = values_map(assign_map(cell->getPort(ID::Y))); - if (sig_y.is_fully_const()) - return true; - - if (cell->hasPort(ID::S)) { - sig_s = cell->getPort(ID::S); - } - - if (cell->hasPort(ID::A)) - sig_a = cell->getPort(ID::A); - - if (cell->hasPort(ID::B)) - sig_b = cell->getPort(ID::B); - - if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_NMUX_))) - { - std::vector y_candidates; - int count_set_s_bits = 0; - - if (!eval(sig_s, undef, cell)) - return false; - - 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) - 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; - if (cell->type == ID($_NMUX_)) - y_values.push_back(RTLIL::const_not(yc.as_const(), Const(), false, false, GetSize(yc))); - else - 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 == ID($bmux)) - { - if (!eval(sig_s, undef, cell)) - return false; - - if (sig_s.is_fully_def()) { - int sel = sig_s.as_int(); - int width = GetSize(sig_y); - SigSpec res = sig_a.extract(sel * width, width); - if (!eval(res, undef, cell)) - return false; - set(sig_y, res.as_const()); - } else { - if (!eval(sig_a, undef, cell)) - return false; - set(sig_y, const_bmux(sig_a.as_const(), sig_s.as_const())); - } - } - else if (cell->type == ID($demux)) - { - if (!eval(sig_a, undef, cell)) - return false; - if (sig_a.is_fully_zero()) { - set(sig_y, Const(0, GetSize(sig_y))); - } else { - if (!eval(sig_s, undef, cell)) - return false; - set(sig_y, const_demux(sig_a.as_const(), sig_s.as_const())); - } - } - else if (cell->type == ID($fa)) - { - RTLIL::SigSpec sig_c = cell->getPort(ID::C); - RTLIL::SigSpec sig_x = cell->getPort(ID::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 == ID($alu)) - { - bool signed_a = cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool(); - bool signed_b = cell->parameters.count(ID::B_SIGNED) > 0 && cell->parameters[ID::B_SIGNED].as_bool(); - - RTLIL::SigSpec sig_ci = cell->getPort(ID::CI); - RTLIL::SigSpec sig_bi = cell->getPort(ID::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(ID::X); - RTLIL::SigSpec sig_co = cell->getPort(ID::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] == State::S1; - bool b_inv = sig_bi[0] == State::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] == State::S1; - bool bit_b = (sig_b[i] == State::S1) != b_inv; - bool bit_x = bit_a != bit_b; - set(sig_x[i], bit_x ? State::S1 : State::S0); - } - - if (any_input_undef) { - set(sig_y[i], RTLIL::Sx); - set(sig_co[i], RTLIL::Sx); - } else { - bool bit_a = sig_a[i] == State::S1; - bool bit_b = (sig_b[i] == State::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 ? State::S1 : State::S0); - set(sig_co[i], carry ? State::S1 : State::S0); - } - } - } - else if (cell->type == ID($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(ID::Y))); - if (!macc.eval(result)) - log_abort(); - - set(cell->getPort(ID::Y), result); - } - else - { - RTLIL::SigSpec sig_c, sig_d; - - if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) { - if (cell->hasPort(ID::C)) - sig_c = cell->getPort(ID::C); - if (cell->hasPort(ID::D)) - sig_d = cell->getPort(ID::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/constids.inc b/yosys/kernel/constids.inc deleted file mode 100644 index 39211d0c753..00000000000 --- a/yosys/kernel/constids.inc +++ /dev/null @@ -1,264 +0,0 @@ -X(A) -X(abc9_box) -X(abc9_box_id) -X(abc9_box_seq) -X(abc9_bypass) -X(abc9_carry) -X(abc9_flop) -X(abc9_keep) -X(abc9_lut) -X(abc9_mergeability) -X(abc9_scc_id) -X(abcgroup) -X(ABITS) -X(AD) -X(ADDR) -X(allconst) -X(allseq) -X(ALOAD) -X(ALOAD_POLARITY) -X(always_comb) -X(always_ff) -X(always_latch) -X(anyconst) -X(anyseq) -X(ARST) -X(ARST_POLARITY) -X(ARST_VALUE) -X(A_SIGNED) -X(A_WIDTH) -X(B) -X(BI) -X(BITS_USED) -X(blackbox) -X(B_SIGNED) -X(bugpoint_keep) -X(B_WIDTH) -X(BYTE) -X(C) -X(cells_not_processed) -X(CE_OVER_SRST) -X(CFG_ABITS) -X(CFG_DBITS) -X(CFG_INIT) -X(CI) -X(CLK) -X(clkbuf_driver) -X(clkbuf_inhibit) -X(clkbuf_inv) -X(clkbuf_sink) -X(CLK_ENABLE) -X(CLK_POLARITY) -X(CLR) -X(CLR_POLARITY) -X(CO) -X(COLLISION_X_MASK) -X(CONFIG) -X(CONFIG_WIDTH) -X(CTRL_IN) -X(CTRL_IN_WIDTH) -X(CTRL_OUT) -X(CTRL_OUT_WIDTH) -X(D) -X(DAT) -X(DATA) -X(DAT_DST_PEN) -X(DAT_DST_POL) -X(defaultvalue) -X(DELAY) -X(DEPTH) -X(DST) -X(DST_EN) -X(DST_PEN) -X(DST_POL) -X(DST_WIDTH) -X(dynports) -X(E) -X(EDGE_EN) -X(EDGE_POL) -X(EN) -X(EN_DST) -X(EN_POLARITY) -X(EN_SRC) -X(enum_base_type) -X(enum_type) -X(equiv_merged) -X(equiv_region) -X(extract_order) -X(F) -X(force_downto) -X(force_upto) -X(fsm_encoding) -X(fsm_export) -X(FULL) -X(full_case) -X(G) -X(gclk) -X(gentb_clock) -X(gentb_constant) -X(gentb_skip) -X(H) -X(hdlname) -X(hierconn) -X(I) -X(INIT) -X(INIT_VALUE) -X(init) -X(initial_top) -X(interface_modport) -X(interfaces_replaced_in_module) -X(interface_type) -X(invertible_pin) -X(iopad_external_pin) -X(is_interface) -X(J) -X(K) -X(keep) -X(keep_hierarchy) -X(L) -X(lib_whitebox) -X(localparam) -X(logic_block) -X(lram) -X(LUT) -X(lut_keep) -X(M) -X(maximize) -X(mem2reg) -X(MEMID) -X(minimize) -X(module_not_derived) -X(N) -X(NAME) -X(noblackbox) -X(nolatches) -X(nomem2init) -X(nomem2reg) -X(nomeminit) -X(nosync) -X(nowrshmsk) -X(no_rw_check) -X(O) -X(OFFSET) -X(onehot) -X(P) -X(parallel_case) -X(parameter) -X(PORTID) -X(PRIORITY) -X(PRIORITY_MASK) -X(Q) -X(qwp_position) -X(R) -X(ram_block) -X(ram_style) -X(ramstyle) -X(RD_ADDR) -X(RD_ARST) -X(RD_ARST_VALUE) -X(RD_CE_OVER_SRST) -X(RD_CLK) -X(RD_CLK_ENABLE) -X(RD_CLK_POLARITY) -X(RD_COLLISION_X_MASK) -X(RD_DATA) -X(RD_EN) -X(RD_INIT_VALUE) -X(RD_PORTS) -X(RD_SRST) -X(RD_SRST_VALUE) -X(RD_TRANSPARENCY_MASK) -X(RD_TRANSPARENT) -X(RD_WIDE_CONTINUATION) -X(reg) -X(replaced_by_gclk) -X(reprocess_after) -X(rom_block) -X(rom_style) -X(romstyle) -X(S) -X(SET) -X(SET_POLARITY) -X(SIZE) -X(SRC) -X(src) -X(SRC_DST_PEN) -X(SRC_DST_POL) -X(SRC_EN) -X(SRC_PEN) -X(SRC_POL) -X(SRC_WIDTH) -X(SRST) -X(SRST_POLARITY) -X(SRST_VALUE) -X(sta_arrival) -X(STATE_BITS) -X(STATE_NUM) -X(STATE_NUM_LOG2) -X(STATE_RST) -X(STATE_TABLE) -X(smtlib2_module) -X(smtlib2_comb_expr) -X(submod) -X(syn_ramstyle) -X(syn_romstyle) -X(S_WIDTH) -X(T) -X(TABLE) -X(techmap_autopurge) -X(_TECHMAP_BITS_CONNMAP_) -X(_TECHMAP_CELLNAME_) -X(_TECHMAP_CELLTYPE_) -X(techmap_celltype) -X(_TECHMAP_FAIL_) -X(techmap_maccmap) -X(_TECHMAP_REPLACE_) -X(techmap_simplemap) -X(_techmap_special_) -X(techmap_wrap) -X(T_FALL_MAX) -X(T_FALL_MIN) -X(T_FALL_TYP) -X(T_LIMIT) -X(T_LIMIT2) -X(T_LIMIT2_MAX) -X(T_LIMIT2_MIN) -X(T_LIMIT2_TYP) -X(T_LIMIT_MAX) -X(T_LIMIT_MIN) -X(T_LIMIT_TYP) -X(to_delete) -X(top) -X(TRANS_NUM) -X(TRANSPARENCY_MASK) -X(TRANSPARENT) -X(TRANS_TABLE) -X(T_RISE_MAX) -X(T_RISE_MIN) -X(T_RISE_TYP) -X(TYPE) -X(U) -X(unique) -X(unused_bits) -X(V) -X(via_celltype) -X(wand) -X(whitebox) -X(WIDTH) -X(wildcard_port_conns) -X(wiretype) -X(wor) -X(WORDS) -X(WR_ADDR) -X(WR_CLK) -X(WR_CLK_ENABLE) -X(WR_CLK_POLARITY) -X(WR_DATA) -X(WR_EN) -X(WR_PORTS) -X(WR_PRIORITY_MASK) -X(WR_WIDE_CONTINUATION) -X(X) -X(xprop_decoder) -X(Y) -X(Y_WIDTH) diff --git a/yosys/kernel/cost.h b/yosys/kernel/cost.h deleted file mode 100644 index b81420af756..00000000000 --- a/yosys/kernel/cost.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 - -struct CellCosts -{ - static const dict& default_gate_cost() { - static const dict db = { - { ID($_BUF_), 1 }, - { ID($_NOT_), 2 }, - { ID($_AND_), 4 }, - { ID($_NAND_), 4 }, - { ID($_OR_), 4 }, - { ID($_NOR_), 4 }, - { ID($_ANDNOT_), 4 }, - { ID($_ORNOT_), 4 }, - { ID($_XOR_), 5 }, - { ID($_XNOR_), 5 }, - { ID($_AOI3_), 6 }, - { ID($_OAI3_), 6 }, - { ID($_AOI4_), 7 }, - { ID($_OAI4_), 7 }, - { ID($_MUX_), 4 }, - { ID($_NMUX_), 4 } - }; - return db; - } - - static const dict& cmos_gate_cost() { - static const dict db = { - { ID($_BUF_), 1 }, - { ID($_NOT_), 2 }, - { ID($_AND_), 6 }, - { ID($_NAND_), 4 }, - { ID($_OR_), 6 }, - { ID($_NOR_), 4 }, - { ID($_ANDNOT_), 6 }, - { ID($_ORNOT_), 6 }, - { ID($_XOR_), 12 }, - { ID($_XNOR_), 12 }, - { ID($_AOI3_), 6 }, - { ID($_OAI3_), 6 }, - { ID($_AOI4_), 8 }, - { ID($_OAI4_), 8 }, - { ID($_MUX_), 12 }, - { ID($_NMUX_), 10 } - }; - return db; - } - - dict mod_cost_cache; - const dict *gate_cost = nullptr; - Design *design = nullptr; - - int get(RTLIL::IdString type) const - { - if (gate_cost && gate_cost->count(type)) - return gate_cost->at(type); - - log_warning("Can't determine cost of %s cell.\n", log_id(type)); - return 1; - } - - int get(RTLIL::Cell *cell) - { - if (gate_cost && gate_cost->count(cell->type)) - return gate_cost->at(cell->type); - - if (design && design->module(cell->type) && cell->parameters.empty()) - { - RTLIL::Module *mod = design->module(cell->type); - - if (mod->attributes.count(ID(cost))) - return mod->attributes.at(ID(cost)).as_int(); - - 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(c); - - mod_cost_cache[mod->name] = module_cost; - return module_cost; - } - - log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters)); - return 1; - } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/driver.cc b/yosys/kernel/driver.cc deleted file mode 100644 index ef8e7792473..00000000000 --- a/yosys/kernel/driver.cc +++ /dev/null @@ -1,779 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 -#ifndef __STDC_FORMAT_MACROS -# define __STDC_FORMAT_MACROS -#endif -#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"); - } -} - -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 - -#if defined(__wasm) -extern "C" { - // FIXME: WASI does not currently support exceptions. - void* __cxa_allocate_exception(size_t thrown_size) throw() { - return malloc(thrown_size); - } - bool __cxa_uncaught_exception() throw(); - void __cxa_throw(void* thrown_exception, struct std::type_info * tinfo, void (*dest)(void*)) { - std::terminate(); - } -} -#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 -} - -#if defined(__OpenBSD__) -namespace Yosys { -extern char *yosys_argv0; -extern char yosys_path[PATH_MAX]; -}; -#endif -#ifdef YOSYS_ENABLE_TCL -namespace Yosys { - extern int yosys_tcl_iterp_init(Tcl_Interp *interp); - extern void yosys_tcl_activate_repl(); -}; -#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 = ""; - std::string topmodule = ""; - std::string perffile = ""; - bool scriptfile_tcl = false; - bool print_banner = true; - bool print_stats = true; - bool call_abort = false; - bool timing_details = false; - bool run_shell = true; - bool run_tcl_shell = 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"); -#ifdef YOSYS_ENABLE_TCL - 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(" -C\n"); - printf(" enters TCL interatcive shell mode\n"); -#endif - printf("\n"); - printf(" -p command\n"); - printf(" execute the commands (to chain commands, separate them with semicolon + whitespace: 'cmd1; cmd2')\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(" -r \n"); - printf(" elaborate command line arguments using the specified top module\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(" -x \n"); - printf(" do not print warnings for the specified experimental feature\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); - } - - if (argc == 2 && (!strcmp(argv[1], "-V") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version"))) - { - printf("%s\n", yosys_version_str); - exit(0); - } - - int opt; - while ((opt = getopt(argc, argv, "MXAQTVCSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:r:D:P:E:x:B:")) != -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"); - run_shell = false; - 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"); - run_shell = false; - break; - case 'h': - passes_commands.push_back(stringf("help %s", optarg)); - run_shell = false; - break; - case 'b': - backend_command = optarg; - run_shell = false; - break; - case 'p': - passes_commands.push_back(optarg); - run_shell = false; - break; - case 'o': - output_filename = optarg; - run_shell = false; - 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; - run_shell = false; - break; - case 'c': - scriptfile = optarg; - scriptfile_tcl = true; - run_shell = false; - break; - case 'W': - log_warn_regexes.push_back(YS_REGEX_COMPILE(optarg)); - break; - case 'w': - log_nowarn_regexes.push_back(YS_REGEX_COMPILE(optarg)); - break; - case 'e': - log_werror_regexes.push_back(YS_REGEX_COMPILE(optarg)); - break; - case 'r': - topmodule = optarg; - 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; - case 'x': - log_experimentals_ignored.insert(optarg); - break; - case 'B': - perffile = optarg; - break; - case 'C': - run_tcl_shell = true; - 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(__OpenBSD__) - // save the executable origin for proc_self_dirname() - yosys_argv0 = argv[0]; - realpath(yosys_argv0, yosys_path); -#endif - -#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 (!vlog_defines.empty()) { - std::string vdef_cmd = "read -define"; - for (auto vdef : vlog_defines) - vdef_cmd += " " + vdef; - run_pass(vdef_cmd); - } - - while (optind < argc) - if (run_frontend(argv[optind++], frontend_command)) - run_shell = false; - - if (!topmodule.empty()) - run_pass("hierarchy -top " + topmodule); - - 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"); - } - - for (auto it = passes_commands.begin(); it != passes_commands.end(); it++) - run_pass(*it); - - if (run_tcl_shell) { -#ifdef YOSYS_ENABLE_TCL - yosys_tcl_activate_repl(); - Tcl_Main(argc, argv, yosys_tcl_iterp_init); -#else - log_error("Can't exectue TCL shell: this version of yosys is not built with TCL support enabled.\n"); -#endif - } else { - if (run_shell) - shell(yosys_design); - else - run_backend(output_filename, backend_command); - } - - yosys_design->check(); - for (auto it : saved_designs) - it.second->check(); - for (auto it : pushed_designs) - it->check(); - - 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 (log_expect_no_warnings && log_warnings_count_noexpect) - log_error("Unexpected warnings found: %d unique messages, %d total, %d expected\n", GetSize(log_warnings), - log_warnings_count, log_warnings_count - log_warnings_count_noexpect); - - 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); - - if (!log_experimentals.empty()) - log("Warnings: %d experimental features used (not excluded with -x).\n", GetSize(log_experimentals)); - -#ifdef _WIN32 - log("End of script. Logfile hash: %s\n", hash.c_str()); -#else - std::string meminfo; - std::string stats_divider = ", "; - - struct rusage ru_buffer; - getrusage(RUSAGE_SELF, &ru_buffer); - if (yosys_design->scratchpad_get_bool("print_stats.include_children")) { - struct rusage ru_buffer_children; - getrusage(RUSAGE_CHILDREN, &ru_buffer_children); - ru_buffer.ru_utime.tv_sec += ru_buffer_children.ru_utime.tv_sec; - ru_buffer.ru_utime.tv_usec += ru_buffer_children.ru_utime.tv_usec; - ru_buffer.ru_stime.tv_sec += ru_buffer_children.ru_stime.tv_sec; - ru_buffer.ru_stime.tv_usec += ru_buffer_children.ru_stime.tv_usec; -#if defined(__linux__) || defined(__FreeBSD__) - ru_buffer.ru_maxrss = std::max(ru_buffer.ru_maxrss, ru_buffer_children.ru_maxrss); -#endif - } -#if defined(__linux__) || defined(__FreeBSD__) - meminfo = stringf(", MEM: %.2f MB peak", - ru_buffer.ru_maxrss / 1024.0); -#endif - 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(!perffile.empty()) - { - FILE *f = fopen(perffile.c_str(), "wt"); - if (f == nullptr) - log_error("Can't open performance log file for writing: %s\n", strerror(errno)); - - fprintf(f, "{\n"); - fprintf(f, " \"generator\": \"%s\",\n", yosys_version_str); - fprintf(f, " \"total_ns\": %" PRIu64 ",\n", total_ns); - fprintf(f, " \"passes\": {"); - - bool first = true; - for (auto it = timedat.rbegin(); it != timedat.rend(); it++) { - if (!first) - fprintf(f, ","); - fprintf(f, "\n \"%s\": {\n", std::get<2>(*it).c_str()); - fprintf(f, " \"runtime_ns\": %" PRIu64 ",\n", std::get<0>(*it)); - fprintf(f, " \"num_calls\": %u\n", std::get<1>(*it)); - fprintf(f, " }"); - first = false; - } - fprintf(f, "\n }\n}\n"); - } - } - -#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 - - log_check_expected(); - - 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/ff.cc b/yosys/kernel/ff.cc deleted file mode 100644 index 697ba734221..00000000000 --- a/yosys/kernel/ff.cc +++ /dev/null @@ -1,773 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 Marcelina Kościelnicka - * - * 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/ff.h" - -USING_YOSYS_NAMESPACE - -FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initvals, cell_->name) -{ - cell = cell_; - sig_q = cell->getPort(ID::Q); - width = GetSize(sig_q); - attributes = cell->attributes; - - if (initvals) - val_init = (*initvals)(sig_q); - - std::string type_str = cell->type.str(); - - if (cell->type.in(ID($anyinit), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) { - if (cell->type.in(ID($anyinit), ID($ff))) { - has_gclk = true; - sig_d = cell->getPort(ID::D); - if (cell->type == ID($anyinit)) { - is_anyinit = true; - log_assert(val_init.is_fully_undef()); - } - } else if (cell->type == ID($sr)) { - // No data input at all. - } else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) { - has_aload = true; - sig_aload = cell->getPort(ID::EN); - pol_aload = cell->getParam(ID::EN_POLARITY).as_bool(); - sig_ad = cell->getPort(ID::D); - } else { - has_clk = true; - sig_clk = cell->getPort(ID::CLK); - pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool(); - sig_d = cell->getPort(ID::D); - } - if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($aldffe), ID($sdffe), ID($sdffce))) { - has_ce = true; - sig_ce = cell->getPort(ID::EN); - pol_ce = cell->getParam(ID::EN_POLARITY).as_bool(); - } - if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) { - has_sr = true; - sig_clr = cell->getPort(ID::CLR); - sig_set = cell->getPort(ID::SET); - pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool(); - pol_set = cell->getParam(ID::SET_POLARITY).as_bool(); - } - if (cell->type.in(ID($aldff), ID($aldffe))) { - has_aload = true; - sig_aload = cell->getPort(ID::ALOAD); - pol_aload = cell->getParam(ID::ALOAD_POLARITY).as_bool(); - sig_ad = cell->getPort(ID::AD); - } - if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) { - has_arst = true; - sig_arst = cell->getPort(ID::ARST); - pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool(); - val_arst = cell->getParam(ID::ARST_VALUE); - } - if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) { - has_srst = true; - sig_srst = cell->getPort(ID::SRST); - pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool(); - val_srst = cell->getParam(ID::SRST_VALUE); - ce_over_srst = cell->type == ID($sdffce); - } - } else if (cell->type == ID($_FF_)) { - is_fine = true; - has_gclk = true; - sig_d = cell->getPort(ID::D); - } else if (type_str.substr(0, 5) == "$_SR_") { - is_fine = true; - has_sr = true; - pol_set = type_str[5] == 'P'; - pol_clr = type_str[6] == 'P'; - sig_set = cell->getPort(ID::S); - sig_clr = cell->getPort(ID::R); - } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[6] == 'P'; - sig_clk = cell->getPort(ID::C); - } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[7] == 'P'; - sig_clk = cell->getPort(ID::C); - has_ce = true; - pol_ce = type_str[8] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[6] == 'P'; - sig_clk = cell->getPort(ID::C); - has_arst = true; - pol_arst = type_str[7] == 'P'; - sig_arst = cell->getPort(ID::R); - val_arst = type_str[8] == '1' ? State::S1 : State::S0; - } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[7] == 'P'; - sig_clk = cell->getPort(ID::C); - has_arst = true; - pol_arst = type_str[8] == 'P'; - sig_arst = cell->getPort(ID::R); - val_arst = type_str[9] == '1' ? State::S1 : State::S0; - has_ce = true; - pol_ce = type_str[10] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 8) == "$_ALDFF_" && type_str.size() == 11) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[8] == 'P'; - sig_clk = cell->getPort(ID::C); - has_aload = true; - pol_aload = type_str[9] == 'P'; - sig_aload = cell->getPort(ID::L); - sig_ad = cell->getPort(ID::AD); - } else if (type_str.substr(0, 9) == "$_ALDFFE_" && type_str.size() == 13) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[9] == 'P'; - sig_clk = cell->getPort(ID::C); - has_aload = true; - pol_aload = type_str[10] == 'P'; - sig_aload = cell->getPort(ID::L); - sig_ad = cell->getPort(ID::AD); - has_ce = true; - pol_ce = type_str[11] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[8] == 'P'; - sig_clk = cell->getPort(ID::C); - has_sr = true; - pol_set = type_str[9] == 'P'; - pol_clr = type_str[10] == 'P'; - sig_set = cell->getPort(ID::S); - sig_clr = cell->getPort(ID::R); - } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[9] == 'P'; - sig_clk = cell->getPort(ID::C); - has_sr = true; - pol_set = type_str[10] == 'P'; - pol_clr = type_str[11] == 'P'; - sig_set = cell->getPort(ID::S); - sig_clr = cell->getPort(ID::R); - has_ce = true; - pol_ce = type_str[12] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[7] == 'P'; - sig_clk = cell->getPort(ID::C); - has_srst = true; - pol_srst = type_str[8] == 'P'; - sig_srst = cell->getPort(ID::R); - val_srst = type_str[9] == '1' ? State::S1 : State::S0; - } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[8] == 'P'; - sig_clk = cell->getPort(ID::C); - has_srst = true; - pol_srst = type_str[9] == 'P'; - sig_srst = cell->getPort(ID::R); - val_srst = type_str[10] == '1' ? State::S1 : State::S0; - has_ce = true; - pol_ce = type_str[11] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[9] == 'P'; - sig_clk = cell->getPort(ID::C); - has_srst = true; - pol_srst = type_str[10] == 'P'; - sig_srst = cell->getPort(ID::R); - val_srst = type_str[11] == '1' ? State::S1 : State::S0; - has_ce = true; - pol_ce = type_str[12] == 'P'; - sig_ce = cell->getPort(ID::E); - ce_over_srst = true; - } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) { - is_fine = true; - has_aload = true; - sig_ad = cell->getPort(ID::D); - has_aload = true; - pol_aload = type_str[9] == 'P'; - sig_aload = cell->getPort(ID::E); - } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) { - is_fine = true; - has_aload = true; - sig_ad = cell->getPort(ID::D); - has_aload = true; - pol_aload = type_str[9] == 'P'; - sig_aload = cell->getPort(ID::E); - has_arst = true; - pol_arst = type_str[10] == 'P'; - sig_arst = cell->getPort(ID::R); - val_arst = type_str[11] == '1' ? State::S1 : State::S0; - } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) { - is_fine = true; - has_aload = true; - sig_ad = cell->getPort(ID::D); - has_aload = true; - pol_aload = type_str[11] == 'P'; - sig_aload = cell->getPort(ID::E); - has_sr = true; - pol_set = type_str[12] == 'P'; - pol_clr = type_str[13] == 'P'; - sig_set = cell->getPort(ID::S); - sig_clr = cell->getPort(ID::R); - } else { - log_assert(0); - } - if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) { - // Plain D latches with const D treated specially. - has_aload = false; - has_arst = true; - sig_arst = sig_aload; - pol_arst = pol_aload; - val_arst = sig_ad.as_const(); - } -} - -FfData FfData::slice(const std::vector &bits) { - FfData res(module, initvals, NEW_ID); - res.sig_clk = sig_clk; - res.sig_ce = sig_ce; - res.sig_aload = sig_aload; - res.sig_arst = sig_arst; - res.sig_srst = sig_srst; - res.has_clk = has_clk; - res.has_gclk = has_gclk; - res.has_ce = has_ce; - res.has_aload = has_aload; - res.has_arst = has_arst; - res.has_srst = has_srst; - res.has_sr = has_sr; - res.ce_over_srst = ce_over_srst; - res.is_fine = is_fine; - res.is_anyinit = is_anyinit; - res.pol_clk = pol_clk; - res.pol_ce = pol_ce; - res.pol_aload = pol_aload; - res.pol_arst = pol_arst; - res.pol_srst = pol_srst; - res.pol_clr = pol_clr; - res.pol_set = pol_set; - res.attributes = attributes; - for (int i : bits) { - res.sig_q.append(sig_q[i]); - if (has_clk || has_gclk) - res.sig_d.append(sig_d[i]); - if (has_aload) - res.sig_ad.append(sig_ad[i]); - if (has_sr) { - res.sig_clr.append(sig_clr[i]); - res.sig_set.append(sig_set[i]); - } - if (has_arst) - res.val_arst.bits.push_back(val_arst[i]); - if (has_srst) - res.val_srst.bits.push_back(val_srst[i]); - if (initvals) - res.val_init.bits.push_back(val_init[i]); - } - res.width = GetSize(res.sig_q); - return res; -} - -void FfData::add_dummy_ce() { - if (has_ce) - return; - has_ce = true; - pol_ce = true; - sig_ce = State::S1; - ce_over_srst = false; -} - -void FfData::add_dummy_srst() { - if (has_srst) - return; - has_srst = true; - pol_srst = true; - sig_srst = State::S0; - val_srst = Const(State::Sx, width); - ce_over_srst = false; -} - -void FfData::add_dummy_arst() { - if (has_arst) - return; - has_arst = true; - pol_arst = true; - sig_arst = State::S0; - val_arst = Const(State::Sx, width); -} - -void FfData::add_dummy_aload() { - if (has_aload) - return; - has_aload = true; - pol_aload = true; - sig_aload = State::S0; - sig_ad = Const(State::Sx, width); -} - -void FfData::add_dummy_sr() { - if (has_sr) - return; - has_sr = true; - pol_clr = true; - pol_set = true; - sig_clr = Const(State::S0, width); - sig_set = Const(State::S0, width); -} - -void FfData::add_dummy_clk() { - if (has_clk) - return; - has_clk = true; - pol_clk = true; - sig_clk = State::S0; - sig_d = Const(State::Sx, width); -} - -void FfData::arst_to_aload() { - log_assert(has_arst); - log_assert(!has_aload); - pol_aload = pol_arst; - sig_aload = sig_arst; - sig_ad = val_arst; - has_aload = true; - has_arst = false; -} - -void FfData::arst_to_sr() { - log_assert(has_arst); - log_assert(!has_sr); - pol_clr = pol_arst; - pol_set = pol_arst; - sig_clr = Const(pol_arst ? State::S0 : State::S1, width); - sig_set = Const(pol_arst ? State::S0 : State::S1, width); - has_sr = true; - has_arst = false; - for (int i = 0; i < width; i++) { - if (val_arst[i] == State::S1) - sig_set[i] = sig_arst; - else - sig_clr[i] = sig_arst; - } -} - -void FfData::aload_to_sr() { - log_assert(has_aload); - log_assert(!has_sr); - has_sr = true; - has_aload = false; - if (!is_fine) { - pol_clr = false; - pol_set = true; - if (pol_aload) { - sig_clr = module->Mux(NEW_ID, Const(State::S1, width), sig_ad, sig_aload); - sig_set = module->Mux(NEW_ID, Const(State::S0, width), sig_ad, sig_aload); - } else { - sig_clr = module->Mux(NEW_ID, sig_ad, Const(State::S1, width), sig_aload); - sig_set = module->Mux(NEW_ID, sig_ad, Const(State::S0, width), sig_aload); - } - } else { - pol_clr = pol_aload; - pol_set = pol_aload; - if (pol_aload) { - sig_clr = module->AndnotGate(NEW_ID, sig_aload, sig_ad); - sig_set = module->AndGate(NEW_ID, sig_aload, sig_ad); - } else { - sig_clr = module->OrGate(NEW_ID, sig_aload, sig_ad); - sig_set = module->OrnotGate(NEW_ID, sig_aload, sig_ad); - } - } -} - -void FfData::convert_ce_over_srst(bool val) { - if (!has_ce || !has_srst || ce_over_srst == val) - return; - if (val) { - // sdffe to sdffce - if (!is_fine) { - if (pol_ce) { - if (pol_srst) { - sig_ce = module->Or(NEW_ID, sig_ce, sig_srst); - } else { - SigSpec tmp = module->Not(NEW_ID, sig_srst); - sig_ce = module->Or(NEW_ID, sig_ce, tmp); - } - } else { - if (pol_srst) { - SigSpec tmp = module->Not(NEW_ID, sig_srst); - sig_ce = module->And(NEW_ID, sig_ce, tmp); - } else { - sig_ce = module->And(NEW_ID, sig_ce, sig_srst); - } - } - } else { - if (pol_ce) { - if (pol_srst) { - sig_ce = module->OrGate(NEW_ID, sig_ce, sig_srst); - } else { - sig_ce = module->OrnotGate(NEW_ID, sig_ce, sig_srst); - } - } else { - if (pol_srst) { - sig_ce = module->AndnotGate(NEW_ID, sig_ce, sig_srst); - } else { - sig_ce = module->AndGate(NEW_ID, sig_ce, sig_srst); - } - } - } - } else { - // sdffce to sdffe - if (!is_fine) { - if (pol_srst) { - if (pol_ce) { - sig_srst = cell->module->And(NEW_ID, sig_srst, sig_ce); - } else { - SigSpec tmp = module->Not(NEW_ID, sig_ce); - sig_srst = cell->module->And(NEW_ID, sig_srst, tmp); - } - } else { - if (pol_ce) { - SigSpec tmp = module->Not(NEW_ID, sig_ce); - sig_srst = cell->module->Or(NEW_ID, sig_srst, tmp); - } else { - sig_srst = cell->module->Or(NEW_ID, sig_srst, sig_ce); - } - } - } else { - if (pol_srst) { - if (pol_ce) { - sig_srst = cell->module->AndGate(NEW_ID, sig_srst, sig_ce); - } else { - sig_srst = cell->module->AndnotGate(NEW_ID, sig_srst, sig_ce); - } - } else { - if (pol_ce) { - sig_srst = cell->module->OrnotGate(NEW_ID, sig_srst, sig_ce); - } else { - sig_srst = cell->module->OrGate(NEW_ID, sig_srst, sig_ce); - } - } - } - } - ce_over_srst = val; -} - -void FfData::unmap_ce() { - if (!has_ce) - return; - log_assert(has_clk); - if (has_srst && ce_over_srst) - unmap_srst(); - - if (!is_fine) { - if (pol_ce) - sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce); - else - sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce); - } else { - if (pol_ce) - sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce); - else - sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce); - } - has_ce = false; -} - -void FfData::unmap_srst() { - if (!has_srst) - return; - if (has_ce && !ce_over_srst) - unmap_ce(); - - if (!is_fine) { - if (pol_srst) - sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst); - else - sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst); - } else { - if (pol_srst) - sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst); - else - sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst); - } - has_srst = false; -} - -Cell *FfData::emit() { - remove(); - if (!width) - return nullptr; - if (!has_aload && !has_clk && !has_gclk && !has_sr) { - if (has_arst) { - // Convert this case to a D latch. - arst_to_aload(); - } else { - // No control inputs left. Turn into a const driver. - module->connect(sig_q, val_init); - return nullptr; - } - } - if (initvals && !is_anyinit) - initvals->set_init(sig_q, val_init); - if (!is_fine) { - if (has_gclk) { - log_assert(!has_clk); - log_assert(!has_ce); - log_assert(!has_aload); - log_assert(!has_arst); - log_assert(!has_srst); - log_assert(!has_sr); - if (is_anyinit) { - cell = module->addAnyinit(name, sig_d, sig_q); - log_assert(val_init.is_fully_undef()); - } else { - cell = module->addFf(name, sig_d, sig_q); - } - } else if (!has_aload && !has_clk) { - log_assert(has_sr); - cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr); - } else if (!has_clk) { - log_assert(!has_srst); - if (has_sr) - cell = module->addDlatchsr(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr); - else if (has_arst) - cell = module->addAdlatch(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst, pol_aload, pol_arst); - else - cell = module->addDlatch(name, sig_aload, sig_ad, sig_q, pol_aload); - } else { - if (has_sr) { - if (has_ce) - cell = module->addDffsre(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr); - else - cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr); - } else if (has_arst) { - if (has_ce) - cell = module->addAdffe(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_ce, pol_arst); - else - cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst); - } else if (has_aload) { - if (has_ce) - cell = module->addAldffe(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload); - else - cell = module->addAldff(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload); - } else if (has_srst) { - if (has_ce) - if (ce_over_srst) - cell = module->addSdffce(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst); - else - cell = module->addSdffe(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst); - else - cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst); - } else { - if (has_ce) - cell = module->addDffe(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce); - else - cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk); - } - } - } else { - if (has_gclk) { - log_assert(!has_clk); - log_assert(!has_ce); - log_assert(!has_aload); - log_assert(!has_arst); - log_assert(!has_srst); - log_assert(!has_sr); - log_assert(!is_anyinit); - cell = module->addFfGate(name, sig_d, sig_q); - } else if (!has_aload && !has_clk) { - log_assert(has_sr); - cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr); - } else if (!has_clk) { - log_assert(!has_srst); - if (has_sr) - cell = module->addDlatchsrGate(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr); - else if (has_arst) - cell = module->addAdlatchGate(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst.as_bool(), pol_aload, pol_arst); - else - cell = module->addDlatchGate(name, sig_aload, sig_ad, sig_q, pol_aload); - } else { - if (has_sr) { - if (has_ce) - cell = module->addDffsreGate(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr); - else - cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr); - } else if (has_arst) { - if (has_ce) - cell = module->addAdffeGate(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_ce, pol_arst); - else - cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst); - } else if (has_aload) { - if (has_ce) - cell = module->addAldffeGate(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload); - else - cell = module->addAldffGate(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload); - } else if (has_srst) { - if (has_ce) - if (ce_over_srst) - cell = module->addSdffceGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst); - else - cell = module->addSdffeGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst); - else - cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst); - } else { - if (has_ce) - cell = module->addDffeGate(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce); - else - cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk); - } - } - } - cell->attributes = attributes; - return cell; -} - -void FfData::remove() { - if (cell) { - remove_init(); - module->remove(cell); - cell = nullptr; - } -} - -namespace { - State invert(State s) { - switch (s) { - case State::S0: return State::S1; - case State::S1: return State::S0; - default: return s; - } - } -} - -void FfData::flip_rst_bits(const pool &bits) { - if (!bits.size()) - return; - - remove_init(); - - for (auto bit: bits) { - if (has_arst) - val_arst[bit] = invert(val_arst[bit]); - if (has_srst) - val_srst[bit] = invert(val_srst[bit]); - val_init[bit] = invert(val_init[bit]); - } -} - -void FfData::flip_bits(const pool &bits) { - if (!bits.size()) - return; - - flip_rst_bits(bits); - - Wire *new_q = module->addWire(NEW_ID, width); - - if (has_sr && cell) { - log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].\n", log_id(module->name), log_id(cell->name), log_id(cell->type)); - } - - if (is_fine) { - if (has_sr) { - bool new_pol_clr = pol_set; - SigSpec new_sig_clr; - if (pol_set) { - if (pol_clr) { - new_sig_clr = module->AndnotGate(NEW_ID, sig_set, sig_clr); - } else { - new_sig_clr = module->AndGate(NEW_ID, sig_set, sig_clr); - } - } else { - if (pol_clr) { - new_sig_clr = module->OrGate(NEW_ID, sig_set, sig_clr); - } else { - new_sig_clr = module->OrnotGate(NEW_ID, sig_set, sig_clr); - } - } - pol_set = pol_clr; - sig_set = sig_clr; - pol_clr = new_pol_clr; - sig_clr = new_sig_clr; - } - if (has_clk || has_gclk) - sig_d = module->NotGate(NEW_ID, sig_d); - if (has_aload) - sig_ad = module->NotGate(NEW_ID, sig_ad); - module->addNotGate(NEW_ID, new_q, sig_q); - } - else - { - if (has_sr) { - SigSpec not_clr; - if (!pol_clr) { - not_clr = sig_clr; - sig_clr = module->Not(NEW_ID, sig_clr); - pol_clr = true; - } else { - not_clr = module->Not(NEW_ID, sig_clr); - } - if (!pol_set) { - sig_set = module->Not(NEW_ID, sig_set); - pol_set = true; - } - - SigSpec masked_set = module->And(NEW_ID, sig_set, not_clr); - for (auto bit: bits) { - sig_set[bit] = sig_clr[bit]; - sig_clr[bit] = masked_set[bit]; - } - } - - Const mask = Const(State::S0, width); - for (auto bit: bits) - mask.bits[bit] = State::S1; - - if (has_clk || has_gclk) - sig_d = module->Xor(NEW_ID, sig_d, mask); - if (has_aload) - sig_ad = module->Xor(NEW_ID, sig_ad, mask); - module->addXor(NEW_ID, new_q, mask, sig_q); - } - - sig_q = new_q; -} diff --git a/yosys/kernel/ff.h b/yosys/kernel/ff.h deleted file mode 100644 index e684d3c4314..00000000000 --- a/yosys/kernel/ff.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 Marcelina Kościelnicka - * - * 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 FF_H -#define FF_H - -#include "kernel/yosys.h" -#include "kernel/ffinit.h" - -YOSYS_NAMESPACE_BEGIN - -// Describes a flip-flop or a latch. -// -// If has_gclk, this is a formal verification FF with implicit global clock: -// Q is simply previous cycle's D. Additionally if is_anyinit is true, this is -// an $anyinit cell which always has an undefined initialization value. Note -// that $anyinit is not considered to be among the FF celltypes, so a pass has -// to explicitly opt-in to process $anyinit cells with FfData. -// -// Otherwise, the FF/latch can have any number of features selected by has_* -// attributes that determine Q's value (in order of decreasing priority): -// -// - on start, register is initialized to val_init -// - if has_sr is present: -// - sig_clr is per-bit async clear, and sets the corresponding bit to 0 -// if active -// - sig_set is per-bit async set, and sets the corresponding bit to 1 -// if active -// - if has_arst is present: -// - sig_arst is whole-reg async reset, and sets the whole register to val_arst -// - if has_aload is present: -// - sig_aload is whole-reg async load (aka latch gate enable), and sets the whole -// register to sig_ad -// - if has_clk is present, and we're currently on a clock edge: -// - if has_ce is present and ce_over_srst is true: -// - ignore clock edge (don't change value) unless sig_ce is active -// - if has_srst is present: -// - sig_srst is whole-reg sync reset and sets the register to val_srst -// - if has_ce is present and ce_over_srst is false: -// - ignore clock edge (don't change value) unless sig_ce is active -// - set whole reg to sig_d -// - if nothing of the above applies, the reg value remains unchanged -// -// Since the yosys FF cell library isn't fully generic, not all combinations -// of the features above can be supported: -// -// - only one of has_srst, has_arst, has_sr can be used -// - if has_clk is used together with has_aload, then has_srst, has_arst, -// has_sr cannot be used -// -// The valid feature combinations are thus: -// -// - has_clk + optional has_ce [dff/dffe] -// - has_clk + optional has_ce + has_arst [adff/adffe] -// - has_clk + optional has_ce + has_aload [aldff/aldffe] -// - has_clk + optional has_ce + has_sr [dffsr/dffsre] -// - has_clk + optional has_ce + has_srst [sdff/sdffe/sdffce] -// - has_aload [dlatch] -// - has_aload + has_arst [adlatch] -// - has_aload + has_sr [dlatchsr] -// - has_sr [sr] -// - has_arst [does not correspond to a native cell, represented as dlatch with const D input] -// - empty set [not a cell — will be emitted as a simple direct connection] - -struct FfData { - Module *module; - FfInitVals *initvals; - Cell *cell; - IdString name; - // The FF output. - SigSpec sig_q; - // The sync data input, present if has_clk or has_gclk. - SigSpec sig_d; - // The async data input, present if has_aload. - SigSpec sig_ad; - // The sync clock, present if has_clk. - SigSpec sig_clk; - // The clock enable, present if has_ce. - SigSpec sig_ce; - // The async load enable, present if has_aload. - SigSpec sig_aload; - // The async reset, preset if has_arst. - SigSpec sig_arst; - // The sync reset, preset if has_srst. - SigSpec sig_srst; - // The async clear (per-lane), present if has_sr. - SigSpec sig_clr; - // The async set (per-lane), present if has_sr. - SigSpec sig_set; - // True if this is a clocked (edge-sensitive) flip-flop. - bool has_clk; - // True if this is a $ff, exclusive with every other has_*. - bool has_gclk; - // True if this FF has a clock enable. Depends on has_clk. - bool has_ce; - // True if this FF has async load function — this includes D latches. - // If this and has_clk are both set, has_arst and has_sr cannot be set. - bool has_aload; - // True if this FF has sync set/reset. Depends on has_clk, exclusive - // with has_arst, has_sr, has_aload. - bool has_srst; - // True if this FF has async set/reset. Exclusive with has_srst, - // has_sr. If this and has_clk are both set, has_aload cannot be set. - bool has_arst; - // True if this FF has per-bit async set + clear. Exclusive with - // has_srst, has_arst. If this and has_clk are both set, has_aload - // cannot be set. - bool has_sr; - // If has_ce and has_srst are both set, determines their relative - // priorities: if true, inactive ce disables srst; if false, srst - // operates independent of ce. - bool ce_over_srst; - // True if this FF is a fine cell, false if it is a coarse cell. - // If true, width must be 1. - bool is_fine; - // True if this FF is an $anyinit cell. Depends on has_gclk. - bool is_anyinit; - // Polarities, corresponding to sig_*. True means active-high, false - // means active-low. - bool pol_clk; - bool pol_ce; - bool pol_aload; - bool pol_arst; - bool pol_srst; - bool pol_clr; - bool pol_set; - // The value loaded by sig_arst. - Const val_arst; - // The value loaded by sig_srst. - Const val_srst; - // The initial value at power-up. - Const val_init; - // The FF data width in bits. - int width; - dict attributes; - - FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) { - width = 0; - has_clk = false; - has_gclk = false; - has_ce = false; - has_aload = false; - has_srst = false; - has_arst = false; - has_sr = false; - ce_over_srst = false; - is_fine = false; - is_anyinit = false; - pol_clk = false; - pol_aload = false; - pol_ce = false; - pol_arst = false; - pol_srst = false; - pol_clr = false; - pol_set = false; - } - - FfData(FfInitVals *initvals, Cell *cell_); - - // Returns a FF identical to this one, but only keeping bit indices from the argument. - FfData slice(const std::vector &bits); - - void add_dummy_ce(); - void add_dummy_srst(); - void add_dummy_arst(); - void add_dummy_aload(); - void add_dummy_sr(); - void add_dummy_clk(); - - void arst_to_aload(); - void arst_to_sr(); - - void aload_to_sr(); - - // Given a FF with both has_ce and has_srst, sets ce_over_srst to the given value and - // fixes up control signals appropriately to preserve semantics. - void convert_ce_over_srst(bool val); - - void unmap_ce(); - void unmap_srst(); - - void unmap_ce_srst() { - unmap_ce(); - unmap_srst(); - } - - Cell *emit(); - - // Removes init attribute from the Q output, but keeps val_init unchanged. - // It will be automatically reattached on emit. Use this before changing sig_q. - void remove_init() { - if (initvals) - initvals->remove_init(sig_q); - } - - void remove(); - - // Flip the sense of the given bit slices of the FF: insert inverters on data - // inputs and output, flip the corresponding init/reset bits, swap clr/set - // inputs with proper priority fix. - void flip_bits(const pool &bits); - - void flip_rst_bits(const pool &bits); -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/ffinit.h b/yosys/kernel/ffinit.h deleted file mode 100644 index 9d33ac572d3..00000000000 --- a/yosys/kernel/ffinit.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 Marcelina Kościelnicka - * - * 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 FFINIT_H -#define FFINIT_H - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -YOSYS_NAMESPACE_BEGIN - -struct FfInitVals -{ - const SigMap *sigmap; - dict> initbits; - - void set(const SigMap *sigmap_, RTLIL::Module *module) - { - sigmap = sigmap_; - initbits.clear(); - for (auto wire : module->wires()) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec wirebits = (*sigmap)(wire); - Const initval = wire->attributes.at(ID::init); - - for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) - { - SigBit bit = wirebits[i]; - State val = initval[i]; - - if (val != State::S0 && val != State::S1 && bit.wire != nullptr) - continue; - - if (initbits.count(bit)) { - if (initbits.at(bit).first != val) - log_error("Conflicting init values for signal %s (%s = %s != %s).\n", - log_signal(bit), log_signal(SigBit(wire, i)), - log_signal(val), log_signal(initbits.at(bit).first)); - continue; - } - - initbits[bit] = std::make_pair(val,SigBit(wire,i)); - } - } - } - - RTLIL::State operator()(RTLIL::SigBit bit) const - { - auto it = initbits.find((*sigmap)(bit)); - if (it != initbits.end()) - return it->second.first; - else - return State::Sx; - } - - RTLIL::Const operator()(const RTLIL::SigSpec &sig) const - { - RTLIL::Const res; - for (auto bit : sig) - res.bits.push_back((*this)(bit)); - return res; - } - - void set_init(RTLIL::SigBit bit, RTLIL::State val) - { - SigBit mbit = (*sigmap)(bit); - SigBit abit = bit; - auto it = initbits.find(mbit); - if (it != initbits.end()) - abit = it->second.second; - else if (val == State::Sx) - return; - log_assert(abit.wire); - initbits[mbit] = std::make_pair(val,abit); - auto it2 = abit.wire->attributes.find(ID::init); - if (it2 != abit.wire->attributes.end()) { - it2->second[abit.offset] = val; - if (it2->second.is_fully_undef()) - abit.wire->attributes.erase(it2); - } else if (val != State::Sx) { - Const cval(State::Sx, GetSize(abit.wire)); - cval[abit.offset] = val; - abit.wire->attributes[ID::init] = cval; - } - } - - void set_init(const RTLIL::SigSpec &sig, RTLIL::Const val) - { - log_assert(GetSize(sig) == GetSize(val)); - for (int i = 0; i < GetSize(sig); i++) - set_init(sig[i], val[i]); - } - - void remove_init(RTLIL::SigBit bit) - { - set_init(bit, State::Sx); - } - - void remove_init(const RTLIL::SigSpec &sig) - { - for (auto bit : sig) - remove_init(bit); - } - - void clear() - { - initbits.clear(); - } - - FfInitVals (const SigMap *sigmap, RTLIL::Module *module) - { - set(sigmap, module); - } - - FfInitVals () {} -}; - - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/ffmerge.cc b/yosys/kernel/ffmerge.cc deleted file mode 100644 index c6510841391..00000000000 --- a/yosys/kernel/ffmerge.cc +++ /dev/null @@ -1,359 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2021 Marcelina Kościelnicka - * - * 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/ffmerge.h" - -USING_YOSYS_NAMESPACE - -bool FfMergeHelper::is_output_unused(RTLIL::SigSpec sig) { - for (auto bit : (*sigmap)(sig)) - if (sigbit_users_count[bit] != 0) - return false; - return true; -} - -bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits) { - ff = FfData(module, initvals, NEW_ID); - sigmap->apply(sig); - - bool found = false; - - for (auto bit : sig) - { - if (bit.wire == NULL || sigbit_users_count[bit] == 0) { - ff.width++; - ff.sig_q.append(bit); - ff.sig_d.append(bit); - ff.sig_clr.append(State::Sx); - ff.sig_set.append(State::Sx); - ff.val_init.bits.push_back(State::Sx); - ff.val_srst.bits.push_back(State::Sx); - ff.val_arst.bits.push_back(State::Sx); - continue; - } - - if (sigbit_users_count[bit] != 1) - return false; - - auto &sinks = dff_sink[bit]; - if (sinks.size() != 1) - return false; - - Cell *cell; - int idx; - std::tie(cell, idx) = *sinks.begin(); - bits.insert(std::make_pair(cell, idx)); - - FfData cur_ff(initvals, cell); - - // Reject latches and $ff. - if (!cur_ff.has_clk) - return false; - - log_assert((*sigmap)(cur_ff.sig_d[idx]) == bit); - - if (!found) { - ff.sig_clk = cur_ff.sig_clk; - ff.sig_ce = cur_ff.sig_ce; - ff.sig_aload = cur_ff.sig_aload; - ff.sig_srst = cur_ff.sig_srst; - ff.sig_arst = cur_ff.sig_arst; - ff.has_clk = cur_ff.has_clk; - ff.has_ce = cur_ff.has_ce; - ff.has_aload = cur_ff.has_aload; - ff.has_srst = cur_ff.has_srst; - ff.has_arst = cur_ff.has_arst; - ff.has_sr = cur_ff.has_sr; - ff.ce_over_srst = cur_ff.ce_over_srst; - ff.pol_clk = cur_ff.pol_clk; - ff.pol_ce = cur_ff.pol_ce; - ff.pol_aload = cur_ff.pol_aload; - ff.pol_arst = cur_ff.pol_arst; - ff.pol_srst = cur_ff.pol_srst; - ff.pol_clr = cur_ff.pol_clr; - ff.pol_set = cur_ff.pol_set; - } else { - if (ff.has_clk != cur_ff.has_clk) - return false; - if (ff.has_ce != cur_ff.has_ce) - return false; - if (ff.has_aload != cur_ff.has_aload) - return false; - if (ff.has_srst != cur_ff.has_srst) - return false; - if (ff.has_arst != cur_ff.has_arst) - return false; - if (ff.has_sr != cur_ff.has_sr) - return false; - if (ff.has_clk) { - if (ff.sig_clk != cur_ff.sig_clk) - return false; - if (ff.pol_clk != cur_ff.pol_clk) - return false; - } - if (ff.has_ce) { - if (ff.sig_ce != cur_ff.sig_ce) - return false; - if (ff.pol_ce != cur_ff.pol_ce) - return false; - } - if (ff.has_aload) { - if (ff.sig_aload != cur_ff.sig_aload) - return false; - if (ff.pol_aload != cur_ff.pol_aload) - return false; - } - if (ff.has_srst) { - if (ff.sig_srst != cur_ff.sig_srst) - return false; - if (ff.pol_srst != cur_ff.pol_srst) - return false; - if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst) - return false; - } - if (ff.has_arst) { - if (ff.sig_arst != cur_ff.sig_arst) - return false; - if (ff.pol_arst != cur_ff.pol_arst) - return false; - } - if (ff.has_sr) { - if (ff.pol_clr != cur_ff.pol_clr) - return false; - if (ff.pol_set != cur_ff.pol_set) - return false; - } - } - - ff.width++; - ff.sig_d.append(cur_ff.sig_d[idx]); - ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx); - ff.sig_q.append(cur_ff.sig_q[idx]); - ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0); - ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0); - ff.val_arst.bits.push_back(ff.has_arst ? cur_ff.val_arst[idx] : State::Sx); - ff.val_srst.bits.push_back(ff.has_srst ? cur_ff.val_srst[idx] : State::Sx); - ff.val_init.bits.push_back(cur_ff.val_init[idx]); - found = true; - } - - return found; -} - -bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits) { - ff = FfData(module, initvals, NEW_ID); - sigmap->apply(sig); - - bool found = false; - - pool const_bits; - - for (auto bit : sig) - { - if (bit.wire == NULL) { - const_bits.insert(ff.width); - ff.width++; - ff.sig_q.append(bit); - ff.sig_d.append(bit); - // These two will be fixed up later. - ff.sig_clr.append(State::Sx); - ff.sig_set.append(State::Sx); - ff.val_init.bits.push_back(bit.data); - ff.val_srst.bits.push_back(bit.data); - ff.val_arst.bits.push_back(bit.data); - continue; - } - - if (!dff_driver.count(bit)) - return false; - - Cell *cell; - int idx; - std::tie(cell, idx) = dff_driver[bit]; - bits.insert(std::make_pair(cell, idx)); - - FfData cur_ff(initvals, cell); - - log_assert((*sigmap)(cur_ff.sig_q[idx]) == bit); - - if (!found) { - ff.sig_clk = cur_ff.sig_clk; - ff.sig_ce = cur_ff.sig_ce; - ff.sig_aload = cur_ff.sig_aload; - ff.sig_srst = cur_ff.sig_srst; - ff.sig_arst = cur_ff.sig_arst; - ff.has_clk = cur_ff.has_clk; - ff.has_gclk = cur_ff.has_gclk; - ff.has_ce = cur_ff.has_ce; - ff.has_aload = cur_ff.has_aload; - ff.has_srst = cur_ff.has_srst; - ff.has_arst = cur_ff.has_arst; - ff.has_sr = cur_ff.has_sr; - ff.ce_over_srst = cur_ff.ce_over_srst; - ff.pol_clk = cur_ff.pol_clk; - ff.pol_ce = cur_ff.pol_ce; - ff.pol_aload = cur_ff.pol_aload; - ff.pol_arst = cur_ff.pol_arst; - ff.pol_srst = cur_ff.pol_srst; - ff.pol_clr = cur_ff.pol_clr; - ff.pol_set = cur_ff.pol_set; - } else { - if (ff.has_gclk != cur_ff.has_gclk) - return false; - if (ff.has_clk != cur_ff.has_clk) - return false; - if (ff.has_ce != cur_ff.has_ce) - return false; - if (ff.has_aload != cur_ff.has_aload) - return false; - if (ff.has_srst != cur_ff.has_srst) - return false; - if (ff.has_arst != cur_ff.has_arst) - return false; - if (ff.has_sr != cur_ff.has_sr) - return false; - if (ff.has_clk) { - if (ff.sig_clk != cur_ff.sig_clk) - return false; - if (ff.pol_clk != cur_ff.pol_clk) - return false; - } - if (ff.has_ce) { - if (ff.sig_ce != cur_ff.sig_ce) - return false; - if (ff.pol_ce != cur_ff.pol_ce) - return false; - } - if (ff.has_aload) { - if (ff.sig_aload != cur_ff.sig_aload) - return false; - if (ff.pol_aload != cur_ff.pol_aload) - return false; - } - if (ff.has_srst) { - if (ff.sig_srst != cur_ff.sig_srst) - return false; - if (ff.pol_srst != cur_ff.pol_srst) - return false; - if (ff.has_ce && ff.ce_over_srst != cur_ff.ce_over_srst) - return false; - } - if (ff.has_arst) { - if (ff.sig_arst != cur_ff.sig_arst) - return false; - if (ff.pol_arst != cur_ff.pol_arst) - return false; - } - if (ff.has_sr) { - if (ff.pol_clr != cur_ff.pol_clr) - return false; - if (ff.pol_set != cur_ff.pol_set) - return false; - } - } - - ff.width++; - ff.sig_d.append((ff.has_clk || ff.has_gclk) ? cur_ff.sig_d[idx] : State::Sx); - ff.sig_ad.append(ff.has_aload ? cur_ff.sig_ad[idx] : State::Sx); - ff.sig_q.append(cur_ff.sig_q[idx]); - ff.sig_clr.append(ff.has_sr ? cur_ff.sig_clr[idx] : State::S0); - ff.sig_set.append(ff.has_sr ? cur_ff.sig_set[idx] : State::S0); - ff.val_arst.bits.push_back(ff.has_arst ? cur_ff.val_arst[idx] : State::Sx); - ff.val_srst.bits.push_back(ff.has_srst ? cur_ff.val_srst[idx] : State::Sx); - ff.val_init.bits.push_back(cur_ff.val_init[idx]); - found = true; - } - - if (found && ff.has_sr) { - for (auto i: const_bits) { - if (ff.sig_d[i] == State::S0) { - ff.sig_set[i] = ff.pol_set ? State::S0 : State::S1; - } else if (ff.sig_d[i] == State::S1) { - ff.sig_clr[i] = ff.pol_clr ? State::S0 : State::S1; - } - } - } - - return found; -} - - -void FfMergeHelper::remove_output_ff(const pool> &bits) { - for (auto &it : bits) { - Cell *cell = it.first; - int idx = it.second; - SigSpec q = cell->getPort(ID::Q); - initvals->remove_init(q[idx]); - dff_driver.erase((*sigmap)(q[idx])); - q[idx] = module->addWire(stringf("$ffmerge_disconnected$%d", autoidx++)); - cell->setPort(ID::Q, q); - } -} - -void FfMergeHelper::mark_input_ff(const pool> &bits) { - for (auto &it : bits) { - Cell *cell = it.first; - int idx = it.second; - if (cell->hasPort(ID::D)) { - SigSpec d = cell->getPort(ID::D); - // The user count was already at least 1 - // (for the D port). Bump it as it is now connected - // to the merged-to cell as well. This suffices for - // it to not be considered for output merging. - sigbit_users_count[d[idx]]++; - } - } -} - -void FfMergeHelper::set(FfInitVals *initvals_, RTLIL::Module *module_) -{ - clear(); - initvals = initvals_; - sigmap = initvals->sigmap; - module = module_; - - for (auto wire : module->wires()) { - if (wire->port_output) - for (auto bit : (*sigmap)(wire)) - sigbit_users_count[bit]++; - } - - for (auto cell : module->cells()) { - if (RTLIL::builtin_ff_cell_types().count(cell->type)) { - if (cell->hasPort(ID::D)) { - SigSpec d = (*sigmap)(cell->getPort(ID::D)); - for (int i = 0; i < GetSize(d); i++) - dff_sink[d[i]].insert(std::make_pair(cell, i)); - } - SigSpec q = (*sigmap)(cell->getPort(ID::Q)); - for (int i = 0; i < GetSize(q); i++) - dff_driver[q[i]] = std::make_pair(cell, i); - } - for (auto &conn : cell->connections()) - if (!cell->known() || cell->input(conn.first)) - for (auto bit : (*sigmap)(conn.second)) - sigbit_users_count[bit]++; - } -} - -void FfMergeHelper::clear() { - dff_driver.clear(); - dff_sink.clear(); - sigbit_users_count.clear(); -} diff --git a/yosys/kernel/ffmerge.h b/yosys/kernel/ffmerge.h deleted file mode 100644 index 5428da324a5..00000000000 --- a/yosys/kernel/ffmerge.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2021 Marcelina Kościelnicka - * - * 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 FFMERGE_H -#define FFMERGE_H - -#include "kernel/ffinit.h" -#include "kernel/ff.h" - -YOSYS_NAMESPACE_BEGIN - -// A helper class for passes that want to merge FFs on the input or output -// of a cell into the cell itself. -// -// The procedure is: -// -// 1. Construct this class (at beginning of processing for a given module). -// 2. For every considered cell: -// -// a. Call find_output_ff for every considered output. -// b. Call find_input_ff for every considered input. -// c. Look at the FF description returned (if any) from each call, reject -// results that cannot be merged into given cell for any reason. -// If both inputs and outputs are being merged, take care of FF bits that -// are returned in both input and output results (a FF bit cannot be -// merged to both). Decide on the final set of FF bits to merge. -// d. Call remove_output_ff for every find_output_ff result that will be used -// for merging. This removes the actual FF bits from design and from index. -// e. Call mark_input_ff for every find_input_ff result that will be used -// for merging. This updates the index disallowing further usage of these -// FF bits for output FF merging, if they were eligible before. The actual -// FF bits are still left in the design and can be merged into other inputs. -// If the FF bits are not otherwise used, they will be removed by later -// opt passes. -// f. Merge the FFs into the cell. -// -// Note that, if both inputs and outputs are being considered for merging in -// a single pass, the result may be nondeterministic (depending on cell iteration -// order) because a given FF bit could be eligible for both input and output merge, -// perhaps in different cells. For this reason, it may be a good idea to separate -// input and output merging. - -struct FfMergeHelper -{ - const SigMap *sigmap; - RTLIL::Module *module; - FfInitVals *initvals; - - dict> dff_driver; - dict>> dff_sink; - dict sigbit_users_count; - - // Returns true if all bits in sig are completely unused. - bool is_output_unused(RTLIL::SigSpec sig); - - // Finds the FF to merge into a given cell output. Takes sig, which - // is the current cell output — it will be the sig_d of the found FF. - // If found, returns true, and fills the two output arguments. - // - // For every bit of sig, this function finds a FF bit that has - // the same sig_d, and fills the output FfData according to the FF - // bits found. This function will only consider FF bits that are - // the only user of the given sig bits — if any bit in sig is used - // by anything other than a single FF, this function will return false. - // - // The returned FfData structure does not correspond to any actual FF - // cell in the design — it is the amalgamation of extracted FF bits, - // possibly coming from several FF cells. - // - // If some of the bits in sig have no users at all, this function - // will accept them as well (and fill returned FfData with dummy values - // for the given bit, effectively synthesizing an unused FF bit of the - // appropriate type). However, if all bits in sig are completely - // unused, this function will fail and return false (having no idea - // what kind of FF to produce) — use the above helper if that case - // is important to handle. - // - // Note that this function does not remove the FF bits returned from - // the design — this is so that the caller can decide whether to accept - // this FF for merging or not. If the result is accepted, - // remove_output_ff should be called on the second output argument. - bool find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits); - - // Like above, but returns a FF to merge into a given cell input. Takes - // sig_q, which is the current cell input — it will search for FFs with - // matching sig_q. - // - // As opposed to find_output_ff, this function doesn't care about usage - // counts, and may return FF bits that also have other fanout. This - // should not be a problem for input FF merging. - // - // As a special case, if some of the bits in sig_q are constant, this - // function will accept them as well, by synthesizing in-place - // a constant-input FF bit (with matching initial value and reset value). - // However, this will not work if the input is all-constant — if the caller - // cares about this case, it needs to check for it explicitely. - bool find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits); - - // To be called on find_output_ff result that will be merged. This - // marks the given FF bits as used up (and not to be considered for - // further merging as inputs), and reconnects their Q ports to a dummy - // wire (since the wire previously connected there will now be driven - // by the merged-to cell instead). - void remove_output_ff(const pool> &bits); - - // To be called on find_input_ff result that will be merged. This - // marks the given FF bits as used, and disallows merging them as - // outputs. They can, however, still be merged as inputs again - // (perhaps for another cell). - void mark_input_ff(const pool> &bits); - - void set(FfInitVals *initvals_, RTLIL::Module *module_); - - void clear(); - - FfMergeHelper(FfInitVals *initvals, RTLIL::Module *module) { - set(initvals, module); - } - - FfMergeHelper() {} -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/fstdata.cc b/yosys/kernel/fstdata.cc deleted file mode 100644 index 65ae3426cd6..00000000000 --- a/yosys/kernel/fstdata.cc +++ /dev/null @@ -1,264 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2022 Miodrag Milanovic - * - * 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/fstdata.h" - -USING_YOSYS_NAMESPACE - - -static std::string file_base_name(std::string const & path) -{ - return path.substr(path.find_last_of("/\\") + 1); -} - -FstData::FstData(std::string filename) : ctx(nullptr) -{ - #if !defined(YOSYS_DISABLE_SPAWN) - std::string filename_trim = file_base_name(filename); - if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vcd") == 0) { - filename_trim.erase(filename_trim.size()-4); - tmp_file = stringf("%s/converted_%s.fst", get_base_tmpdir().c_str(), filename_trim.c_str()); - std::string cmd = stringf("vcd2fst %s %s", filename.c_str(), tmp_file.c_str()); - log("Exec: %s\n", cmd.c_str()); - if (run_command(cmd) != 0) - log_cmd_error("Shell command failed!\n"); - filename = tmp_file; - } - #endif - const std::vector g_units = { "s", "ms", "us", "ns", "ps", "fs", "as", "zs" }; - ctx = (fstReaderContext *)fstReaderOpen(filename.c_str()); - if (!ctx) - log_error("Error opening '%s' as FST file\n", filename.c_str()); - int scale = (int)fstReaderGetTimescale(ctx); - timescale = pow(10.0, scale); - timescale_str = ""; - int unit = 0; - int zeros = 0; - if (scale > 0) { - zeros = scale; - } else { - if ((scale % 3) == 0) { - zeros = (-scale % 3); - unit = (-scale / 3); - } else { - zeros = 3 - (-scale % 3); - unit = (-scale / 3) + 1; - } - } - for (int i=0;i') - c = ']'; - } -} - -fstHandle FstData::getHandle(std::string name) { - normalize_brackets(name); - if (name_to_handle.find(name) != name_to_handle.end()) - return name_to_handle[name]; - else - return 0; -}; - -dict FstData::getMemoryHandles(std::string name) { - if (memory_to_handle.find(name) != memory_to_handle.end()) - return memory_to_handle[name]; - else - return dict(); -}; - -static std::string remove_spaces(std::string str) -{ - str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); - return str; -} - -void FstData::extractVarNames() -{ - struct fstHier *h; - std::string fst_scope_name; - - while ((h = fstReaderIterateHier(ctx))) { - switch (h->htyp) { - case FST_HT_SCOPE: { - fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, NULL); - break; - } - case FST_HT_UPSCOPE: { - fst_scope_name = fstReaderPopScope(ctx); - break; - } - case FST_HT_VAR: { - FstVar var; - var.id = h->u.var.handle; - var.is_alias = h->u.var.is_alias; - var.is_reg = (fstVarType)h->u.var.typ == FST_VT_VCD_REG; - var.name = remove_spaces(h->u.var.name); - var.scope = fst_scope_name; - normalize_brackets(var.scope); - var.width = h->u.var.length; - vars.push_back(var); - if (!var.is_alias) - handle_to_var[h->u.var.handle] = var; - std::string clean_name; - for(size_t i=0;iu.var.name);i++) - { - char c = h->u.var.name[i]; - if(c==' ') break; - clean_name += c; - } - if (clean_name[0]=='\\') - clean_name = clean_name.substr(1); - size_t pos = clean_name.find_last_of("<"); - if (pos != std::string::npos && clean_name.back() == '>') { - std::string mem_cell = clean_name.substr(0, pos); - normalize_brackets(mem_cell); - std::string addr = clean_name.substr(pos+1); - addr.pop_back(); // remove closing bracket - char *endptr; - int mem_addr = strtol(addr.c_str(), &endptr, 16); - if (*endptr) { - log_debug("Error parsing memory address in : %s\n", clean_name.c_str()); - } else { - memory_to_handle[var.scope+"."+mem_cell][mem_addr] = var.id; - } - } - pos = clean_name.find_last_of("["); - if (pos != std::string::npos && clean_name.back() == ']') { - std::string mem_cell = clean_name.substr(0, pos); - normalize_brackets(mem_cell); - std::string addr = clean_name.substr(pos+1); - addr.pop_back(); // remove closing bracket - char *endptr; - int mem_addr = strtol(addr.c_str(), &endptr, 10); - if (*endptr) { - log_debug("Error parsing memory address in : %s\n", clean_name.c_str()); - } else { - memory_to_handle[var.scope+"."+mem_cell][mem_addr] = var.id; - } - } - normalize_brackets(clean_name); - name_to_handle[var.scope+"."+clean_name] = h->u.var.handle; - break; - } - } - } -} - - -static void reconstruct_clb_varlen_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen) -{ - FstData *ptr = (FstData*)user_data; - ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen); -} - -static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value) -{ - FstData *ptr = (FstData*)user_data; - uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0; - ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen); -} - -void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */) -{ - if (pnt_time > end_time || !pnt_value) return; - // if we are past the timestamp - bool is_clock = false; - if (!all_samples) { - for(auto &s : clk_signals) { - if (s==pnt_facidx) { - is_clock=true; - break; - } - } - } - - if (pnt_time > past_time) { - past_data = last_data; - past_time = pnt_time; - } - - if (pnt_time > last_time) { - if (all_samples) { - callback(last_time); - last_time = pnt_time; - } else { - if (is_clock) { - std::string val = std::string((const char *)pnt_value); - std::string prev = past_data[pnt_facidx]; - if ((prev!="1" && val=="1") || (prev!="0" && val=="0")) { - callback(last_time); - last_time = pnt_time; - } - } - } - } - // always update last_data - last_data[pnt_facidx] = std::string((const char *)pnt_value); -} - -void FstData::reconstructAllAtTimes(std::vector &signal, uint64_t start, uint64_t end, CallbackFunction cb) -{ - clk_signals = signal; - callback = cb; - start_time = start; - end_time = end; - last_data.clear(); - last_time = start_time; - past_data.clear(); - past_time = start_time; - all_samples = clk_signals.empty(); - - fstReaderSetUnlimitedTimeRange(ctx); - fstReaderSetFacProcessMaskAll(ctx); - fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr); - if (last_time!=end_time) { - past_data = last_data; - callback(last_time); - } - past_data = last_data; - callback(end_time); -} - -std::string FstData::valueOf(fstHandle signal) -{ - if (past_data.find(signal) == past_data.end()) - log_error("Signal id %d not found\n", (int)signal); - return past_data[signal]; -} diff --git a/yosys/kernel/fstdata.h b/yosys/kernel/fstdata.h deleted file mode 100644 index f5cf1d48d8e..00000000000 --- a/yosys/kernel/fstdata.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2022 Miodrag Milanovic - * - * 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 FSTDATA_H -#define FSTDATA_H - -#include "kernel/yosys.h" -#include "libs/fst/fstapi.h" - -YOSYS_NAMESPACE_BEGIN - -typedef std::function CallbackFunction; -struct fst_end_of_data_exception { }; - -struct FstVar -{ - fstHandle id; - std::string name; - bool is_alias; - bool is_reg; - std::string scope; - int width; -}; - -class FstData -{ - public: - FstData(std::string filename); - ~FstData(); - - uint64_t getStartTime(); - uint64_t getEndTime(); - - std::vector& getVars() { return vars; }; - - void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen); - void reconstructAllAtTimes(std::vector &signal, uint64_t start_time, uint64_t end_time, CallbackFunction cb); - - std::string valueOf(fstHandle signal); - fstHandle getHandle(std::string name); - dict getMemoryHandles(std::string name); - double getTimescale() { return timescale; } - const char *getTimescaleString() { return timescale_str.c_str(); } -private: - void extractVarNames(); - - struct fstReaderContext *ctx; - std::vector vars; - std::map handle_to_var; - std::map name_to_handle; - std::map> memory_to_handle; - std::map last_data; - uint64_t last_time; - std::map past_data; - uint64_t past_time; - double timescale; - std::string timescale_str; - uint64_t start_time; - uint64_t end_time; - CallbackFunction callback; - std::vector clk_signals; - bool all_samples; - std::string tmp_file; -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/hashlib.h b/yosys/kernel/hashlib.h index af282715356..b3f99bf730f 100644 --- a/yosys/kernel/hashlib.h +++ b/yosys/kernel/hashlib.h @@ -84,6 +84,12 @@ template<> struct hash_ops : hash_int_ops return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); } }; +template<> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(uint32_t a) { + return a; + } +}; template<> struct hash_ops { static inline bool cmp(const std::string &a, const std::string &b) { diff --git a/yosys/kernel/json.cc b/yosys/kernel/json.cc deleted file mode 100644 index 73874626722..00000000000 --- a/yosys/kernel/json.cc +++ /dev/null @@ -1,172 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2022 Jannis Harder - * - * 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/json.h" - -USING_YOSYS_NAMESPACE - -void PrettyJson::emit_to_log() -{ - struct LogTarget : public Target { - void emit(const char *data) override { log("%s", data); } - }; - - targets.push_back(std::unique_ptr(new LogTarget)); -} - -void PrettyJson::append_to_string(std::string &target) -{ - struct AppendStringTarget : public Target { - std::string ⌖ - AppendStringTarget(std::string &target) : target(target) {} - void emit(const char *data) override { target += data; } - }; - - targets.push_back(std::unique_ptr(new AppendStringTarget(target))); -} - -bool PrettyJson::write_to_file(const std::string &path) -{ - struct WriteFileTarget : public Target { - std::ofstream target; - void emit(const char *data) override { target << data; } - void flush() override { target.flush(); } - }; - - auto target = std::unique_ptr(new WriteFileTarget); - target->target.open(path); - if (target->target.fail()) - return false; - targets.push_back(std::unique_ptr(target.release())); - return true; -} - -void PrettyJson::line(bool space_if_inline) -{ - if (compact_depth != INT_MAX) { - if (space_if_inline) - raw(" "); - return; - } - int indent = state.size() - (state.empty() ? 0 : state.back() == VALUE); - newline_indent.resize(1 + 2 * indent, ' '); - raw(newline_indent.c_str()); -} - -void PrettyJson::raw(const char *raw_json) -{ - for (auto &target : targets) - target->emit(raw_json); -} - -void PrettyJson::flush() -{ - for (auto &target : targets) - target->flush(); -} - -void PrettyJson::begin_object() -{ - begin_value(); - raw("{"); - state.push_back(OBJECT_FIRST); -} - -void PrettyJson::begin_array() -{ - begin_value(); - raw("["); - state.push_back(ARRAY_FIRST); -} - -void PrettyJson::end_object() -{ - Scope top_scope = state.back(); - state.pop_back(); - if (top_scope == OBJECT) - line(false); - else - log_assert(top_scope == OBJECT_FIRST); - raw("}"); - end_value(); -} - -void PrettyJson::end_array() -{ - Scope top_scope = state.back(); - state.pop_back(); - if (top_scope == ARRAY) - line(false); - else - log_assert(top_scope == ARRAY_FIRST); - raw("]"); - end_value(); -} - -void PrettyJson::name(const char *name) -{ - if (state.back() == OBJECT_FIRST) { - state.back() = OBJECT; - line(false); - } else { - raw(","); - line(); - } - raw(Json(name).dump().c_str()); - raw(": "); - state.push_back(VALUE); -} - -void PrettyJson::begin_value() -{ - if (state.back() == ARRAY_FIRST) { - line(false); - state.back() = ARRAY; - } else if (state.back() == ARRAY) { - raw(","); - line(); - } else { - log_assert(state.back() == VALUE); - state.pop_back(); - } -} - -void PrettyJson::end_value() -{ - if (state.empty()) { - raw("\n"); - flush(); - } - if (GetSize(state) < compact_depth) - compact_depth = INT_MAX; -} - -void PrettyJson::value_json(const Json &value) -{ - begin_value(); - raw(value.dump().c_str()); - end_value(); -} - -void PrettyJson::entry_json(const char *name, const Json &value) -{ - this->name(name); - this->value(value); -} - diff --git a/yosys/kernel/json.h b/yosys/kernel/json.h deleted file mode 100644 index c9aa0e04550..00000000000 --- a/yosys/kernel/json.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2022 Jannis Harder - * - * 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 JSON_H -#define JSON_H - -#include "kernel/yosys.h" -#include "libs/json11/json11.hpp" -#include - -YOSYS_NAMESPACE_BEGIN - -using json11::Json; - -class PrettyJson -{ - enum Scope { - VALUE, - OBJECT_FIRST, - OBJECT, - ARRAY_FIRST, - ARRAY, - }; - - struct Target { - virtual void emit(const char *data) = 0; - virtual void flush() {}; - virtual ~Target() {}; - }; - - std::string newline_indent = "\n"; - std::vector> targets; - std::vector state = {VALUE}; - int compact_depth = INT_MAX; -public: - - void emit_to_log(); - void append_to_string(std::string &target); - bool write_to_file(const std::string &path); - - bool active() { return !targets.empty(); } - - void compact() { compact_depth = GetSize(state); } - - void line(bool space_if_inline = true); - void raw(const char *raw_json); - void flush(); - void begin_object(); - void begin_array(); - void end_object(); - void end_array(); - void name(const char *name); - void begin_value(); - void end_value(); - void value_json(const Json &value); - void value(unsigned int value) { value_json(Json((int)value)); } - template - void value(T &&value) { value_json(Json(std::forward(value))); }; - - void entry_json(const char *name, const Json &value); - void entry(const char *name, unsigned int value) { entry_json(name, Json((int)value)); } - template - void entry(const char *name, T &&value) { entry_json(name, Json(std::forward(value))); }; - - template - void object(const T &&values) - { - begin_object(); - for (auto &item : values) - entry(item.first, item.second); - end_object(); - } - - template - void array(const T &&values) - { - begin_object(); - for (auto &item : values) - value(item); - end_object(); - } -}; - - - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/log.cc b/yosys/kernel/log.cc deleted file mode 100644 index 75a1ffb4559..00000000000 --- a/yosys/kernel/log.cc +++ /dev/null @@ -1,775 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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/rtlil/rtlil_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::vector log_scratchpads; -std::map> log_hdump; -std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -dict log_expect_log, log_expect_warning, log_expect_error; -std::set log_warnings, log_experimentals, log_experimentals_ignored; -int log_warnings_count = 0; -int log_warnings_count_noexpect = 0; -bool log_expect_no_warnings = false; -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; -vector 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; - -static void log_id_cache_clear() -{ - for (auto p : log_id_cache) - free(p); - log_id_cache.clear(); -} - -#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; - - RTLIL::Design *design = yosys_get_design(); - if (design != nullptr) - for (auto &scratchpad : log_scratchpads) - design->scratchpad[scratchpad].append(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() && log_expect_log.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()); - - for (auto &item : log_expect_log) - if (std::regex_search(linebuffer, item.second.pattern)) - item.second.current_count++; - - 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()); - - bool warning_match = false; - for (auto &item : log_expect_warning) - if (std::regex_search(message, item.second.pattern)) { - item.second.current_count++; - warning_match = true; - } - - 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); - } - - if (!warning_match) - log_warnings_count_noexpect++; - 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); -} - -[[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; - - for (auto &item : log_expect_error) - if (std::regex_search(log_last_error, item.second.pattern)) - item.second.current_count++; - - log_check_expected(); - - if (log_error_atexit) - log_error_atexit(); - - YS_DEBUGTRAP_IF_DEBUGGING; - const char *e = getenv("YOSYS_ABORT_ON_LOG_ERROR"); - if (e && atoi(e)) - abort(); - -#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_experimental(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - string s = vstringf(format, ap); - va_end(ap); - - if (log_experimentals_ignored.count(s) == 0 && log_experimentals.count(s) == 0) { - log_warning("Feature '%s' is experimental.\n", s.c_str()); - log_experimentals.insert(s); - } -} - -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)); -} - -void log_dump_val_worker(RTLIL::State v) { - log("%s", log_signal(v)); -} - -const char *log_signal(const RTLIL::SigSpec &sig, bool autoint) -{ - std::stringstream buf; - RTLIL_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(const RTLIL::IdString &str) -{ - log_id_cache.push_back(strdup(str.c_str())); - const char *p = log_id_cache.back(); - 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; - RTLIL_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; - RTLIL_BACKEND::dump_cell(buf, indent, cell); - log("%s", buf.str().c_str()); -} - -void log_wire(RTLIL::Wire *wire, std::string indent) -{ - std::stringstream buf; - RTLIL_BACKEND::dump_wire(buf, indent, wire); - log("%s", buf.str().c_str()); -} - -void log_check_expected() -{ - // copy out all of the expected logs so that they cannot be re-checked - // or match against themselves - dict expect_log, expect_warning, expect_error; - std::swap(expect_warning, log_expect_warning); - std::swap(expect_log, log_expect_log); - std::swap(expect_error, log_expect_error); - - for (auto &item : expect_warning) { - if (item.second.current_count == 0) { - log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' not found !\n", item.first.c_str()); - } - if (item.second.current_count != item.second.expected_count) { - log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.first.c_str(), item.second.current_count, item.second.expected_count); - } - } - - for (auto &item : expect_log) { - if (item.second.current_count == 0) { - log_warn_regexes.clear(); - log_error("Expected log pattern '%s' not found !\n", item.first.c_str()); - } - if (item.second.current_count != item.second.expected_count) { - log_warn_regexes.clear(); - log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.first.c_str(), item.second.current_count, item.second.expected_count); - } - } - - for (auto &item : expect_error) - if (item.second.current_count == item.second.expected_count) { - log_warn_regexes.clear(); - log("Expected error pattern '%s' found !!!\n", item.first.c_str()); - yosys_shutdown(); - #ifdef EMSCRIPTEN - throw 0; - #elif defined(_MSC_VER) - _exit(0); - #else - _Exit(0); - #endif - } else { - log_warn_regexes.clear(); - log_error("Expected error pattern '%s' not found !\n", item.first.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 3a6ec87587a..00000000000 --- a/yosys/kernel/log.h +++ /dev/null @@ -1,448 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 -#define YS_REGEX_COMPILE(param) std::regex(param, \ - std::regex_constants::nosubs | \ - std::regex_constants::optimize | \ - std::regex_constants::egrep) -#define YS_REGEX_COMPILE_WITH_SUBS(param) std::regex(param, \ - std::regex_constants::optimize | \ - std::regex_constants::egrep) - -#if defined(_WIN32) -# include -#else -# include -# include -# if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) -# include -# endif -#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__) - -// YS_DEBUGTRAP is a macro that is functionally equivalent to a breakpoint -// if the platform provides such functionality, and does nothing otherwise. -// If no debugger is attached, it starts a just-in-time debugger if available, -// and crashes the process otherwise. -#if defined(_WIN32) -# define YS_DEBUGTRAP __debugbreak() -#else -# ifndef __has_builtin -// __has_builtin is a GCC/Clang extension; on a different compiler (or old enough GCC/Clang) -// that does not have it, using __has_builtin(...) is a syntax error. -# define __has_builtin(x) 0 -# endif -# if __has_builtin(__builtin_debugtrap) -# define YS_DEBUGTRAP __builtin_debugtrap() -# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) -# define YS_DEBUGTRAP raise(SIGTRAP) -# else -# define YS_DEBUGTRAP do {} while(0) -# endif -#endif - -// YS_DEBUGTRAP_IF_DEBUGGING is a macro that is functionally equivalent to a breakpoint -// if a debugger is attached, and does nothing otherwise. -#if defined(_WIN32) -# define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0) -# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) -// There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However, -// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore. -# define YS_DEBUGTRAP_IF_DEBUGGING do { \ - auto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ - } while(0) -#else -# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0) -#endif - -struct log_cmd_error_exception { }; - -extern std::vector log_files; -extern std::vector log_streams; -extern std::vector log_scratchpads; -extern std::map> log_hdump; -extern std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -extern std::set log_warnings, log_experimentals, log_experimentals_ignored; -extern int log_warnings_count; -extern int log_warnings_count_noexpect; -extern bool log_expect_no_warnings; -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); -[[noreturn]] void logv_error(const char *format, va_list ap); - -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)); -void log_experimental(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)); -[[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]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); - -#ifndef NDEBUG -static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } -#else -static inline bool ys_debug(int = 0) { return false; } -#endif -# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) - -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(); - -struct LogExpectedItem -{ - LogExpectedItem(const std::regex &pat, int expected) : - pattern(pat), expected_count(expected), current_count(0) {} - LogExpectedItem() : expected_count(0), current_count(0) {} - - std::regex pattern; - int expected_count; - int current_count; -}; - -extern dict log_expect_log, log_expect_warning, log_expect_error; -void log_check_expected(); - -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(const 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_) do { if (0) { (void)(_assert_expr_); } } while(0) -#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(RUSAGE_SELF) - struct rusage rusage; - int64_t t = 0; - for (int who : {RUSAGE_SELF, RUSAGE_CHILDREN}) { - if (getrusage(who, &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) { log_assert(*p == 0); } -void log_dump_val_worker(RTLIL::IdString v); -void log_dump_val_worker(RTLIL::SigSpec v); -void log_dump_val_worker(RTLIL::State v); - -template static inline void log_dump_val_worker(dict &v); -template static inline void log_dump_val_worker(pool &v); -template static inline void log_dump_val_worker(std::vector &v); -template static inline void log_dump_val_worker(T *ptr); - -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(std::vector &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 e4e1ebf52ab..00000000000 --- a/yosys/kernel/macc.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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] == State::S0) - port.in_a.remove(GetSize(port.in_a)-1); - while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == State::S0) - port.in_b.remove(GetSize(port.in_b)-1); - } - - new_ports.push_back(port); - } - - for (auto &bit : bit_ports) - if (bit == State::S1) - off = const_add(off, RTLIL::Const(1, width), false, false, width); - else if (bit != State::S0) - new_bit_ports.append(bit); - - if (off.as_bool()) { - port_t port; - port.in_a = off; - 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(ID::A); - - ports.clear(); - bit_ports = cell->getPort(ID::B); - - std::vector config_bits = cell->getParam(ID::CONFIG).bits; - int config_cursor = 0; - - int config_width = cell->getParam(ID::CONFIG_WIDTH).as_int(); - log_assert(GetSize(config_bits) >= config_width); - - int num_bits = 0; - if (config_bits[config_cursor++] == State::S1) num_bits |= 1; - if (config_bits[config_cursor++] == State::S1) num_bits |= 2; - if (config_bits[config_cursor++] == State::S1) num_bits |= 4; - if (config_bits[config_cursor++] == State::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++] == State::S1; - this_port.do_subtract = config_bits[config_cursor++] == State::S1; - - int size_a = 0; - for (int i = 0; i < num_bits; i++) - if (config_bits[config_cursor++] == State::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++] == State::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 ? State::S1 : State::S0); - config_bits.push_back(num_bits & 2 ? State::S1 : State::S0); - config_bits.push_back(num_bits & 4 ? State::S1 : State::S0); - config_bits.push_back(num_bits & 8 ? State::S1 : State::S0); - - for (auto &port : ports) - { - if (GetSize(port.in_a) == 0) - continue; - - config_bits.push_back(port.is_signed ? State::S1 : State::S0); - config_bits.push_back(port.do_subtract ? State::S1 : State::S0); - - int size_a = GetSize(port.in_a); - for (int i = 0; i < num_bits; i++) - config_bits.push_back(size_a & (1 << i) ? State::S1 : State::S0); - - int size_b = GetSize(port.in_b); - for (int i = 0; i < num_bits; i++) - config_bits.push_back(size_b & (1 << i) ? State::S1 : State::S0); - - port_a.append(port.in_a); - port_a.append(port.in_b); - } - - cell->setPort(ID::A, port_a); - cell->setPort(ID::B, bit_ports); - cell->setParam(ID::CONFIG, config_bits); - cell->setParam(ID::CONFIG_WIDTH, GetSize(config_bits)); - cell->setParam(ID::A_WIDTH, GetSize(port_a)); - cell->setParam(ID::B_WIDTH, GetSize(bit_ports)); - } - - bool eval(RTLIL::Const &result) const - { - for (auto &bit : result.bits) - bit = State::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/mem.cc b/yosys/kernel/mem.cc deleted file mode 100644 index ed01a086713..00000000000 --- a/yosys/kernel/mem.cc +++ /dev/null @@ -1,1670 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 Marcelina Kościelnicka - * - * 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/mem.h" -#include "kernel/ff.h" - -USING_YOSYS_NAMESPACE - -void Mem::remove() { - if (cell) { - module->remove(cell); - cell = nullptr; - } - if (mem) { - module->memories.erase(mem->name); - delete mem; - mem = nullptr; - } - for (auto &port : rd_ports) { - if (port.cell) { - module->remove(port.cell); - port.cell = nullptr; - } - } - for (auto &port : wr_ports) { - if (port.cell) { - module->remove(port.cell); - port.cell = nullptr; - } - } - for (auto &init : inits) { - if (init.cell) { - module->remove(init.cell); - init.cell = nullptr; - } - } -} - -void Mem::emit() { - check(); - std::vector rd_left; - for (int i = 0; i < GetSize(rd_ports); i++) { - auto &port = rd_ports[i]; - if (port.removed) { - if (port.cell) { - module->remove(port.cell); - } - } else { - rd_left.push_back(i); - } - } - std::vector wr_left; - for (int i = 0; i < GetSize(wr_ports); i++) { - auto &port = wr_ports[i]; - if (port.removed) { - if (port.cell) { - module->remove(port.cell); - } - } else { - wr_left.push_back(i); - } - } - std::vector init_left; - for (int i = 0; i < GetSize(inits); i++) { - auto &init = inits[i]; - if (init.removed) { - if (init.cell) { - module->remove(init.cell); - } - } else { - init_left.push_back(i); - } - } - for (int i = 0; i < GetSize(rd_left); i++) - if (i != rd_left[i]) - std::swap(rd_ports[i], rd_ports[rd_left[i]]); - rd_ports.resize(GetSize(rd_left)); - for (int i = 0; i < GetSize(wr_left); i++) - if (i != wr_left[i]) - std::swap(wr_ports[i], wr_ports[wr_left[i]]); - wr_ports.resize(GetSize(wr_left)); - for (int i = 0; i < GetSize(init_left); i++) - if (i != init_left[i]) - std::swap(inits[i], inits[init_left[i]]); - inits.resize(GetSize(init_left)); - - for (auto &port : rd_ports) { - for (int i = 0; i < GetSize(wr_left); i++) { - port.transparency_mask[i] = port.transparency_mask[wr_left[i]]; - port.collision_x_mask[i] = port.collision_x_mask[wr_left[i]]; - } - port.transparency_mask.resize(GetSize(wr_left)); - port.collision_x_mask.resize(GetSize(wr_left)); - } - for (auto &port : wr_ports) { - for (int i = 0; i < GetSize(wr_left); i++) - port.priority_mask[i] = port.priority_mask[wr_left[i]]; - port.priority_mask.resize(GetSize(wr_left)); - } - - if (packed) { - if (mem) { - module->memories.erase(mem->name); - delete mem; - mem = nullptr; - } - if (!cell) { - if (memid.empty()) - memid = NEW_ID; - cell = module->addCell(memid, ID($mem_v2)); - } - cell->type = ID($mem_v2); - cell->attributes = attributes; - cell->parameters[ID::MEMID] = Const(memid.str()); - cell->parameters[ID::WIDTH] = Const(width); - cell->parameters[ID::OFFSET] = Const(start_offset); - cell->parameters[ID::SIZE] = Const(size); - Const rd_wide_continuation, rd_clk_enable, rd_clk_polarity, rd_transparency_mask, rd_collision_x_mask; - Const wr_wide_continuation, wr_clk_enable, wr_clk_polarity, wr_priority_mask; - Const rd_ce_over_srst, rd_arst_value, rd_srst_value, rd_init_value; - SigSpec rd_clk, rd_en, rd_addr, rd_data; - SigSpec wr_clk, wr_en, wr_addr, wr_data; - SigSpec rd_arst, rd_srst; - int abits = 0; - for (auto &port : rd_ports) - abits = std::max(abits, GetSize(port.addr)); - for (auto &port : wr_ports) - abits = std::max(abits, GetSize(port.addr)); - cell->parameters[ID::ABITS] = Const(abits); - std::vector wr_port_xlat; - for (int i = 0; i < GetSize(wr_ports); i++) - for (int j = 0; j < (1 << wr_ports[i].wide_log2); j++) - wr_port_xlat.push_back(i); - for (auto &port : rd_ports) { - if (port.cell) { - module->remove(port.cell); - port.cell = nullptr; - } - for (int sub = 0; sub < (1 << port.wide_log2); sub++) - { - rd_wide_continuation.bits.push_back(State(sub != 0)); - rd_clk_enable.bits.push_back(State(port.clk_enable)); - rd_clk_polarity.bits.push_back(State(port.clk_polarity)); - rd_ce_over_srst.bits.push_back(State(port.ce_over_srst)); - rd_clk.append(port.clk); - rd_arst.append(port.arst); - rd_srst.append(port.srst); - rd_en.append(port.en); - SigSpec addr = port.sub_addr(sub); - addr.extend_u0(abits, false); - rd_addr.append(addr); - log_assert(GetSize(addr) == abits); - for (auto idx : wr_port_xlat) { - rd_transparency_mask.bits.push_back(State(bool(port.transparency_mask[idx]))); - rd_collision_x_mask.bits.push_back(State(bool(port.collision_x_mask[idx]))); - } - } - rd_data.append(port.data); - for (auto &bit : port.arst_value) - rd_arst_value.bits.push_back(bit); - for (auto &bit : port.srst_value) - rd_srst_value.bits.push_back(bit); - for (auto &bit : port.init_value) - rd_init_value.bits.push_back(bit); - } - if (rd_ports.empty()) { - rd_wide_continuation = State::S0; - rd_clk_enable = State::S0; - rd_clk_polarity = State::S0; - rd_ce_over_srst = State::S0; - rd_arst_value = State::S0; - rd_srst_value = State::S0; - rd_init_value = State::S0; - } - if (rd_ports.empty() || wr_ports.empty()) { - rd_transparency_mask = State::S0; - rd_collision_x_mask = State::S0; - } - cell->parameters[ID::RD_PORTS] = Const(GetSize(rd_clk)); - cell->parameters[ID::RD_CLK_ENABLE] = rd_clk_enable; - cell->parameters[ID::RD_CLK_POLARITY] = rd_clk_polarity; - cell->parameters[ID::RD_TRANSPARENCY_MASK] = rd_transparency_mask; - cell->parameters[ID::RD_COLLISION_X_MASK] = rd_collision_x_mask; - cell->parameters[ID::RD_WIDE_CONTINUATION] = rd_wide_continuation; - cell->parameters[ID::RD_CE_OVER_SRST] = rd_ce_over_srst; - cell->parameters[ID::RD_ARST_VALUE] = rd_arst_value; - cell->parameters[ID::RD_SRST_VALUE] = rd_srst_value; - cell->parameters[ID::RD_INIT_VALUE] = rd_init_value; - cell->parameters.erase(ID::RD_TRANSPARENT); - cell->setPort(ID::RD_CLK, rd_clk); - cell->setPort(ID::RD_EN, rd_en); - cell->setPort(ID::RD_ARST, rd_arst); - cell->setPort(ID::RD_SRST, rd_srst); - cell->setPort(ID::RD_ADDR, rd_addr); - cell->setPort(ID::RD_DATA, rd_data); - for (auto &port : wr_ports) { - if (port.cell) { - module->remove(port.cell); - port.cell = nullptr; - } - for (int sub = 0; sub < (1 << port.wide_log2); sub++) - { - wr_wide_continuation.bits.push_back(State(sub != 0)); - wr_clk_enable.bits.push_back(State(port.clk_enable)); - wr_clk_polarity.bits.push_back(State(port.clk_polarity)); - wr_clk.append(port.clk); - for (auto idx : wr_port_xlat) - wr_priority_mask.bits.push_back(State(bool(port.priority_mask[idx]))); - SigSpec addr = port.sub_addr(sub); - addr.extend_u0(abits, false); - wr_addr.append(addr); - log_assert(GetSize(addr) == abits); - } - wr_en.append(port.en); - wr_data.append(port.data); - } - if (wr_ports.empty()) { - wr_wide_continuation = State::S0; - wr_clk_enable = State::S0; - wr_clk_polarity = State::S0; - wr_priority_mask = State::S0; - } - cell->parameters[ID::WR_PORTS] = Const(GetSize(wr_clk)); - cell->parameters[ID::WR_CLK_ENABLE] = wr_clk_enable; - cell->parameters[ID::WR_CLK_POLARITY] = wr_clk_polarity; - cell->parameters[ID::WR_PRIORITY_MASK] = wr_priority_mask; - cell->parameters[ID::WR_WIDE_CONTINUATION] = wr_wide_continuation; - cell->setPort(ID::WR_CLK, wr_clk); - cell->setPort(ID::WR_EN, wr_en); - cell->setPort(ID::WR_ADDR, wr_addr); - cell->setPort(ID::WR_DATA, wr_data); - for (auto &init : inits) { - if (init.cell) { - module->remove(init.cell); - init.cell = nullptr; - } - } - cell->parameters[ID::INIT] = get_init_data(); - } else { - if (cell) { - module->remove(cell); - cell = nullptr; - } - if (!mem) { - if (memid.empty()) - memid = NEW_ID; - mem = new RTLIL::Memory; - mem->name = memid; - module->memories[memid] = mem; - } - mem->width = width; - mem->start_offset = start_offset; - mem->size = size; - mem->attributes = attributes; - for (auto &port : rd_ports) { - if (!port.cell) - port.cell = module->addCell(NEW_ID, ID($memrd_v2)); - port.cell->type = ID($memrd_v2); - port.cell->attributes = port.attributes; - port.cell->parameters[ID::MEMID] = memid.str(); - port.cell->parameters[ID::ABITS] = GetSize(port.addr); - port.cell->parameters[ID::WIDTH] = width << port.wide_log2; - port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable; - port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity; - port.cell->parameters[ID::CE_OVER_SRST] = port.ce_over_srst; - port.cell->parameters[ID::ARST_VALUE] = port.arst_value; - port.cell->parameters[ID::SRST_VALUE] = port.srst_value; - port.cell->parameters[ID::INIT_VALUE] = port.init_value; - port.cell->parameters[ID::TRANSPARENCY_MASK] = port.transparency_mask; - port.cell->parameters[ID::COLLISION_X_MASK] = port.collision_x_mask; - port.cell->parameters.erase(ID::TRANSPARENT); - port.cell->setPort(ID::CLK, port.clk); - port.cell->setPort(ID::EN, port.en); - port.cell->setPort(ID::ARST, port.arst); - port.cell->setPort(ID::SRST, port.srst); - port.cell->setPort(ID::ADDR, port.addr); - port.cell->setPort(ID::DATA, port.data); - } - int idx = 0; - for (auto &port : wr_ports) { - if (!port.cell) - port.cell = module->addCell(NEW_ID, ID($memwr_v2)); - port.cell->type = ID($memwr_v2); - port.cell->attributes = port.attributes; - if (port.cell->parameters.count(ID::PRIORITY)) - port.cell->parameters.erase(ID::PRIORITY); - port.cell->parameters[ID::MEMID] = memid.str(); - port.cell->parameters[ID::ABITS] = GetSize(port.addr); - port.cell->parameters[ID::WIDTH] = width << port.wide_log2; - port.cell->parameters[ID::CLK_ENABLE] = port.clk_enable; - port.cell->parameters[ID::CLK_POLARITY] = port.clk_polarity; - port.cell->parameters[ID::PORTID] = idx++; - port.cell->parameters[ID::PRIORITY_MASK] = port.priority_mask; - port.cell->setPort(ID::CLK, port.clk); - port.cell->setPort(ID::EN, port.en); - port.cell->setPort(ID::ADDR, port.addr); - port.cell->setPort(ID::DATA, port.data); - } - idx = 0; - for (auto &init : inits) { - bool v2 = !init.en.is_fully_ones(); - if (!init.cell) - init.cell = module->addCell(NEW_ID, v2 ? ID($meminit_v2) : ID($meminit)); - else - init.cell->type = v2 ? ID($meminit_v2) : ID($meminit); - init.cell->attributes = init.attributes; - init.cell->parameters[ID::MEMID] = memid.str(); - init.cell->parameters[ID::ABITS] = GetSize(init.addr); - init.cell->parameters[ID::WIDTH] = width; - init.cell->parameters[ID::WORDS] = GetSize(init.data) / width; - init.cell->parameters[ID::PRIORITY] = idx++; - init.cell->setPort(ID::ADDR, init.addr); - init.cell->setPort(ID::DATA, init.data); - if (v2) - init.cell->setPort(ID::EN, init.en); - else - init.cell->unsetPort(ID::EN); - } - } -} - -void Mem::clear_inits() { - for (auto &init : inits) - init.removed = true; -} - -void Mem::coalesce_inits() { - // start address -> end address - std::map chunks; - // Figure out chunk boundaries. - for (auto &init : inits) { - if (init.removed) - continue; - bool valid = false; - for (auto bit : init.en) - if (bit == State::S1) - valid = true; - if (!valid) { - init.removed = true; - continue; - } - int addr = init.addr.as_int(); - int addr_e = addr + GetSize(init.data) / width; - auto it_e = chunks.upper_bound(addr_e); - auto it = it_e; - while (it != chunks.begin()) { - --it; - if (it->second < addr) { - ++it; - break; - } - } - if (it == it_e) { - // No overlapping inits — add this one to index. - chunks[addr] = addr_e; - } else { - // We have an overlap — all chunks in the [it, it_e) - // range will be merged with this init. - if (it->first < addr) - addr = it->first; - auto it_last = it_e; - it_last--; - if (it_last->second > addr_e) - addr_e = it_last->second; - chunks.erase(it, it_e); - chunks[addr] = addr_e; - } - } - // Group inits by the chunk they belong to. - dict> inits_by_chunk; - for (int i = 0; i < GetSize(inits); i++) { - auto &init = inits[i]; - if (init.removed) - continue; - auto it = chunks.upper_bound(init.addr.as_int()); - --it; - inits_by_chunk[it->first].push_back(i); - int addr = init.addr.as_int(); - int addr_e = addr + GetSize(init.data) / width; - log_assert(addr >= it->first && addr_e <= it->second); - } - // Process each chunk. - for (auto &it : inits_by_chunk) { - int caddr = it.first; - int caddr_e = chunks[caddr]; - auto &chunk_inits = it.second; - if (GetSize(chunk_inits) == 1) { - auto &init = inits[chunk_inits[0]]; - if (!init.en.is_fully_ones()) { - for (int i = 0; i < GetSize(init.data); i++) - if (init.en[i % width] != State::S1) - init.data[i] = State::Sx; - init.en = Const(State::S1, width); - } - continue; - } - Const cdata(State::Sx, (caddr_e - caddr) * width); - for (int idx : chunk_inits) { - auto &init = inits[idx]; - int offset = (init.addr.as_int() - caddr) * width; - log_assert(offset >= 0); - log_assert(offset + GetSize(init.data) <= GetSize(cdata)); - for (int i = 0; i < GetSize(init.data); i++) - if (init.en[i % width] == State::S1) - cdata.bits[i+offset] = init.data.bits[i]; - init.removed = true; - } - MemInit new_init; - new_init.addr = caddr; - new_init.data = cdata; - new_init.en = Const(State::S1, width); - inits.push_back(new_init); - } -} - -Const Mem::get_init_data() const { - Const init_data(State::Sx, width * size); - for (auto &init : inits) { - if (init.removed) - continue; - int offset = (init.addr.as_int() - start_offset) * width; - for (int i = 0; i < GetSize(init.data); i++) - if (0 <= i+offset && i+offset < GetSize(init_data) && init.en[i % width] == State::S1) - init_data.bits[i+offset] = init.data.bits[i]; - } - return init_data; -} - -void Mem::check() { - int max_wide_log2 = 0; - for (auto &port : rd_ports) { - if (port.removed) - continue; - log_assert(GetSize(port.clk) == 1); - log_assert(GetSize(port.en) == 1); - log_assert(GetSize(port.arst) == 1); - log_assert(GetSize(port.srst) == 1); - log_assert(GetSize(port.data) == (width << port.wide_log2)); - log_assert(GetSize(port.init_value) == (width << port.wide_log2)); - log_assert(GetSize(port.arst_value) == (width << port.wide_log2)); - log_assert(GetSize(port.srst_value) == (width << port.wide_log2)); - if (!port.clk_enable) { - log_assert(port.en == State::S1); - log_assert(port.arst == State::S0); - log_assert(port.srst == State::S0); - } - for (int j = 0; j < port.wide_log2; j++) { - log_assert(port.addr[j] == State::S0); - } - max_wide_log2 = std::max(max_wide_log2, port.wide_log2); - log_assert(GetSize(port.transparency_mask) == GetSize(wr_ports)); - log_assert(GetSize(port.collision_x_mask) == GetSize(wr_ports)); - for (int j = 0; j < GetSize(wr_ports); j++) { - auto &wport = wr_ports[j]; - if ((port.transparency_mask[j] || port.collision_x_mask[j]) && !wport.removed) { - log_assert(port.clk_enable); - log_assert(wport.clk_enable); - log_assert(port.clk == wport.clk); - log_assert(port.clk_polarity == wport.clk_polarity); - } - log_assert(!port.transparency_mask[j] || !port.collision_x_mask[j]); - } - } - for (int i = 0; i < GetSize(wr_ports); i++) { - auto &port = wr_ports[i]; - if (port.removed) - continue; - log_assert(GetSize(port.clk) == 1); - log_assert(GetSize(port.en) == (width << port.wide_log2)); - log_assert(GetSize(port.data) == (width << port.wide_log2)); - for (int j = 0; j < port.wide_log2; j++) { - log_assert(port.addr[j] == State::S0); - } - max_wide_log2 = std::max(max_wide_log2, port.wide_log2); - log_assert(GetSize(port.priority_mask) == GetSize(wr_ports)); - for (int j = 0; j < GetSize(wr_ports); j++) { - auto &wport = wr_ports[j]; - if (port.priority_mask[j] && !wport.removed) { - log_assert(j < i); - log_assert(port.clk_enable == wport.clk_enable); - if (port.clk_enable) { - log_assert(port.clk == wport.clk); - log_assert(port.clk_polarity == wport.clk_polarity); - } - } - } - } - int mask = (1 << max_wide_log2) - 1; - log_assert(!(start_offset & mask)); - log_assert(!(size & mask)); - log_assert(width != 0); -} - -namespace { - - struct MemIndex { - dict> rd_ports; - dict> wr_ports; - dict> inits; - MemIndex (Module *module) { - for (auto cell: module->cells()) { - if (cell->type.in(ID($memwr), ID($memwr_v2))) - wr_ports[cell->parameters.at(ID::MEMID).decode_string()].insert(cell); - else if (cell->type.in(ID($memrd), ID($memrd_v2))) - rd_ports[cell->parameters.at(ID::MEMID).decode_string()].insert(cell); - else if (cell->type.in(ID($meminit), ID($meminit_v2))) - inits[cell->parameters.at(ID::MEMID).decode_string()].insert(cell); - } - } - }; - - Mem mem_from_memory(Module *module, RTLIL::Memory *mem, const MemIndex &index) { - Mem res(module, mem->name, mem->width, mem->start_offset, mem->size); - res.packed = false; - res.mem = mem; - res.attributes = mem->attributes; - std::vector rd_transparent; - std::vector wr_portid; - if (index.rd_ports.count(mem->name)) { - for (auto cell : index.rd_ports.at(mem->name)) { - MemRd mrd; - bool is_compat = cell->type == ID($memrd); - mrd.cell = cell; - mrd.attributes = cell->attributes; - mrd.clk_enable = cell->parameters.at(ID::CLK_ENABLE).as_bool(); - mrd.clk_polarity = cell->parameters.at(ID::CLK_POLARITY).as_bool(); - mrd.clk = cell->getPort(ID::CLK); - mrd.en = cell->getPort(ID::EN); - mrd.addr = cell->getPort(ID::ADDR); - mrd.data = cell->getPort(ID::DATA); - mrd.wide_log2 = ceil_log2(GetSize(mrd.data) / mem->width); - bool transparent = false; - if (is_compat) { - transparent = cell->parameters.at(ID::TRANSPARENT).as_bool(); - mrd.ce_over_srst = false; - mrd.arst_value = Const(State::Sx, mem->width << mrd.wide_log2); - mrd.srst_value = Const(State::Sx, mem->width << mrd.wide_log2); - mrd.init_value = Const(State::Sx, mem->width << mrd.wide_log2); - mrd.srst = State::S0; - mrd.arst = State::S0; - if (!mrd.clk_enable) { - // Fix some patterns that we'll allow for backwards compatibility, - // but don't want to see moving forwards: async transparent - // ports (inherently meaningless) and async ports without - // const 1 tied to EN bit (which may mean a latch in the future). - transparent = false; - if (mrd.en == State::Sx) - mrd.en = State::S1; - } - } else { - mrd.ce_over_srst = cell->parameters.at(ID::CE_OVER_SRST).as_bool(); - mrd.arst_value = cell->parameters.at(ID::ARST_VALUE); - mrd.srst_value = cell->parameters.at(ID::SRST_VALUE); - mrd.init_value = cell->parameters.at(ID::INIT_VALUE); - mrd.arst = cell->getPort(ID::ARST); - mrd.srst = cell->getPort(ID::SRST); - } - res.rd_ports.push_back(mrd); - rd_transparent.push_back(transparent); - } - } - if (index.wr_ports.count(mem->name)) { - std::vector> ports; - for (auto cell : index.wr_ports.at(mem->name)) { - MemWr mwr; - bool is_compat = cell->type == ID($memwr); - mwr.cell = cell; - mwr.attributes = cell->attributes; - mwr.clk_enable = cell->parameters.at(ID::CLK_ENABLE).as_bool(); - mwr.clk_polarity = cell->parameters.at(ID::CLK_POLARITY).as_bool(); - mwr.clk = cell->getPort(ID::CLK); - mwr.en = cell->getPort(ID::EN); - mwr.addr = cell->getPort(ID::ADDR); - mwr.data = cell->getPort(ID::DATA); - mwr.wide_log2 = ceil_log2(GetSize(mwr.data) / mem->width); - ports.push_back(std::make_pair(cell->parameters.at(is_compat ? ID::PRIORITY : ID::PORTID).as_int(), mwr)); - } - std::sort(ports.begin(), ports.end(), [](const std::pair &a, const std::pair &b) { return a.first < b.first; }); - for (auto &it : ports) { - res.wr_ports.push_back(it.second); - wr_portid.push_back(it.first); - } - for (int i = 0; i < GetSize(res.wr_ports); i++) { - auto &port = res.wr_ports[i]; - bool is_compat = port.cell->type == ID($memwr); - if (is_compat) { - port.priority_mask.resize(GetSize(res.wr_ports)); - for (int j = 0; j < i; j++) { - auto &oport = res.wr_ports[j]; - if (port.clk_enable != oport.clk_enable) - continue; - if (port.clk_enable && port.clk != oport.clk) - continue; - if (port.clk_enable && port.clk_polarity != oport.clk_polarity) - continue; - port.priority_mask[j] = true; - } - } else { - Const orig_prio_mask = port.cell->parameters.at(ID::PRIORITY_MASK); - for (int orig_portid : wr_portid) { - bool has_prio = orig_portid < GetSize(orig_prio_mask) && orig_prio_mask[orig_portid] == State::S1; - port.priority_mask.push_back(has_prio); - } - } - } - } - if (index.inits.count(mem->name)) { - std::vector> inits; - for (auto cell : index.inits.at(mem->name)) { - MemInit init; - init.cell = cell; - init.attributes = cell->attributes; - auto addr = cell->getPort(ID::ADDR); - auto data = cell->getPort(ID::DATA); - if (!addr.is_fully_const()) - log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell)); - if (!data.is_fully_const()) - log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell)); - init.addr = addr.as_const(); - init.data = data.as_const(); - if (cell->type == ID($meminit_v2)) { - auto en = cell->getPort(ID::EN); - if (!en.is_fully_const()) - log_error("Non-constant enable %s in memory initialization %s.\n", log_signal(en), log_id(cell)); - init.en = en.as_const(); - } else { - init.en = RTLIL::Const(State::S1, mem->width); - } - inits.push_back(std::make_pair(cell->parameters.at(ID::PRIORITY).as_int(), init)); - } - std::sort(inits.begin(), inits.end(), [](const std::pair &a, const std::pair &b) { return a.first < b.first; }); - for (auto &it : inits) - res.inits.push_back(it.second); - } - for (int i = 0; i < GetSize(res.rd_ports); i++) { - auto &port = res.rd_ports[i]; - bool is_compat = port.cell->type == ID($memrd); - if (is_compat) { - port.transparency_mask.resize(GetSize(res.wr_ports)); - port.collision_x_mask.resize(GetSize(res.wr_ports)); - if (!rd_transparent[i]) - continue; - if (!port.clk_enable) - continue; - for (int j = 0; j < GetSize(res.wr_ports); j++) { - auto &wport = res.wr_ports[j]; - if (!wport.clk_enable) - continue; - if (port.clk != wport.clk) - continue; - if (port.clk_polarity != wport.clk_polarity) - continue; - port.transparency_mask[j] = true; - } - } else { - Const orig_trans_mask = port.cell->parameters.at(ID::TRANSPARENCY_MASK); - Const orig_cx_mask = port.cell->parameters.at(ID::COLLISION_X_MASK); - for (int orig_portid : wr_portid) { - port.transparency_mask.push_back(orig_portid < GetSize(orig_trans_mask) && orig_trans_mask[orig_portid] == State::S1); - port.collision_x_mask.push_back(orig_portid < GetSize(orig_cx_mask) && orig_cx_mask[orig_portid] == State::S1); - } - } - } - res.check(); - return res; - } - - Mem mem_from_cell(Cell *cell) { - Mem res(cell->module, cell->parameters.at(ID::MEMID).decode_string(), - cell->parameters.at(ID::WIDTH).as_int(), - cell->parameters.at(ID::OFFSET).as_int(), - cell->parameters.at(ID::SIZE).as_int() - ); - bool is_compat = cell->type == ID($mem); - int abits = cell->parameters.at(ID::ABITS).as_int(); - res.packed = true; - res.cell = cell; - res.attributes = cell->attributes; - Const &init = cell->parameters.at(ID::INIT); - if (!init.is_fully_undef()) { - int pos = 0; - while (pos < res.size) { - Const word = init.extract(pos * res.width, res.width, State::Sx); - if (word.is_fully_undef()) { - pos++; - } else { - int epos; - for (epos = pos; epos < res.size; epos++) { - Const eword = init.extract(epos * res.width, res.width, State::Sx); - if (eword.is_fully_undef()) - break; - } - MemInit minit; - minit.addr = res.start_offset + pos; - minit.data = init.extract(pos * res.width, (epos - pos) * res.width, State::Sx); - minit.en = RTLIL::Const(State::S1, res.width); - res.inits.push_back(minit); - pos = epos; - } - } - } - int n_rd_ports = cell->parameters.at(ID::RD_PORTS).as_int(); - int n_wr_ports = cell->parameters.at(ID::WR_PORTS).as_int(); - Const rd_wide_continuation = is_compat ? Const(State::S0, n_rd_ports) : cell->parameters.at(ID::RD_WIDE_CONTINUATION); - Const wr_wide_continuation = is_compat ? Const(State::S0, n_wr_ports) : cell->parameters.at(ID::WR_WIDE_CONTINUATION); - for (int i = 0, ni; i < n_rd_ports; i = ni) { - ni = i + 1; - while (ni < n_rd_ports && rd_wide_continuation[ni] == State::S1) - ni++; - MemRd mrd; - mrd.wide_log2 = ceil_log2(ni - i); - log_assert(ni - i == (1 << mrd.wide_log2)); - mrd.clk_enable = cell->parameters.at(ID::RD_CLK_ENABLE).extract(i, 1).as_bool(); - mrd.clk_polarity = cell->parameters.at(ID::RD_CLK_POLARITY).extract(i, 1).as_bool(); - mrd.clk = cell->getPort(ID::RD_CLK).extract(i, 1); - mrd.en = cell->getPort(ID::RD_EN).extract(i, 1); - mrd.addr = cell->getPort(ID::RD_ADDR).extract(i * abits, abits); - mrd.data = cell->getPort(ID::RD_DATA).extract(i * res.width, (ni - i) * res.width); - if (is_compat) { - mrd.ce_over_srst = false; - mrd.arst_value = Const(State::Sx, res.width << mrd.wide_log2); - mrd.srst_value = Const(State::Sx, res.width << mrd.wide_log2); - mrd.init_value = Const(State::Sx, res.width << mrd.wide_log2); - mrd.arst = State::S0; - mrd.srst = State::S0; - } else { - mrd.ce_over_srst = cell->parameters.at(ID::RD_CE_OVER_SRST).extract(i, 1).as_bool(); - mrd.arst_value = cell->parameters.at(ID::RD_ARST_VALUE).extract(i * res.width, (ni - i) * res.width); - mrd.srst_value = cell->parameters.at(ID::RD_SRST_VALUE).extract(i * res.width, (ni - i) * res.width); - mrd.init_value = cell->parameters.at(ID::RD_INIT_VALUE).extract(i * res.width, (ni - i) * res.width); - mrd.arst = cell->getPort(ID::RD_ARST).extract(i, 1); - mrd.srst = cell->getPort(ID::RD_SRST).extract(i, 1); - } - if (!is_compat) { - Const transparency_mask = cell->parameters.at(ID::RD_TRANSPARENCY_MASK).extract(i * n_wr_ports, n_wr_ports); - Const collision_x_mask = cell->parameters.at(ID::RD_COLLISION_X_MASK).extract(i * n_wr_ports, n_wr_ports); - for (int j = 0; j < n_wr_ports; j++) - if (wr_wide_continuation[j] != State::S1) { - mrd.transparency_mask.push_back(transparency_mask[j] == State::S1); - mrd.collision_x_mask.push_back(collision_x_mask[j] == State::S1); - } - } - res.rd_ports.push_back(mrd); - } - for (int i = 0, ni; i < n_wr_ports; i = ni) { - ni = i + 1; - while (ni < n_wr_ports && wr_wide_continuation[ni] == State::S1) - ni++; - MemWr mwr; - mwr.wide_log2 = ceil_log2(ni - i); - log_assert(ni - i == (1 << mwr.wide_log2)); - mwr.clk_enable = cell->parameters.at(ID::WR_CLK_ENABLE).extract(i, 1).as_bool(); - mwr.clk_polarity = cell->parameters.at(ID::WR_CLK_POLARITY).extract(i, 1).as_bool(); - mwr.clk = cell->getPort(ID::WR_CLK).extract(i, 1); - mwr.en = cell->getPort(ID::WR_EN).extract(i * res.width, (ni - i) * res.width); - mwr.addr = cell->getPort(ID::WR_ADDR).extract(i * abits, abits); - mwr.data = cell->getPort(ID::WR_DATA).extract(i * res.width, (ni - i) * res.width); - if (!is_compat) { - Const priority_mask = cell->parameters.at(ID::WR_PRIORITY_MASK).extract(i * n_wr_ports, n_wr_ports); - for (int j = 0; j < n_wr_ports; j++) - if (wr_wide_continuation[j] != State::S1) - mwr.priority_mask.push_back(priority_mask[j] == State::S1); - } - res.wr_ports.push_back(mwr); - } - if (is_compat) { - for (int i = 0; i < GetSize(res.wr_ports); i++) { - auto &port = res.wr_ports[i]; - port.priority_mask.resize(GetSize(res.wr_ports)); - for (int j = 0; j < i; j++) { - auto &oport = res.wr_ports[j]; - if (port.clk_enable != oport.clk_enable) - continue; - if (port.clk_enable && port.clk != oport.clk) - continue; - if (port.clk_enable && port.clk_polarity != oport.clk_polarity) - continue; - port.priority_mask[j] = true; - } - } - for (int i = 0; i < GetSize(res.rd_ports); i++) { - auto &port = res.rd_ports[i]; - port.transparency_mask.resize(GetSize(res.wr_ports)); - port.collision_x_mask.resize(GetSize(res.wr_ports)); - if (!cell->parameters.at(ID::RD_TRANSPARENT).extract(i, 1).as_bool()) - continue; - if (!port.clk_enable) - continue; - for (int j = 0; j < GetSize(res.wr_ports); j++) { - auto &wport = res.wr_ports[j]; - if (!wport.clk_enable) - continue; - if (port.clk != wport.clk) - continue; - if (port.clk_polarity != wport.clk_polarity) - continue; - port.transparency_mask[j] = true; - } - } - } - res.check(); - return res; - } - -} - -std::vector Mem::get_all_memories(Module *module) { - std::vector res; - MemIndex index(module); - for (auto it: module->memories) { - res.push_back(mem_from_memory(module, it.second, index)); - } - for (auto cell: module->cells()) { - if (cell->type.in(ID($mem), ID($mem_v2))) - res.push_back(mem_from_cell(cell)); - } - return res; -} - -std::vector Mem::get_selected_memories(Module *module) { - std::vector res; - MemIndex index(module); - for (auto it: module->memories) { - if (module->design->selected(module, it.second)) - res.push_back(mem_from_memory(module, it.second, index)); - } - for (auto cell: module->selected_cells()) { - if (cell->type.in(ID($mem), ID($mem_v2))) - res.push_back(mem_from_cell(cell)); - } - return res; -} - -Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) { - MemRd &port = rd_ports[idx]; - - if (!port.clk_enable) - return nullptr; - - Cell *c; - - // There are two ways to handle rdff extraction when transparency is involved: - // - // - if all of the following conditions are true, put the FF on address input: - // - // - the port has no clock enable, no reset, and no initial value - // - the port is transparent wrt all write ports (implying they also share - // the clock domain) - // - // - otherwise, put the FF on the data output, and make bypass paths for - // all write ports wrt which this port is transparent - bool trans_use_addr = true; - for (int i = 0; i < GetSize(wr_ports); i++) - if (!port.transparency_mask[i] && !wr_ports[i].removed) - trans_use_addr = false; - - // If there are no write ports at all, we could possibly use either way; do data - // FF in this case. - if (GetSize(wr_ports) == 0) - trans_use_addr = false; - - if (port.en != State::S1 || port.srst != State::S0 || port.arst != State::S0 || !port.init_value.is_fully_undef()) - trans_use_addr = false; - - if (trans_use_addr) - { - // Do not put a register in front of constant address bits — this is both - // unnecessary and will break wide ports. - int width = 0; - for (int i = 0; i < GetSize(port.addr); i++) - if (port.addr[i].wire) - width++; - - if (width) - { - SigSpec sig_q = module->addWire(stringf("$%s$rdreg[%d]$q", memid.c_str(), idx), width); - SigSpec sig_d; - - int pos = 0; - for (int i = 0; i < GetSize(port.addr); i++) - if (port.addr[i].wire) { - sig_d.append(port.addr[i]); - port.addr[i] = sig_q[pos++]; - } - - c = module->addDff(stringf("$%s$rdreg[%d]", memid.c_str(), idx), port.clk, sig_d, sig_q, port.clk_polarity); - } else { - c = nullptr; - } - } - else - { - log_assert(port.arst == State::S0 || port.srst == State::S0); - - SigSpec async_d = module->addWire(stringf("$%s$rdreg[%d]$d", memid.c_str(), idx), GetSize(port.data)); - SigSpec sig_d = async_d; - - for (int i = 0; i < GetSize(wr_ports); i++) { - auto &wport = wr_ports[i]; - if (wport.removed) - continue; - if (port.transparency_mask[i] || port.collision_x_mask[i]) { - log_assert(wport.clk_enable); - log_assert(wport.clk == port.clk); - log_assert(wport.clk_enable == port.clk_enable); - int min_wide_log2 = std::min(port.wide_log2, wport.wide_log2); - int max_wide_log2 = std::max(port.wide_log2, wport.wide_log2); - bool wide_write = wport.wide_log2 > port.wide_log2; - for (int sub = 0; sub < (1 << max_wide_log2); sub += (1 << min_wide_log2)) { - SigSpec raddr = port.addr; - SigSpec waddr = wport.addr; - if (wide_write) - waddr = wport.sub_addr(sub); - else - raddr = port.sub_addr(sub); - SigSpec addr_eq; - if (raddr != waddr) - addr_eq = module->Eq(stringf("$%s$rdtransen[%d][%d][%d]$d", memid.c_str(), idx, i, sub), raddr, waddr); - int pos = 0; - int ewidth = width << min_wide_log2; - int wsub = wide_write ? sub : 0; - int rsub = wide_write ? 0 : sub; - while (pos < ewidth) { - int epos = pos; - while (epos < ewidth && wport.en[epos + wsub * width] == wport.en[pos + wsub * width]) - epos++; - SigSpec cur = sig_d.extract(pos + rsub * width, epos-pos); - SigSpec other = port.transparency_mask[i] ? wport.data.extract(pos + wsub * width, epos-pos) : Const(State::Sx, epos-pos); - SigSpec cond; - if (raddr != waddr) - cond = module->And(stringf("$%s$rdtransgate[%d][%d][%d][%d]$d", memid.c_str(), idx, i, sub, pos), wport.en[pos + wsub * width], addr_eq); - else - cond = wport.en[pos + wsub * width]; - SigSpec merged = module->Mux(stringf("$%s$rdtransmux[%d][%d][%d][%d]$d", memid.c_str(), idx, i, sub, pos), cur, other, cond); - sig_d.replace(pos + rsub * width, merged); - pos = epos; - } - } - } - } - - IdString name = stringf("$%s$rdreg[%d]", memid.c_str(), idx); - FfData ff(module, initvals, name); - ff.width = GetSize(port.data); - ff.has_clk = true; - ff.sig_clk = port.clk; - ff.pol_clk = port.clk_polarity; - if (port.en != State::S1) { - ff.has_ce = true; - ff.pol_ce = true; - ff.sig_ce = port.en; - } - if (port.arst != State::S0) { - ff.has_arst = true; - ff.pol_arst = true; - ff.sig_arst = port.arst; - ff.val_arst = port.arst_value; - } - if (port.srst != State::S0) { - ff.has_srst = true; - ff.pol_srst = true; - ff.sig_srst = port.srst; - ff.val_srst = port.srst_value; - ff.ce_over_srst = ff.has_ce && port.ce_over_srst; - } - ff.sig_d = sig_d; - ff.sig_q = port.data; - ff.val_init = port.init_value; - port.data = async_d; - c = ff.emit(); - } - - if (c) - log("Extracted %s FF from read port %d of %s.%s: %s\n", trans_use_addr ? "addr" : "data", - idx, log_id(module), log_id(memid), log_id(c)); - - port.en = State::S1; - port.clk = State::S0; - port.arst = State::S0; - port.srst = State::S0; - port.clk_enable = false; - port.clk_polarity = true; - port.ce_over_srst = false; - port.arst_value = Const(State::Sx, GetSize(port.data)); - port.srst_value = Const(State::Sx, GetSize(port.data)); - port.init_value = Const(State::Sx, GetSize(port.data)); - - for (int i = 0; i < GetSize(wr_ports); i++) { - port.transparency_mask[i] = false; - port.collision_x_mask[i] = false; - } - - return c; -} - -void Mem::narrow() { - // NOTE: several passes depend on this function not modifying - // the design at all until (and unless) emit() is called. - // Be careful to preserve this. - std::vector new_rd_ports; - std::vector new_wr_ports; - std::vector> new_rd_map; - std::vector> new_wr_map; - for (int i = 0; i < GetSize(rd_ports); i++) { - auto &port = rd_ports[i]; - for (int sub = 0; sub < (1 << port.wide_log2); sub++) { - new_rd_map.push_back(std::make_pair(i, sub)); - } - } - for (int i = 0; i < GetSize(wr_ports); i++) { - auto &port = wr_ports[i]; - for (int sub = 0; sub < (1 << port.wide_log2); sub++) { - new_wr_map.push_back(std::make_pair(i, sub)); - } - } - for (auto &it : new_rd_map) { - MemRd &orig = rd_ports[it.first]; - MemRd port = orig; - if (it.second != 0) - port.cell = nullptr; - if (port.wide_log2) { - port.data = port.data.extract(it.second * width, width); - port.init_value = port.init_value.extract(it.second * width, width); - port.arst_value = port.arst_value.extract(it.second * width, width); - port.srst_value = port.srst_value.extract(it.second * width, width); - port.addr = port.sub_addr(it.second); - port.wide_log2 = 0; - } - port.transparency_mask.clear(); - port.collision_x_mask.clear(); - for (auto &it2 : new_wr_map) - port.transparency_mask.push_back(orig.transparency_mask[it2.first]); - for (auto &it2 : new_wr_map) - port.collision_x_mask.push_back(orig.collision_x_mask[it2.first]); - new_rd_ports.push_back(port); - } - for (auto &it : new_wr_map) { - MemWr &orig = wr_ports[it.first]; - MemWr port = orig; - if (it.second != 0) - port.cell = nullptr; - if (port.wide_log2) { - port.data = port.data.extract(it.second * width, width); - port.en = port.en.extract(it.second * width, width); - port.addr = port.sub_addr(it.second); - port.wide_log2 = 0; - } - port.priority_mask.clear(); - for (auto &it2 : new_wr_map) - port.priority_mask.push_back(orig.priority_mask[it2.first]); - new_wr_ports.push_back(port); - } - std::swap(rd_ports, new_rd_ports); - std::swap(wr_ports, new_wr_ports); -} - -void Mem::emulate_priority(int idx1, int idx2, FfInitVals *initvals) -{ - auto &port1 = wr_ports[idx1]; - auto &port2 = wr_ports[idx2]; - if (!port2.priority_mask[idx1]) - return; - for (int i = 0; i < GetSize(rd_ports); i++) { - auto &rport = rd_ports[i]; - if (rport.removed) - continue; - if (rport.transparency_mask[idx1] && !(rport.transparency_mask[idx2] || rport.collision_x_mask[idx2])) - emulate_transparency(idx1, i, initvals); - } - int min_wide_log2 = std::min(port1.wide_log2, port2.wide_log2); - int max_wide_log2 = std::max(port1.wide_log2, port2.wide_log2); - bool wide1 = port1.wide_log2 > port2.wide_log2; - for (int sub = 0; sub < (1 << max_wide_log2); sub += (1 << min_wide_log2)) { - SigSpec addr1 = port1.addr; - SigSpec addr2 = port2.addr; - if (wide1) - addr1 = port1.sub_addr(sub); - else - addr2 = port2.sub_addr(sub); - SigSpec addr_eq = module->Eq(NEW_ID, addr1, addr2); - int ewidth = width << min_wide_log2; - int sub1 = wide1 ? sub : 0; - int sub2 = wide1 ? 0 : sub; - dict, SigBit> cache; - for (int pos = 0; pos < ewidth; pos++) { - SigBit &en1 = port1.en[pos + sub1 * width]; - SigBit &en2 = port2.en[pos + sub2 * width]; - std::pair key(en1, en2); - if (cache.count(key)) { - en1 = cache[key]; - } else { - SigBit active2 = module->And(NEW_ID, addr_eq, en2); - SigBit nactive2 = module->Not(NEW_ID, active2); - en1 = cache[key] = module->And(NEW_ID, en1, nactive2); - } - } - } - port2.priority_mask[idx1] = false; -} - -void Mem::emulate_transparency(int widx, int ridx, FfInitVals *initvals) { - auto &wport = wr_ports[widx]; - auto &rport = rd_ports[ridx]; - log_assert(rport.transparency_mask[widx]); - // If other write ports have priority over this one, emulate their transparency too. - for (int i = GetSize(wr_ports) - 1; i > widx; i--) { - if (wr_ports[i].removed) - continue; - if (rport.transparency_mask[i] && wr_ports[i].priority_mask[widx]) - emulate_transparency(i, ridx, initvals); - } - int min_wide_log2 = std::min(rport.wide_log2, wport.wide_log2); - int max_wide_log2 = std::max(rport.wide_log2, wport.wide_log2); - bool wide_write = wport.wide_log2 > rport.wide_log2; - // The write data FF doesn't need full reset/init behavior, as it'll be masked by - // the mux whenever this would be relevant. It does, however, need to have the same - // clock enable signal as the read port. - SigSpec wdata_q = module->addWire(NEW_ID, GetSize(wport.data)); - module->addDffe(NEW_ID, rport.clk, rport.en, wport.data, wdata_q, rport.clk_polarity, true); - for (int sub = 0; sub < (1 << max_wide_log2); sub += (1 << min_wide_log2)) { - SigSpec raddr = rport.addr; - SigSpec waddr = wport.addr; - for (int j = min_wide_log2; j < max_wide_log2; j++) - if (wide_write) - waddr = wport.sub_addr(sub); - else - raddr = rport.sub_addr(sub); - SigSpec addr_eq; - if (raddr != waddr) - addr_eq = module->Eq(NEW_ID, raddr, waddr); - int pos = 0; - int ewidth = width << min_wide_log2; - int wsub = wide_write ? sub : 0; - int rsub = wide_write ? 0 : sub; - SigSpec rdata_a = module->addWire(NEW_ID, ewidth); - while (pos < ewidth) { - int epos = pos; - while (epos < ewidth && wport.en[epos + wsub * width] == wport.en[pos + wsub * width]) - epos++; - SigSpec cond; - if (raddr != waddr) - cond = module->And(NEW_ID, wport.en[pos + wsub * width], addr_eq); - else - cond = wport.en[pos + wsub * width]; - SigSpec cond_q = module->addWire(NEW_ID); - // The FF for storing the bypass enable signal must be carefully - // constructed to preserve the overall init/reset/enable behavior - // of the whole port. - FfData ff(module, initvals, NEW_ID); - ff.width = 1; - ff.sig_q = cond_q; - ff.sig_d = cond; - ff.has_clk = true; - ff.sig_clk = rport.clk; - ff.pol_clk = rport.clk_polarity; - if (rport.en != State::S1) { - ff.has_ce = true; - ff.sig_ce = rport.en; - ff.pol_ce = true; - } - if (rport.arst != State::S0) { - ff.has_arst = true; - ff.sig_arst = rport.arst; - ff.pol_arst = true; - ff.val_arst = State::S0; - } - if (rport.srst != State::S0) { - ff.has_srst = true; - ff.sig_srst = rport.srst; - ff.pol_srst = true; - ff.val_srst = State::S0; - ff.ce_over_srst = rport.ce_over_srst; - } - if (!rport.init_value.is_fully_undef()) - ff.val_init = State::S0; - else - ff.val_init = State::Sx; - ff.emit(); - // And the final bypass mux. - SigSpec cur = rdata_a.extract(pos, epos-pos); - SigSpec other = wdata_q.extract(pos + wsub * width, epos-pos); - SigSpec dest = rport.data.extract(pos + rsub * width, epos-pos); - module->addMux(NEW_ID, cur, other, cond_q, dest); - pos = epos; - } - rport.data.replace(rsub * width, rdata_a); - } - rport.transparency_mask[widx] = false; - rport.collision_x_mask[widx] = true; -} - -void Mem::prepare_wr_merge(int idx1, int idx2, FfInitVals *initvals) { - log_assert(idx1 < idx2); - auto &port1 = wr_ports[idx1]; - auto &port2 = wr_ports[idx2]; - // If port 2 has priority over a port before port 1, make port 1 have priority too. - for (int i = 0; i < idx1; i++) - if (port2.priority_mask[i]) - port1.priority_mask[i] = true; - // If port 2 has priority over a port after port 1, emulate it. - for (int i = idx1 + 1; i < idx2; i++) - if (port2.priority_mask[i] && !wr_ports[i].removed) - emulate_priority(i, idx2, initvals); - // If some port had priority over port 2, make it have priority over the merged port too. - for (int i = idx2 + 1; i < GetSize(wr_ports); i++) { - auto &oport = wr_ports[i]; - if (oport.priority_mask[idx2]) - oport.priority_mask[idx1] = true; - } - // Make sure all read ports have identical collision/transparency behavior wrt both - // ports. - for (int i = 0; i < GetSize(rd_ports); i++) { - auto &rport = rd_ports[i]; - if (rport.removed) - continue; - // If collision already undefined with both ports, it's fine. - if (rport.collision_x_mask[idx1] && rport.collision_x_mask[idx2]) - continue; - // If one port has undefined collision, change it to the behavior - // of the other port. - if (rport.collision_x_mask[idx1]) { - rport.collision_x_mask[idx1] = false; - rport.transparency_mask[idx1] = rport.transparency_mask[idx2]; - continue; - } - if (rport.collision_x_mask[idx2]) { - rport.collision_x_mask[idx2] = false; - rport.transparency_mask[idx2] = rport.transparency_mask[idx1]; - continue; - } - // If transparent with both ports, also fine. - if (rport.transparency_mask[idx1] && rport.transparency_mask[idx2]) - continue; - // If transparent with only one, emulate it, and remove the collision-X - // flag that emulate_transparency will set (to align with the other port). - if (rport.transparency_mask[idx1]) { - emulate_transparency(i, idx1, initvals); - rport.collision_x_mask[idx1] = false; - continue; - } - if (rport.transparency_mask[idx2]) { - emulate_transparency(i, idx2, initvals); - rport.collision_x_mask[idx2] = false; - continue; - } - // If we got here, it's transparent with neither port, which is fine. - } -} - -void Mem::prepare_rd_merge(int idx1, int idx2, FfInitVals *initvals) { - auto &port1 = rd_ports[idx1]; - auto &port2 = rd_ports[idx2]; - // Note that going through write ports in order is important, since - // emulating transparency of a write port can change transparency - // mask for higher-numbered ports (due to transitive transparency - // emulation needed because of write port priority). - for (int i = 0; i < GetSize(wr_ports); i++) { - if (wr_ports[i].removed) - continue; - // Both ports undefined, OK. - if (port1.collision_x_mask[i] && port2.collision_x_mask[i]) - continue; - // Only one port undefined — change its behavior - // to align with the other port. - if (port1.collision_x_mask[i]) { - port1.collision_x_mask[i] = false; - port1.transparency_mask[i] = port2.transparency_mask[i]; - continue; - } - if (port2.collision_x_mask[i]) { - port2.collision_x_mask[i] = false; - port2.transparency_mask[i] = port1.transparency_mask[i]; - continue; - } - // Both ports transparent, OK. - if (port1.transparency_mask[i] && port2.transparency_mask[i]) - continue; - // Only one port transparent — emulate transparency - // on the other. - if (port1.transparency_mask[i]) { - emulate_transparency(i, idx1, initvals); - port1.collision_x_mask[i] = false; - continue; - } - if (port2.transparency_mask[i]) { - emulate_transparency(i, idx2, initvals); - port2.collision_x_mask[i] = false; - continue; - } - // No ports transparent, OK. - } - -} - -void Mem::widen_prep(int wide_log2) { - // Make sure start_offset and size are aligned to the port width, - // adjust if necessary. - int mask = ((1 << wide_log2) - 1); - int delta = start_offset & mask; - start_offset -= delta; - size += delta; - if (size & mask) { - size |= mask; - size++; - } -} - -void Mem::widen_wr_port(int idx, int wide_log2) { - widen_prep(wide_log2); - auto &port = wr_ports[idx]; - log_assert(port.wide_log2 <= wide_log2); - if (port.wide_log2 < wide_log2) { - SigSpec new_data, new_en; - SigSpec addr_lo = port.addr.extract(0, wide_log2); - for (int sub = 0; sub < (1 << wide_log2); sub += (1 << port.wide_log2)) - { - Const cur_addr_lo(sub, wide_log2); - if (addr_lo == cur_addr_lo) { - // Always writes to this subword. - new_data.append(port.data); - new_en.append(port.en); - } else if (addr_lo.is_fully_const()) { - // Never writes to this subword. - new_data.append(Const(State::Sx, GetSize(port.data))); - new_en.append(Const(State::S0, GetSize(port.data))); - } else { - // May or may not write to this subword. - new_data.append(port.data); - SigSpec addr_eq = module->Eq(NEW_ID, addr_lo, cur_addr_lo); - SigSpec en = module->Mux(NEW_ID, Const(State::S0, GetSize(port.data)), port.en, addr_eq); - new_en.append(en); - } - } - port.addr.replace(port.wide_log2, Const(State::S0, wide_log2 - port.wide_log2)); - port.data = new_data; - port.en = new_en; - port.wide_log2 = wide_log2; - } -} - -void Mem::emulate_rden(int idx, FfInitVals *initvals) { - auto &port = rd_ports[idx]; - log_assert(port.clk_enable); - emulate_rd_ce_over_srst(idx); - Wire *new_data = module->addWire(NEW_ID, GetSize(port.data)); - Wire *prev_data = module->addWire(NEW_ID, GetSize(port.data)); - Wire *sel = module->addWire(NEW_ID); - FfData ff_sel(module, initvals, NEW_ID); - FfData ff_data(module, initvals, NEW_ID); - ff_sel.width = 1; - ff_sel.has_clk = true; - ff_sel.sig_clk = port.clk; - ff_sel.pol_clk = port.clk_polarity; - ff_sel.sig_d = port.en; - ff_sel.sig_q = sel; - ff_data.width = GetSize(port.data); - ff_data.has_clk = true; - ff_data.sig_clk = port.clk; - ff_data.pol_clk = port.clk_polarity; - ff_data.sig_d = port.data; - ff_data.sig_q = prev_data; - if (!port.init_value.is_fully_undef()) { - ff_sel.val_init = State::S0; - ff_data.val_init = port.init_value; - port.init_value = Const(State::Sx, GetSize(port.data)); - } else { - ff_sel.val_init = State::Sx; - ff_data.val_init = Const(State::Sx, GetSize(port.data)); - } - if (port.arst != State::S0) { - ff_sel.has_arst = true; - ff_sel.val_arst = State::S0; - ff_sel.sig_arst = port.arst; - ff_sel.pol_arst = true; - ff_data.has_arst = true; - ff_data.val_arst = port.arst_value; - ff_data.sig_arst = port.arst; - ff_data.pol_arst = true; - port.arst = State::S0; - } - if (port.srst != State::S0) { - log_assert(!port.ce_over_srst); - ff_sel.has_srst = true; - ff_sel.val_srst = State::S0; - ff_sel.sig_srst = port.srst; - ff_sel.pol_srst = true; - ff_sel.ce_over_srst = false; - ff_data.has_srst = true; - ff_data.val_srst = port.srst_value; - ff_data.sig_srst = port.srst; - ff_data.pol_srst = true; - ff_data.ce_over_srst = false; - port.srst = State::S0; - } - ff_sel.emit(); - ff_data.emit(); - module->addMux(NEW_ID, prev_data, new_data, sel, port.data); - port.data = new_data; - port.en = State::S1; -} - -void Mem::emulate_reset(int idx, bool emu_init, bool emu_arst, bool emu_srst, FfInitVals *initvals) { - auto &port = rd_ports[idx]; - if (emu_init && !port.init_value.is_fully_undef()) { - Wire *sel = module->addWire(NEW_ID); - FfData ff_sel(module, initvals, NEW_ID); - Wire *new_data = module->addWire(NEW_ID, GetSize(port.data)); - ff_sel.width = 1; - ff_sel.has_clk = true; - ff_sel.sig_clk = port.clk; - ff_sel.pol_clk = port.clk_polarity; - ff_sel.sig_d = State::S1; - ff_sel.sig_q = sel; - ff_sel.val_init = State::S0; - if (port.en != State::S1) { - ff_sel.has_ce = true; - ff_sel.sig_ce = port.en; - ff_sel.pol_ce = true; - ff_sel.ce_over_srst = port.ce_over_srst; - } - if (port.arst != State::S0) { - ff_sel.has_arst = true; - ff_sel.sig_arst = port.arst; - ff_sel.pol_arst = true; - if (emu_arst && port.arst_value == port.init_value) { - // If we're going to emulate async reset anyway, and the reset - // value is the same as init value, reuse the same mux. - ff_sel.val_arst = State::S0; - port.arst = State::S0; - } else { - ff_sel.val_arst = State::S1; - } - } - if (port.srst != State::S0) { - ff_sel.has_srst = true; - ff_sel.sig_srst = port.srst; - ff_sel.pol_srst = true; - if (emu_srst && port.srst_value == port.init_value) { - ff_sel.val_srst = State::S0; - port.srst = State::S0; - } else { - ff_sel.val_srst = State::S1; - } - } - ff_sel.emit(); - module->addMux(NEW_ID, port.init_value, new_data, sel, port.data); - port.data = new_data; - port.init_value = Const(State::Sx, GetSize(port.data)); - } - if (emu_arst && port.arst != State::S0) { - Wire *sel = module->addWire(NEW_ID); - FfData ff_sel(module, initvals, NEW_ID); - Wire *new_data = module->addWire(NEW_ID, GetSize(port.data)); - ff_sel.width = 1; - ff_sel.has_clk = true; - ff_sel.sig_clk = port.clk; - ff_sel.pol_clk = port.clk_polarity; - ff_sel.sig_d = State::S1; - ff_sel.sig_q = sel; - if (port.init_value.is_fully_undef()) - ff_sel.val_init = State::Sx; - else - ff_sel.val_init = State::S1; - if (port.en != State::S1) { - ff_sel.has_ce = true; - ff_sel.sig_ce = port.en; - ff_sel.pol_ce = true; - ff_sel.ce_over_srst = port.ce_over_srst; - } - ff_sel.has_arst = true; - ff_sel.sig_arst = port.arst; - ff_sel.pol_arst = true; - ff_sel.val_arst = State::S0; - if (port.srst != State::S0) { - ff_sel.has_srst = true; - ff_sel.sig_srst = port.srst; - ff_sel.pol_srst = true; - if (emu_srst && port.srst_value == port.arst_value) { - ff_sel.val_srst = State::S0; - port.srst = State::S0; - } else { - ff_sel.val_srst = State::S1; - } - } - ff_sel.emit(); - module->addMux(NEW_ID, port.arst_value, new_data, sel, port.data); - port.data = new_data; - port.arst = State::S0; - } - if (emu_srst && port.srst != State::S0) { - Wire *sel = module->addWire(NEW_ID); - FfData ff_sel(module, initvals, NEW_ID); - Wire *new_data = module->addWire(NEW_ID, GetSize(port.data)); - ff_sel.width = 1; - ff_sel.has_clk = true; - ff_sel.sig_clk = port.clk; - ff_sel.pol_clk = port.clk_polarity; - ff_sel.sig_d = State::S1; - ff_sel.sig_q = sel; - if (port.init_value.is_fully_undef()) - ff_sel.val_init = State::Sx; - else - ff_sel.val_init = State::S1; - if (port.en != State::S1) { - ff_sel.has_ce = true; - ff_sel.sig_ce = port.en; - ff_sel.pol_ce = true; - ff_sel.ce_over_srst = port.ce_over_srst; - } - ff_sel.has_srst = true; - ff_sel.sig_srst = port.srst; - ff_sel.pol_srst = true; - ff_sel.val_srst = State::S0; - if (port.arst != State::S0) { - ff_sel.has_arst = true; - ff_sel.sig_arst = port.arst; - ff_sel.pol_arst = true; - ff_sel.val_arst = State::S1; - } - ff_sel.emit(); - module->addMux(NEW_ID, port.srst_value, new_data, sel, port.data); - port.data = new_data; - port.srst = State::S0; - } -} - -void Mem::emulate_rd_ce_over_srst(int idx) { - auto &port = rd_ports[idx]; - log_assert(port.clk_enable); - if (port.en == State::S1 || port.srst == State::S0 || !port.ce_over_srst) { - port.ce_over_srst = false; - return; - } - port.ce_over_srst = false; - port.srst = module->And(NEW_ID, port.en, port.srst); -} - -void Mem::emulate_rd_srst_over_ce(int idx) { - auto &port = rd_ports[idx]; - log_assert(port.clk_enable); - if (port.en == State::S1 || port.srst == State::S0 || port.ce_over_srst) { - port.ce_over_srst = true; - return; - } - port.ce_over_srst = true; - port.en = module->Or(NEW_ID, port.en, port.srst); -} - -bool Mem::emulate_read_first_ok() { - if (wr_ports.empty()) - return false; - SigSpec clk = wr_ports[0].clk; - bool clk_polarity = wr_ports[0].clk_polarity; - for (auto &port: wr_ports) { - if (!port.clk_enable) - return false; - if (port.clk != clk) - return false; - if (port.clk_polarity != clk_polarity) - return false; - } - bool found_read_first = false; - for (auto &port: rd_ports) { - if (!port.clk_enable) - return false; - if (port.clk != clk) - return false; - if (port.clk_polarity != clk_polarity) - return false; - // No point doing this operation if there is no read-first relationship - // in the first place. - for (int j = 0; j < GetSize(wr_ports); j++) - if (!port.transparency_mask[j] && !port.collision_x_mask[j]) - found_read_first = true; - } - return found_read_first; -} - -void Mem::emulate_read_first(FfInitVals *initvals) { - log_assert(emulate_read_first_ok()); - for (int i = 0; i < GetSize(rd_ports); i++) - for (int j = 0; j < GetSize(wr_ports); j++) - if (rd_ports[i].transparency_mask[j]) - emulate_transparency(j, i, initvals); - for (int i = 0; i < GetSize(rd_ports); i++) - for (int j = 0; j < GetSize(wr_ports); j++) { - log_assert(!rd_ports[i].transparency_mask[j]); - rd_ports[i].collision_x_mask[j] = false; - rd_ports[i].transparency_mask[j] = true; - } - for (auto &port: wr_ports) { - Wire *new_data = module->addWire(NEW_ID, GetSize(port.data)); - Wire *new_addr = module->addWire(NEW_ID, GetSize(port.addr)); - auto compressed = port.compress_en(); - Wire *new_en = module->addWire(NEW_ID, GetSize(compressed.first)); - FfData ff_data(module, initvals, NEW_ID); - FfData ff_addr(module, initvals, NEW_ID); - FfData ff_en(module, initvals, NEW_ID); - ff_data.width = GetSize(port.data); - ff_data.has_clk = true; - ff_data.sig_clk = port.clk; - ff_data.pol_clk = port.clk_polarity; - ff_data.sig_d = port.data; - ff_data.sig_q = new_data;; - ff_data.val_init = Const(State::Sx, ff_data.width); - ff_data.emit(); - ff_addr.width = GetSize(port.addr); - ff_addr.has_clk = true; - ff_addr.sig_clk = port.clk; - ff_addr.pol_clk = port.clk_polarity; - ff_addr.sig_d = port.addr; - ff_addr.sig_q = new_addr;; - ff_addr.val_init = Const(State::Sx, ff_addr.width); - ff_addr.emit(); - ff_en.width = GetSize(compressed.first); - ff_en.has_clk = true; - ff_en.sig_clk = port.clk; - ff_en.pol_clk = port.clk_polarity; - ff_en.sig_d = compressed.first; - ff_en.sig_q = new_en;; - if (inits.empty()) - ff_en.val_init = Const(State::Sx, ff_en.width); - else - ff_en.val_init = Const(State::S0, ff_en.width); - ff_en.emit(); - port.data = new_data; - port.addr = new_addr; - port.en = port.decompress_en(compressed.second, new_en); - } -} - -std::pair> MemWr::compress_en() { - SigSpec sig = en[0]; - std::vector swizzle; - SigBit prev_bit = en[0]; - int idx = 0; - for (auto &bit: en) { - if (bit != prev_bit) { - sig.append(bit); - prev_bit = bit; - idx++; - } - swizzle.push_back(idx); - } - log_assert(idx + 1 == GetSize(sig)); - return {sig, swizzle}; -} - -SigSpec MemWr::decompress_en(const std::vector &swizzle, SigSpec sig) { - SigSpec res; - for (int i: swizzle) - res.append(sig[i]); - return res; -} diff --git a/yosys/kernel/mem.h b/yosys/kernel/mem.h deleted file mode 100644 index 8c484274ccf..00000000000 --- a/yosys/kernel/mem.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 Marcelina Kościelnicka - * - * 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 MEM_H -#define MEM_H - -#include "kernel/yosys.h" -#include "kernel/ffinit.h" - -YOSYS_NAMESPACE_BEGIN - -struct MemRd : RTLIL::AttrObject { - bool removed; - Cell *cell; - int wide_log2; - bool clk_enable, clk_polarity, ce_over_srst; - Const arst_value, srst_value, init_value; - // One bit for every write port, true iff simultanous read on this - // port and write on the other port will bypass the written data - // to this port's output (default behavior is to read old value). - // Can only be set for write ports that have the same clock domain. - std::vector transparency_mask; - // One bit for every write port, true iff simultanous read on this - // port and write on the other port will return an all-X (don't care) - // value. Mutually exclusive with transparency_mask. - // Can only be set for write ports that have the same clock domain. - // For optimization purposes, this will also be set if we can - // determine that the two ports can never be active simultanously - // (making the above vacuously true). - std::vector collision_x_mask; - SigSpec clk, en, arst, srst, addr, data; - - MemRd() : removed(false), cell(nullptr), wide_log2(0), clk_enable(false), clk_polarity(true), ce_over_srst(false), clk(State::Sx), en(State::S1), arst(State::S0), srst(State::S0) {} - - // Returns the address of given subword index accessed by this port. - SigSpec sub_addr(int sub) { - SigSpec res = addr; - for (int i = 0; i < wide_log2; i++) - res[i] = State(sub >> i & 1); - return res; - } -}; - -struct MemWr : RTLIL::AttrObject { - bool removed; - Cell *cell; - int wide_log2; - bool clk_enable, clk_polarity; - std::vector priority_mask; - SigSpec clk, en, addr, data; - - MemWr() : removed(false), cell(nullptr) {} - - // Returns the address of given subword index accessed by this port. - SigSpec sub_addr(int sub) { - SigSpec res = addr; - for (int i = 0; i < wide_log2; i++) - res[i] = State(sub >> i & 1); - return res; - } - - std::pair> compress_en(); - SigSpec decompress_en(const std::vector &swizzle, SigSpec sig); -}; - -struct MemInit : RTLIL::AttrObject { - bool removed; - Cell *cell; - Const addr; - Const data; - Const en; - MemInit() : removed(false), cell(nullptr) {} -}; - -struct Mem : RTLIL::AttrObject { - Module *module; - IdString memid; - bool packed; - RTLIL::Memory *mem; - Cell *cell; - int width, start_offset, size; - std::vector inits; - std::vector rd_ports; - std::vector wr_ports; - - // Removes this memory from the module. The data in helper structures - // is unaffected except for the cell/mem fields. - void remove(); - - // Commits all changes in helper structures into the module — ports and - // inits marked as removed are actually removed, new ports/inits create - // new cells, modified port/inits are commited into their existing - // cells. Note that this reindexes the ports and inits array (actually - // removing the ports/inits marked as removed). - void emit(); - - // Marks all inits as removed. - void clear_inits(); - - // Coalesces inits: whenever two inits have overlapping or touching - // address ranges, they are combined into one, with the higher-priority - // one's data overwriting the other. Running this results in - // an inits list equivalent to the original, in which all entries - // cover disjoint (and non-touching) address ranges, and all enable - // masks are all-1. - void coalesce_inits(); - - // Checks consistency of this memory and all its ports/inits, using - // log_assert. - void check(); - - // Gathers all initialization data into a single big const covering - // the whole memory. For all non-initialized bits, Sx will be returned. - Const get_init_data() const; - - // Constructs and returns the helper structures for all memories - // in a module. - static std::vector get_all_memories(Module *module); - - // Constructs and returns the helper structures for all selected - // memories in a module. - static std::vector get_selected_memories(Module *module); - - // Converts a synchronous read port into an asynchronous one by - // extracting the data (or, in some rare cases, address) register - // into a separate cell, together with any soft-transparency - // logic necessary to preserve its semantics. Returns the created - // register cell, if any. Note that in some rare cases this function - // may succeed and perform a conversion without creating a new - // register — a nullptr result doesn't imply nothing was done. - Cell *extract_rdff(int idx, FfInitVals *initvals); - - // Splits all wide ports in this memory into equivalent narrow ones. - // This function performs no modifications at all to the actual - // netlist unless and until emit() is called. - void narrow(); - - // If write port idx2 currently has priority over write port idx1, - // inserts extra logic on idx1's enable signal to disable writes - // when idx2 is writing to the same address, then removes the priority - // from the priority mask. If there is a memory port that is - // transparent with idx1, but not with idx2, that port is converted - // to use soft transparency logic. - void emulate_priority(int idx1, int idx2, FfInitVals *initvals); - - // Creates soft-transparency logic on read port ridx, bypassing the - // data from write port widx. Should only be called when ridx is - // transparent wrt widx in the first place. Once we're done, the - // transparency_mask bit will be cleared, and the collision_x_mask - // bit will be set instead (since whatever value is read will be - // replaced by the soft transparency logic). - void emulate_transparency(int widx, int ridx, FfInitVals *initvals); - - // Prepares for merging write port idx2 into idx1 (where idx1 < idx2). - // Specifically, takes care of priority masks: any priority relations - // that idx2 had are replicated onto idx1, unless they conflict with - // priorities already present on idx1, in which case emulate_priority - // is called. Likewise, ensures transparency and undefined collision - // masks of all read ports have the same values for both ports, - // calling emulate_transparency if necessary. - void prepare_wr_merge(int idx1, int idx2, FfInitVals *initvals); - - // Prepares for merging read port idx2 into idx1. - // Specifically, makes sure the transparency and undefined collision - // masks of both ports are equal, by changing undefined behavior - // of one port to the other's defined behavior, or by calling - // emulate_transparency if necessary. - void prepare_rd_merge(int idx1, int idx2, FfInitVals *initvals); - - // Prepares the memory for widening a port to a given width. This - // involves ensuring that start_offset and size are aligned to the - // target width. - void widen_prep(int wide_log2); - - // Widens a write port up to a given width. The newly port is - // equivalent to the original, made by replicating enable/data bits - // and masking enable bits with decoders on the low part of the - // original address. - void widen_wr_port(int idx, int wide_log2); - - // Emulates a sync read port's enable functionality in soft logic, - // changing the actual read port's enable to be always-on. - void emulate_rden(int idx, FfInitVals *initvals); - - // Emulates a sync read port's initial/reset value functionality in - // soft logic, removing it from the actual read port. - void emulate_reset(int idx, bool emu_init, bool emu_arst, bool emu_srst, FfInitVals *initvals); - - // Given a read port with ce_over_srst set, converts it to a port - // with ce_over_srst unset without changing its behavior by adding - // emulation logic. - void emulate_rd_ce_over_srst(int idx); - - // Given a read port with ce_over_srst unset, converts it to a port - // with ce_over_srst set without changing its behavior by adding - // emulation logic. - void emulate_rd_srst_over_ce(int idx); - - // Returns true iff emulate_read_first makes sense to call. - bool emulate_read_first_ok(); - - // Emulates all read-first read-write port relationships in terms of - // all-transparent ports, by delaying all write ports by one cycle. - // This can only be used when all read ports and all write ports are - // in the same clock domain. - void emulate_read_first(FfInitVals *initvals); - - Mem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {} -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/modtools.h b/yosys/kernel/modtools.h deleted file mode 100644 index 34a23b37981..00000000000 --- a/yosys/kernel/modtools.h +++ /dev/null @@ -1,575 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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, const RTLIL::SigSpec &sig) 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, const RTLIL::SigSig &sigsig) 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, const std::vector&) override - { - log_assert(module == mod); - auto_reload_module = true; - } - - void notify_blackout(RTLIL::Module *mod) 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(RTLIL::Design *design, RTLIL::Module *module = nullptr) : design(design), module(NULL) - { - ct.setup(design); - if (module) - setup(module); - } - - void setup(RTLIL::Module *module, CellTypes *filter_ct = NULL) - { - this->module = module; - - sigmap.set(module); - - signal_drivers.clear(); - signal_consumers.clear(); - signal_inputs.clear(); - signal_outputs.clear(); - cell_inputs.clear(); - cell_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 - - 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; - } - - 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; - } - - 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; - } - - 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/qcsat.cc b/yosys/kernel/qcsat.cc deleted file mode 100644 index aaee984fbaa..00000000000 --- a/yosys/kernel/qcsat.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2021 Marcelina Kościelnicka - * - * 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/qcsat.h" - -USING_YOSYS_NAMESPACE - -std::vector QuickConeSat::importSig(SigSpec sig) -{ - sig = modwalker.sigmap(sig); - for (auto bit : sig) - bits_queue.insert(bit); - return satgen.importSigSpec(sig); -} - -int QuickConeSat::importSigBit(SigBit bit) -{ - bit = modwalker.sigmap(bit); - bits_queue.insert(bit); - return satgen.importSigBit(bit); -} - -void QuickConeSat::prepare() -{ - while (!bits_queue.empty()) - { - pool portbits; - modwalker.get_drivers(portbits, bits_queue); - - for (auto bit : bits_queue) - if (bit.wire && bit.wire->get_bool_attribute(ID::onehot) && !imported_onehot.count(bit.wire)) - { - std::vector bits = satgen.importSigSpec(bit.wire); - for (int i : bits) - for (int j : bits) - if (i != j) - ez->assume(ez->NOT(i), j); - imported_onehot.insert(bit.wire); - } - - bits_queue.clear(); - - for (auto &pbit : portbits) - { - if (imported_cells.count(pbit.cell)) - continue; - if (cell_complexity(pbit.cell) > max_cell_complexity) - continue; - if (max_cell_outs && GetSize(modwalker.cell_outputs[pbit.cell]) > max_cell_outs) - continue; - auto &inputs = modwalker.cell_inputs[pbit.cell]; - bits_queue.insert(inputs.begin(), inputs.end()); - satgen.importCell(pbit.cell); - imported_cells.insert(pbit.cell); - } - - if (max_cell_count && GetSize(imported_cells) > max_cell_count) - break; - } -} - -int QuickConeSat::cell_complexity(RTLIL::Cell *cell) -{ - if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($_BUF_))) - return 0; - if (cell->type.in(ID($not), ID($and), ID($or), ID($xor), ID($xnor), - ID($reduce_and), ID($reduce_or), ID($reduce_xor), - ID($reduce_xnor), ID($reduce_bool), - ID($logic_not), ID($logic_and), ID($logic_or), - ID($eq), ID($ne), ID($eqx), ID($nex), ID($fa), - ID($mux), ID($pmux), ID($bmux), ID($demux), ID($lut), ID($sop), - ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), - ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), - ID($_MUX_), ID($_NMUX_), ID($_MUX4_), ID($_MUX8_), ID($_MUX16_), - ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) - return 1; - if (cell->type.in(ID($neg), ID($add), ID($sub), ID($alu), ID($lcu), - ID($lt), ID($le), ID($gt), ID($ge))) - return 2; - if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) - return 3; - if (cell->type.in(ID($mul), ID($macc), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow))) - return 4; - // Unknown cell. - return 5; -} diff --git a/yosys/kernel/qcsat.h b/yosys/kernel/qcsat.h deleted file mode 100644 index e4d3c3c5dc6..00000000000 --- a/yosys/kernel/qcsat.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2021 Marcelina Kościelnicka - * - * 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 QCSAT_H -#define QCSAT_H - -#include "kernel/satgen.h" -#include "kernel/modtools.h" - -YOSYS_NAMESPACE_BEGIN - -// This is a helper class meant for easy construction of quick SAT queries -// to a combinatorial input cone of some set of signals, meant for SAT-based -// optimizations. Various knobs are provided to set just how much of the -// cone should be included in the model — since this class is meant for -// optimization, it should not be a correctness problem when some cells are -// skipped and the solver spuriously returns SAT with a solution that -// cannot exist in reality due to skipped constraints (ie. only UNSAT results -// from this class should be considered binding). -struct QuickConeSat { - ModWalker &modwalker; - ezSatPtr ez; - SatGen satgen; - - // The effort level knobs. - - // The maximum "complexity level" of cells that will be imported. - // - 1: bitwise operations, muxes, equality comparisons, lut, sop, fa - // - 2: addition, subtraction, greater/less than comparisons, lcu - // - 3: shifts - // - 4: multiplication, division, power - int max_cell_complexity = 2; - // The maximum number of cells to import, or 0 for no limit. - int max_cell_count = 0; - // If non-0, skip importing cells with more than this number of output bits. - int max_cell_outs = 0; - - // Internal state. - pool imported_cells; - pool imported_onehot; - pool bits_queue; - - QuickConeSat(ModWalker &modwalker) : modwalker(modwalker), ez(), satgen(ez.get(), &modwalker.sigmap) {} - - // Imports a signal into the SAT solver, queues its input cone to be - // imported in the next prepare() call. - std::vector importSig(SigSpec sig); - int importSigBit(SigBit bit); - - // Imports the input cones of all previously importSig'd signals into - // the SAT solver. - void prepare(); - - // Returns the "complexity level" of a given cell. - static int cell_complexity(RTLIL::Cell *cell); -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/register.cc b/yosys/kernel/register.cc deleted file mode 100644 index 9ffb17c1a97..00000000000 --- a/yosys/kernel/register.cc +++ /dev/null @@ -1,997 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 - -#ifdef YOSYS_ENABLE_ZLIB -#include - -PRIVATE_NAMESPACE_BEGIN -#define GZ_BUFFER_SIZE 8192 -void decompress_gzip(const std::string &filename, std::stringstream &out) -{ - char buffer[GZ_BUFFER_SIZE]; - int bytes_read; - gzFile gzf = gzopen(filename.c_str(), "rb"); - while(!gzeof(gzf)) { - bytes_read = gzread(gzf, reinterpret_cast(buffer), GZ_BUFFER_SIZE); - out.write(buffer, bytes_read); - } - gzclose(gzf); -} - -/* -An output stream that uses a stringbuf to buffer data internally, -using zlib to write gzip-compressed data every time the stream is flushed. -*/ -class gzip_ostream : public std::ostream { -public: - gzip_ostream() : std::ostream(nullptr) - { - rdbuf(&outbuf); - } - bool open(const std::string &filename) - { - return outbuf.open(filename); - } -private: - class gzip_streambuf : public std::stringbuf { - public: - gzip_streambuf() { }; - bool open(const std::string &filename) - { - gzf = gzopen(filename.c_str(), "wb"); - return gzf != nullptr; - } - virtual int sync() override - { - gzwrite(gzf, reinterpret_cast(str().c_str()), unsigned(str().size())); - str(""); - return 0; - } - virtual ~gzip_streambuf() - { - sync(); - gzclose(gzf); - } - private: - gzFile gzf = nullptr; - } outbuf; -}; -PRIVATE_NAMESPACE_END - -#endif - -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() -{ - if (pass_register.count(pass_name)) - log_error("Unable to register pass '%s', pass already exists!\n", pass_name.c_str()); - - pass_register[pass_name] = this; -} - -void Pass::init_register() -{ - vector added_passes; - while (first_queued_pass) { - added_passes.push_back(first_queued_pass); - first_queued_pass->run_register(); - first_queued_pass = first_queued_pass->next_queued_pass; - } - for (auto added_pass : added_passes) - added_pass->on_register(); -} - -void Pass::done_register() -{ - for (auto &it : pass_register) - it.second->on_shutdown(); - - frontend_register.clear(); - pass_register.clear(); - backend_register.clear(); - log_assert(first_queued_pass == NULL); -} - -void Pass::on_register() -{ -} - -void Pass::on_shutdown() -{ -} - -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.compare(0, 1, "-") == 0) - 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] == '!') { -#if !defined(YOSYS_DISABLE_SPAWN) - 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; -#else - log_cmd_error("Shell is not available.\n"); -#endif - } - - 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()); - - if (pass_register[args[0]]->experimental_flag) - log_experimental("%s", 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(); -} - -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); - active_design->check(); - } -} - -void ScriptPass::run_nocheck(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() -{ - if (pass_register.count(pass_name)) - log_error("Unable to register pass '%s', pass already exists!\n", pass_name.c_str()); - pass_register[pass_name] = this; - - if (frontend_register.count(frontend_name)) - log_error("Unable to register frontend '%s', frontend already exists!\n", frontend_name.c_str()); - - 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 bin_input) -{ - bool called_with_fp = f != NULL; - - next_args.clear(); - - if (argidx < args.size()) - { - std::string arg = args[argidx]; - - if (arg.compare(0, 1, "-") == 0) - 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; - //Accommodate heredocs with EOT marker spaced out from "<<", e.g. "<< EOT" vs. "< 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.compare(indent, eot_marker.size(), eot_marker) == 0) - 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(), bin_input ? std::ifstream::binary : std::ifstream::in); - yosys_input_files.insert(filename); - if (ff->fail()) { - delete ff; - ff = nullptr; - } - f = ff; - if (f != NULL) { - // Check for gzip magic - unsigned char magic[3]; - int n = 0; - while (n < 3) - { - int c = ff->get(); - if (c != EOF) { - magic[n] = (unsigned char) c; - } - n++; - } - if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) { - #ifdef YOSYS_ENABLE_ZLIB - log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str()); - if (magic[2] != 8) - log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n", - filename.c_str(), unsigned(magic[2])); - delete ff; - std::stringstream *df = new std::stringstream(); - decompress_gzip(filename, *df); - f = df; - #else - log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str()); - #endif - } else { - ff->clear(); - ff->seekg(0, std::ios::beg); - } - } - } - 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].compare(0, 1, "-") == 0) - 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); - } -} - -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() -{ - if (pass_register.count(pass_name)) - log_error("Unable to register pass '%s', pass already exists!\n", pass_name.c_str()); - pass_register[pass_name] = this; - - if (backend_register.count(backend_name)) - log_error("Unable to register backend '%s', backend already exists!\n", backend_name.c_str()); - 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 bin_output) -{ - bool called_with_fp = f != NULL; - - for (; argidx < args.size(); argidx++) - { - std::string arg = args[argidx]; - - if (arg.compare(0, 1, "-") == 0 && 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); - if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".gz") == 0) { -#ifdef YOSYS_ENABLE_ZLIB - gzip_ostream *gf = new gzip_ostream; - if (!gf->open(filename)) { - delete gf; - log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); - } - yosys_output_files.insert(filename); - f = gf; -#else - log_cmd_error("Yosys is compiled without zlib support, unable to write gzip output.\n"); -#endif - } else { - std::ofstream *ff = new std::ofstream; - ff->open(filename.c_str(), bin_output ? (std::ofstream::trunc | std::ofstream::binary) : 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(); -} - -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() 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 write_rst(std::string cmd, std::string title, std::string text) - { - FILE *f = fopen(stringf("docs/source/cmd/%s.rst", cmd.c_str()).c_str(), "wt"); - // make header - size_t char_len = cmd.length() + 3 + title.length(); - std::string title_line = "\n"; - title_line.insert(0, char_len, '='); - fprintf(f, "%s", title_line.c_str()); - fprintf(f, "%s - %s\n", cmd.c_str(), title.c_str()); - fprintf(f, "%s\n", title_line.c_str()); - fprintf(f, ".. raw:: latex\n\n \\begin{comment}\n\n"); - - // render html - fprintf(f, ":code:`yosys> help %s`\n", cmd.c_str()); - fprintf(f, "--------------------------------------------------------------------------------\n\n"); - fprintf(f, ".. container:: cmdref\n"); - std::stringstream ss; - std::string textcp = text; - ss << text; - bool IsUsage = true; - int blank_count = 0; - size_t def_strip_count = 0; - bool WasDefinition = false; - for (std::string line; std::getline(ss, line, '\n');) { - // find position of first non space character - std::size_t first_pos = line.find_first_not_of(" \t"); - std::size_t last_pos = line.find_last_not_of(" \t"); - if (first_pos == std::string::npos) { - // skip formatting empty lines - if (!WasDefinition) - fputc('\n', f); - blank_count += 1; - continue; - } - - // strip leading and trailing whitespace - std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1); - bool IsDefinition = stripped_line[0] == '-'; - IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>'; - bool IsDedent = def_strip_count && first_pos <= def_strip_count; - bool IsIndent = first_pos == 2 || first_pos == 4; - if (cmd.compare(0, 7, "verific") == 0) - // verific.cc has strange and different formatting from the rest - IsIndent = false; - - // another usage block - bool NewUsage = stripped_line.find(cmd) == 0; - - if (IsUsage) { - if (stripped_line.compare(0, 4, "See ") == 0) { - // description refers to another function - fprintf(f, "\n %s\n", stripped_line.c_str()); - } else { - // usage should be the first line of help output - fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str()); - WasDefinition = true; - } - IsUsage = false; - } else if (IsIndent && NewUsage && (blank_count >= 2 || WasDefinition)) { - // another usage block - fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str()); - WasDefinition = true; - def_strip_count = 0; - } else if (IsIndent && IsDefinition && (blank_count || WasDefinition)) { - // format definition term - fprintf(f, "\n\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str()); - WasDefinition = true; - def_strip_count = first_pos; - } else { - if (IsDedent) { - fprintf(f, "\n\n ::\n"); - def_strip_count = first_pos; - } else if (WasDefinition) { - fprintf(f, " ::\n"); - WasDefinition = false; - } - fprintf(f, "\n %s", line.substr(def_strip_count, std::string::npos).c_str()); - } - - blank_count = 0; - } - fputc('\n', f); - - // render latex - fprintf(f, ".. raw:: latex\n\n \\end{comment}\n\n"); - fprintf(f, ".. only:: latex\n\n"); - fprintf(f, " ::\n\n"); - std::stringstream ss2; - ss2 << textcp; - for (std::string line; std::getline(ss2, line, '\n');) { - fprintf(f, " %s\n", line.c_str()); - } - fclose(f); - } - void execute(std::vector args, RTLIL::Design*) 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(); - if (it.second->experimental_flag) { - log("\n"); - log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str()); - log("\n"); - } - } - } - 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-rst-command-reference-manual") { - for (auto &it : pass_register) { - std::ostringstream buf; - log_streams.push_back(&buf); - it.second->help(); - if (it.second->experimental_flag) { - log("\n"); - log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str()); - log("\n"); - } - log_streams.pop_back(); - write_rst(it.first, it.second->short_help, buf.str()); - } - } - else if (pass_register.count(args[1])) { - pass_register.at(args[1])->help(); - if (pass_register.at(args[1])->experimental_flag) { - log("\n"); - log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", args[1].c_str()); - log("\n"); - } - } - 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() 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*) 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() 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 15750af2a40..00000000000 --- a/yosys/kernel/register.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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; - bool experimental_flag = false; - - void experimental() { - experimental_flag = true; - } - - 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(); - - virtual void on_register(); - virtual void on_shutdown(); -}; - -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_nocheck(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() override; - ~Frontend() override; - void execute(std::vector args, RTLIL::Design *design) override 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, bool bin_input = false); - - 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() override; - ~Backend() override; - void execute(std::vector args, RTLIL::Design *design) override 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, bool bin_output = false); - - 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, const 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 7f3508b2f49..00000000000 --- a/yosys/kernel/rtlil.cc +++ /dev/null @@ -1,4989 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 "kernel/binding.h" -#include "frontends/verilog/verilog_frontend.h" -#include "frontends/verilog/preproc.h" -#include "backends/rtlil/rtlil_backend.h" - -#include -#include - -YOSYS_NAMESPACE_BEGIN - -RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard; -std::vector RTLIL::IdString::global_id_storage_; -dict RTLIL::IdString::global_id_index_; -#ifndef YOSYS_NO_IDS_REFCNT -std::vector RTLIL::IdString::global_refcount_storage_; -std::vector RTLIL::IdString::global_free_idx_list_; -#endif -#ifdef YOSYS_USE_STICKY_IDS -int RTLIL::IdString::last_created_idx_[8]; -int RTLIL::IdString::last_created_idx_ptr_; -#endif - -#define X(_id) IdString RTLIL::ID::_id; -#include "kernel/constids.inc" -#undef X - -dict RTLIL::constpad; - -const pool &RTLIL::builtin_ff_cell_types() { - static const pool res = { - ID($sr), - ID($ff), - ID($dff), - ID($dffe), - ID($dffsr), - ID($dffsre), - ID($adff), - ID($adffe), - ID($aldff), - ID($aldffe), - ID($sdff), - ID($sdffe), - ID($sdffce), - ID($dlatch), - ID($adlatch), - ID($dlatchsr), - ID($_DFFE_NN_), - ID($_DFFE_NP_), - ID($_DFFE_PN_), - ID($_DFFE_PP_), - ID($_DFFSR_NNN_), - ID($_DFFSR_NNP_), - ID($_DFFSR_NPN_), - ID($_DFFSR_NPP_), - ID($_DFFSR_PNN_), - ID($_DFFSR_PNP_), - ID($_DFFSR_PPN_), - ID($_DFFSR_PPP_), - ID($_DFFSRE_NNNN_), - ID($_DFFSRE_NNNP_), - ID($_DFFSRE_NNPN_), - ID($_DFFSRE_NNPP_), - ID($_DFFSRE_NPNN_), - ID($_DFFSRE_NPNP_), - ID($_DFFSRE_NPPN_), - ID($_DFFSRE_NPPP_), - ID($_DFFSRE_PNNN_), - ID($_DFFSRE_PNNP_), - ID($_DFFSRE_PNPN_), - ID($_DFFSRE_PNPP_), - ID($_DFFSRE_PPNN_), - ID($_DFFSRE_PPNP_), - ID($_DFFSRE_PPPN_), - ID($_DFFSRE_PPPP_), - ID($_DFF_N_), - ID($_DFF_P_), - ID($_DFF_NN0_), - ID($_DFF_NN1_), - ID($_DFF_NP0_), - ID($_DFF_NP1_), - ID($_DFF_PN0_), - ID($_DFF_PN1_), - ID($_DFF_PP0_), - ID($_DFF_PP1_), - ID($_DFFE_NN0N_), - ID($_DFFE_NN0P_), - ID($_DFFE_NN1N_), - ID($_DFFE_NN1P_), - ID($_DFFE_NP0N_), - ID($_DFFE_NP0P_), - ID($_DFFE_NP1N_), - ID($_DFFE_NP1P_), - ID($_DFFE_PN0N_), - ID($_DFFE_PN0P_), - ID($_DFFE_PN1N_), - ID($_DFFE_PN1P_), - ID($_DFFE_PP0N_), - ID($_DFFE_PP0P_), - ID($_DFFE_PP1N_), - ID($_DFFE_PP1P_), - ID($_ALDFF_NN_), - ID($_ALDFF_NP_), - ID($_ALDFF_PN_), - ID($_ALDFF_PP_), - ID($_ALDFFE_NNN_), - ID($_ALDFFE_NNP_), - ID($_ALDFFE_NPN_), - ID($_ALDFFE_NPP_), - ID($_ALDFFE_PNN_), - ID($_ALDFFE_PNP_), - ID($_ALDFFE_PPN_), - ID($_ALDFFE_PPP_), - ID($_SDFF_NN0_), - ID($_SDFF_NN1_), - ID($_SDFF_NP0_), - ID($_SDFF_NP1_), - ID($_SDFF_PN0_), - ID($_SDFF_PN1_), - ID($_SDFF_PP0_), - ID($_SDFF_PP1_), - ID($_SDFFE_NN0N_), - ID($_SDFFE_NN0P_), - ID($_SDFFE_NN1N_), - ID($_SDFFE_NN1P_), - ID($_SDFFE_NP0N_), - ID($_SDFFE_NP0P_), - ID($_SDFFE_NP1N_), - ID($_SDFFE_NP1P_), - ID($_SDFFE_PN0N_), - ID($_SDFFE_PN0P_), - ID($_SDFFE_PN1N_), - ID($_SDFFE_PN1P_), - ID($_SDFFE_PP0N_), - ID($_SDFFE_PP0P_), - ID($_SDFFE_PP1N_), - ID($_SDFFE_PP1P_), - ID($_SDFFCE_NN0N_), - ID($_SDFFCE_NN0P_), - ID($_SDFFCE_NN1N_), - ID($_SDFFCE_NN1P_), - ID($_SDFFCE_NP0N_), - ID($_SDFFCE_NP0P_), - ID($_SDFFCE_NP1N_), - ID($_SDFFCE_NP1P_), - ID($_SDFFCE_PN0N_), - ID($_SDFFCE_PN0P_), - ID($_SDFFCE_PN1N_), - ID($_SDFFCE_PN1P_), - ID($_SDFFCE_PP0N_), - ID($_SDFFCE_PP0P_), - ID($_SDFFCE_PP1N_), - ID($_SDFFCE_PP1P_), - ID($_SR_NN_), - ID($_SR_NP_), - ID($_SR_PN_), - ID($_SR_PP_), - ID($_DLATCH_N_), - ID($_DLATCH_P_), - ID($_DLATCH_NN0_), - ID($_DLATCH_NN1_), - ID($_DLATCH_NP0_), - ID($_DLATCH_NP1_), - ID($_DLATCH_PN0_), - ID($_DLATCH_PN1_), - ID($_DLATCH_PP0_), - ID($_DLATCH_PP1_), - ID($_DLATCHSR_NNN_), - ID($_DLATCHSR_NNP_), - ID($_DLATCHSR_NPN_), - ID($_DLATCHSR_NPP_), - ID($_DLATCHSR_PNN_), - ID($_DLATCHSR_PNP_), - ID($_DLATCHSR_PPN_), - ID($_DLATCHSR_PPP_), - ID($_FF_), - }; - return res; -} - -RTLIL::Const::Const(const std::string &str) -{ - flags = RTLIL::CONST_FLAG_STRING; - bits.reserve(str.size() * 8); - 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 ? State::S1 : State::S0); - ch = ch >> 1; - } - } -} - -RTLIL::Const::Const(int val, int width) -{ - flags = RTLIL::CONST_FLAG_NONE; - bits.reserve(width); - for (int i = 0; i < width; i++) { - bits.push_back((val & 1) != 0 ? State::S1 : State::S0); - val = val >> 1; - } -} - -RTLIL::Const::Const(RTLIL::State bit, int width) -{ - flags = RTLIL::CONST_FLAG_NONE; - bits.reserve(width); - for (int i = 0; i < width; i++) - bits.push_back(bit); -} - -RTLIL::Const::Const(const std::vector &bits) -{ - flags = RTLIL::CONST_FLAG_NONE; - this->bits.reserve(bits.size()); - for (const auto &b : bits) - this->bits.emplace_back(b ? State::S1 : State::S0); -} - -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] == State::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] == State::S1) - ret |= 1 << i; - if (is_signed && bits.back() == State::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; - ret.reserve(bits.size()); - 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(const std::string &str) -{ - Const c; - c.bits.reserve(str.size()); - 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; - string.reserve(GetSize(bits)/8); - for (int i = 0; i < GetSize(bits); 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.append({ch}); - } - std::reverse(string.begin(), string.end()); - return string; -} - -bool RTLIL::Const::is_fully_zero() const -{ - cover("kernel.rtlil.const.is_fully_zero"); - - for (const 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 (const 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 (const 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 (const auto &bit : bits) - if (bit != RTLIL::State::Sx && bit != RTLIL::State::Sz) - return false; - - return true; -} - -bool RTLIL::Const::is_fully_undef_x_only() const -{ - cover("kernel.rtlil.const.is_fully_undef_x_only"); - - for (const auto &bit : bits) - if (bit != RTLIL::State::Sx) - return false; - - return true; -} - -bool RTLIL::Const::is_onehot(int *pos) const -{ - cover("kernel.rtlil.const.is_onehot"); - - bool found = false; - for (int i = 0; i < GetSize(*this); i++) { - auto &bit = bits[i]; - if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1) - return false; - if (bit == RTLIL::State::S1) { - if (found) - return false; - if (pos) - *pos = i; - found = true; - } - } - return found; -} - -bool RTLIL::AttrObject::has_attribute(const RTLIL::IdString &id) const -{ - return attributes.count(id); -} - -void RTLIL::AttrObject::set_bool_attribute(const RTLIL::IdString &id, bool value) -{ - if (value) - attributes[id] = RTLIL::Const(1); - else - attributes.erase(id); -} - -bool RTLIL::AttrObject::get_bool_attribute(const 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_string_attribute(const RTLIL::IdString& id, string value) -{ - if (value.empty()) - attributes.erase(id); - else - attributes[id] = value; -} - -string RTLIL::AttrObject::get_string_attribute(const RTLIL::IdString &id) const -{ - std::string value; - const auto it = attributes.find(id); - if (it != attributes.end()) - value = it->second.decode_string(); - return value; -} - -void RTLIL::AttrObject::set_strpool_attribute(const RTLIL::IdString& id, const pool &data) -{ - string attrval; - for (const auto &s : data) { - if (!attrval.empty()) - attrval += "|"; - attrval += s; - } - set_string_attribute(id, attrval); -} - -void RTLIL::AttrObject::add_strpool_attribute(const 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(const RTLIL::IdString &id) const -{ - pool data; - if (attributes.count(id) != 0) - for (auto s : split_tokens(get_string_attribute(id), "|")) - data.insert(s); - return data; -} - -void RTLIL::AttrObject::set_hdlname_attribute(const vector &hierarchy) -{ - string attrval; - for (const auto &ident : hierarchy) { - if (!attrval.empty()) - attrval += " "; - attrval += ident; - } - set_string_attribute(ID::hdlname, attrval); -} - -vector RTLIL::AttrObject::get_hdlname_attribute() const -{ - return split_tokens(get_string_attribute(ID::hdlname), " "); -} - -void RTLIL::AttrObject::set_intvec_attribute(const RTLIL::IdString& id, const vector &data) -{ - std::stringstream attrval; - for (auto &i : data) { - if (attrval.tellp() > 0) - attrval << " "; - attrval << i; - } - attributes[id] = RTLIL::Const(attrval.str()); -} - -vector RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) const -{ - vector data; - auto it = attributes.find(id); - if (it != attributes.end()) - for (const auto &s : split_tokens(attributes.at(id).decode_string())) { - char *end = nullptr; - errno = 0; - long value = strtol(s.c_str(), &end, 10); - if (end != s.c_str() + s.size()) - log_cmd_error("Literal for intvec attribute has invalid format"); - if (errno == ERANGE || value < INT_MIN || value > INT_MAX) - log_cmd_error("Literal for intvec attribute is out of range"); - data.push_back(value); - } - return data; -} - -bool RTLIL::Selection::selected_module(const 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(const 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(const RTLIL::IdString &mod_name, const 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() - : verilog_defines (new define_map_t) -{ - 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 &pr : modules_) - delete pr.second; - for (auto n : bindings_) - delete n; - 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(const RTLIL::IdString& name) -{ - return modules_.count(name) ? modules_.at(name) : NULL; -} - -const RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) const -{ - 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(ID::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); - } -} - -void RTLIL::Design::add(RTLIL::Binding *binding) -{ - log_assert(binding != nullptr); - bindings_.push_back(binding); -} - -RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name) -{ - if (modules_.count(name) != 0) - log_error("Attempted to add new module named '%s', but a module by that name already exists\n", name.c_str()); - 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(const std::string &varname) -{ - scratchpad.erase(varname); -} - -void RTLIL::Design::scratchpad_set_int(const std::string &varname, int value) -{ - scratchpad[varname] = stringf("%d", value); -} - -void RTLIL::Design::scratchpad_set_bool(const std::string &varname, bool value) -{ - scratchpad[varname] = value ? "true" : "false"; -} - -void RTLIL::Design::scratchpad_set_string(const std::string &varname, std::string value) -{ - scratchpad[varname] = std::move(value); -} - -int RTLIL::Design::scratchpad_get_int(const std::string &varname, int default_value) const -{ - auto it = scratchpad.find(varname); - if (it == scratchpad.end()) - return default_value; - - const std::string &str = it->second; - - 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(const std::string &varname, bool default_value) const -{ - auto it = scratchpad.find(varname); - if (it == scratchpad.end()) - return default_value; - - const std::string &str = it->second; - - if (str == "0" || str == "false") - return false; - - if (str == "1" || str == "true") - return true; - - return default_value; -} - -std::string RTLIL::Design::scratchpad_get_string(const std::string &varname, const std::string &default_value) const -{ - auto it = scratchpad.find(varname); - if (it == scratchpad.end()) - return default_value; - - return it->second; -} - -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); - log_assert(refcount_modules_ == 0); - 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(const 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(const 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(const RTLIL::IdString& mod_name, const 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(bool include_wb) const -{ - std::vector result; - result.reserve(modules_.size()); - for (auto &it : modules_) - if (it.second->get_blackbox_attribute(include_wb)) - 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 &pr : wires_) - delete pr.second; - for (auto &pr : memories) - delete pr.second; - for (auto &pr : cells_) - delete pr.second; - for (auto &pr : processes) - delete pr.second; - for (auto binding : bindings_) - delete binding; -#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(); - - connections_.clear(); - - remove(delwires); - set_bool_attribute(ID::blackbox); -} - -void RTLIL::Module::expand_interfaces(RTLIL::Design *, const dict &) -{ - log_error("Class doesn't support expand_interfaces (module: `%s')!\n", id2cstr(name)); -} - -bool RTLIL::Module::reprocess_if_necessary(RTLIL::Design *) -{ - return false; -} - -RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, const 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*, const dict &, const dict &, const 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(const 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; - RTLIL_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 RTLIL::IdString& name) - { - auto it = cell->parameters.find(name); - if (it == cell->parameters.end()) - error(__LINE__); - expected_params.insert(name); - return it->second.as_int(); - } - - int param_bool(const RTLIL::IdString& name) - { - int v = param(name); - if (GetSize(cell->parameters.at(name)) > 32) - error(__LINE__); - if (v != 0 && v != 1) - error(__LINE__); - return v; - } - - int param_bool(const RTLIL::IdString& name, bool expected) - { - int v = param_bool(name); - if (v != expected) - error(__LINE__); - return v; - } - - void param_bits(const RTLIL::IdString& name, int width) - { - param(name); - if (GetSize(cell->parameters.at(name).bits) != width) - error(__LINE__); - } - - void port(const RTLIL::IdString& name, int width) - { - auto it = cell->connections_.find(name); - if (it == cell->connections_.end()) - error(__LINE__); - if (GetSize(it->second) != width) - error(__LINE__); - expected_ports.insert(name); - } - - void check_expected(bool check_matched_sign = false) - { - 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 (check_matched_sign) { - log_assert(expected_params.count(ID::A_SIGNED) != 0 && expected_params.count(ID::B_SIGNED) != 0); - bool a_is_signed = cell->parameters.at(ID::A_SIGNED).as_bool(); - bool b_is_signed = cell->parameters.at(ID::B_SIGNED).as_bool(); - if (a_is_signed != b_is_signed) - error(__LINE__); - } - } - - void check() - { - if (!cell->type.begins_with("$") || cell->type.begins_with("$__") || cell->type.begins_with("$paramod") || cell->type.begins_with("$fmcombine") || - cell->type.begins_with("$verific$") || cell->type.begins_with("$array:") || cell->type.begins_with("$extern:")) - return; - - if (cell->type.in(ID($not), ID($pos), ID($neg))) { - param_bool(ID::A_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(); - return; - } - - if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) { - param_bool(ID::A_SIGNED); - param_bool(ID::B_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(true); - return; - } - - if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool))) { - param_bool(ID::A_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(); - return; - } - - if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr))) { - param_bool(ID::A_SIGNED); - param_bool(ID::B_SIGNED, /*expected=*/false); - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(/*check_matched_sign=*/false); - return; - } - - if (cell->type.in(ID($shift), ID($shiftx))) { - if (cell->type == ID($shiftx)) { - param_bool(ID::A_SIGNED, /*expected=*/false); - } else { - param_bool(ID::A_SIGNED); - } - param_bool(ID::B_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(/*check_matched_sign=*/false); - return; - } - - if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) { - param_bool(ID::A_SIGNED); - param_bool(ID::B_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(true); - return; - } - - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow))) { - param_bool(ID::A_SIGNED); - param_bool(ID::B_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(cell->type != ID($pow)); - return; - } - - if (cell->type == ID($fa)) { - port(ID::A, param(ID::WIDTH)); - port(ID::B, param(ID::WIDTH)); - port(ID::C, param(ID::WIDTH)); - port(ID::X, param(ID::WIDTH)); - port(ID::Y, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($lcu)) { - port(ID::P, param(ID::WIDTH)); - port(ID::G, param(ID::WIDTH)); - port(ID::CI, 1); - port(ID::CO, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($alu)) { - param_bool(ID::A_SIGNED); - param_bool(ID::B_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::CI, 1); - port(ID::BI, 1); - port(ID::X, param(ID::Y_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - port(ID::CO, param(ID::Y_WIDTH)); - check_expected(true); - return; - } - - if (cell->type == ID($macc)) { - param(ID::CONFIG); - param(ID::CONFIG_WIDTH); - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(); - Macc().from_cell(cell); - return; - } - - if (cell->type == ID($logic_not)) { - param_bool(ID::A_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(); - return; - } - - if (cell->type.in(ID($logic_and), ID($logic_or))) { - param_bool(ID::A_SIGNED); - param_bool(ID::B_SIGNED); - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - check_expected(/*check_matched_sign=*/false); - return; - } - - if (cell->type == ID($slice)) { - param(ID::OFFSET); - port(ID::A, param(ID::A_WIDTH)); - port(ID::Y, param(ID::Y_WIDTH)); - if (param(ID::OFFSET) + param(ID::Y_WIDTH) > param(ID::A_WIDTH)) - error(__LINE__); - check_expected(); - return; - } - - if (cell->type == ID($concat)) { - port(ID::A, param(ID::A_WIDTH)); - port(ID::B, param(ID::B_WIDTH)); - port(ID::Y, param(ID::A_WIDTH) + param(ID::B_WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($mux)) { - port(ID::A, param(ID::WIDTH)); - port(ID::B, param(ID::WIDTH)); - port(ID::S, 1); - port(ID::Y, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($pmux)) { - port(ID::A, param(ID::WIDTH)); - port(ID::B, param(ID::WIDTH) * param(ID::S_WIDTH)); - port(ID::S, param(ID::S_WIDTH)); - port(ID::Y, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($bmux)) { - port(ID::A, param(ID::WIDTH) << param(ID::S_WIDTH)); - port(ID::S, param(ID::S_WIDTH)); - port(ID::Y, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($demux)) { - port(ID::A, param(ID::WIDTH)); - port(ID::S, param(ID::S_WIDTH)); - port(ID::Y, param(ID::WIDTH) << param(ID::S_WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($lut)) { - param(ID::LUT); - port(ID::A, param(ID::WIDTH)); - port(ID::Y, 1); - check_expected(); - return; - } - - if (cell->type == ID($sop)) { - param(ID::DEPTH); - param(ID::TABLE); - port(ID::A, param(ID::WIDTH)); - port(ID::Y, 1); - check_expected(); - return; - } - - if (cell->type == ID($sr)) { - param_bool(ID::SET_POLARITY); - param_bool(ID::CLR_POLARITY); - port(ID::SET, param(ID::WIDTH)); - port(ID::CLR, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($ff)) { - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($dff)) { - param_bool(ID::CLK_POLARITY); - port(ID::CLK, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($dffe)) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::EN_POLARITY); - port(ID::CLK, 1); - port(ID::EN, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($dffsr)) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::SET_POLARITY); - param_bool(ID::CLR_POLARITY); - port(ID::CLK, 1); - port(ID::SET, param(ID::WIDTH)); - port(ID::CLR, param(ID::WIDTH)); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($dffsre)) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::SET_POLARITY); - param_bool(ID::CLR_POLARITY); - param_bool(ID::EN_POLARITY); - port(ID::CLK, 1); - port(ID::EN, 1); - port(ID::SET, param(ID::WIDTH)); - port(ID::CLR, param(ID::WIDTH)); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($adff)) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::ARST_POLARITY); - param_bits(ID::ARST_VALUE, param(ID::WIDTH)); - port(ID::CLK, 1); - port(ID::ARST, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($sdff)) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::SRST_POLARITY); - param_bits(ID::SRST_VALUE, param(ID::WIDTH)); - port(ID::CLK, 1); - port(ID::SRST, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type.in(ID($sdffe), ID($sdffce))) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::EN_POLARITY); - param_bool(ID::SRST_POLARITY); - param_bits(ID::SRST_VALUE, param(ID::WIDTH)); - port(ID::CLK, 1); - port(ID::EN, 1); - port(ID::SRST, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($adffe)) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::EN_POLARITY); - param_bool(ID::ARST_POLARITY); - param_bits(ID::ARST_VALUE, param(ID::WIDTH)); - port(ID::CLK, 1); - port(ID::EN, 1); - port(ID::ARST, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($aldff)) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::ALOAD_POLARITY); - port(ID::CLK, 1); - port(ID::ALOAD, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::AD, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($aldffe)) { - param_bool(ID::CLK_POLARITY); - param_bool(ID::EN_POLARITY); - param_bool(ID::ALOAD_POLARITY); - port(ID::CLK, 1); - port(ID::EN, 1); - port(ID::ALOAD, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::AD, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($dlatch)) { - param_bool(ID::EN_POLARITY); - port(ID::EN, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($adlatch)) { - param_bool(ID::EN_POLARITY); - param_bool(ID::ARST_POLARITY); - param_bits(ID::ARST_VALUE, param(ID::WIDTH)); - port(ID::EN, 1); - port(ID::ARST, 1); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($dlatchsr)) { - param_bool(ID::EN_POLARITY); - param_bool(ID::SET_POLARITY); - param_bool(ID::CLR_POLARITY); - port(ID::EN, 1); - port(ID::SET, param(ID::WIDTH)); - port(ID::CLR, param(ID::WIDTH)); - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($fsm)) { - param(ID::NAME); - param_bool(ID::CLK_POLARITY); - param_bool(ID::ARST_POLARITY); - param(ID::STATE_BITS); - param(ID::STATE_NUM); - param(ID::STATE_NUM_LOG2); - param(ID::STATE_RST); - param_bits(ID::STATE_TABLE, param(ID::STATE_BITS) * param(ID::STATE_NUM)); - param(ID::TRANS_NUM); - param_bits(ID::TRANS_TABLE, param(ID::TRANS_NUM) * (2*param(ID::STATE_NUM_LOG2) + param(ID::CTRL_IN_WIDTH) + param(ID::CTRL_OUT_WIDTH))); - port(ID::CLK, 1); - port(ID::ARST, 1); - port(ID::CTRL_IN, param(ID::CTRL_IN_WIDTH)); - port(ID::CTRL_OUT, param(ID::CTRL_OUT_WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($memrd)) { - param(ID::MEMID); - param_bool(ID::CLK_ENABLE); - param_bool(ID::CLK_POLARITY); - param_bool(ID::TRANSPARENT); - port(ID::CLK, 1); - port(ID::EN, 1); - port(ID::ADDR, param(ID::ABITS)); - port(ID::DATA, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($memrd_v2)) { - param(ID::MEMID); - param_bool(ID::CLK_ENABLE); - param_bool(ID::CLK_POLARITY); - param(ID::TRANSPARENCY_MASK); - param(ID::COLLISION_X_MASK); - param_bool(ID::CE_OVER_SRST); - param_bits(ID::ARST_VALUE, param(ID::WIDTH)); - param_bits(ID::SRST_VALUE, param(ID::WIDTH)); - param_bits(ID::INIT_VALUE, param(ID::WIDTH)); - port(ID::CLK, 1); - port(ID::EN, 1); - port(ID::ARST, 1); - port(ID::SRST, 1); - port(ID::ADDR, param(ID::ABITS)); - port(ID::DATA, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($memwr)) { - param(ID::MEMID); - param_bool(ID::CLK_ENABLE); - param_bool(ID::CLK_POLARITY); - param(ID::PRIORITY); - port(ID::CLK, 1); - port(ID::EN, param(ID::WIDTH)); - port(ID::ADDR, param(ID::ABITS)); - port(ID::DATA, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($memwr_v2)) { - param(ID::MEMID); - param_bool(ID::CLK_ENABLE); - param_bool(ID::CLK_POLARITY); - param(ID::PORTID); - param(ID::PRIORITY_MASK); - port(ID::CLK, 1); - port(ID::EN, param(ID::WIDTH)); - port(ID::ADDR, param(ID::ABITS)); - port(ID::DATA, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($meminit)) { - param(ID::MEMID); - param(ID::PRIORITY); - port(ID::ADDR, param(ID::ABITS)); - port(ID::DATA, param(ID::WIDTH) * param(ID::WORDS)); - check_expected(); - return; - } - - if (cell->type == ID($meminit_v2)) { - param(ID::MEMID); - param(ID::PRIORITY); - port(ID::ADDR, param(ID::ABITS)); - port(ID::DATA, param(ID::WIDTH) * param(ID::WORDS)); - port(ID::EN, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($mem)) { - param(ID::MEMID); - param(ID::SIZE); - param(ID::OFFSET); - param(ID::INIT); - param_bits(ID::RD_CLK_ENABLE, max(1, param(ID::RD_PORTS))); - param_bits(ID::RD_CLK_POLARITY, max(1, param(ID::RD_PORTS))); - param_bits(ID::RD_TRANSPARENT, max(1, param(ID::RD_PORTS))); - param_bits(ID::WR_CLK_ENABLE, max(1, param(ID::WR_PORTS))); - param_bits(ID::WR_CLK_POLARITY, max(1, param(ID::WR_PORTS))); - port(ID::RD_CLK, param(ID::RD_PORTS)); - port(ID::RD_EN, param(ID::RD_PORTS)); - port(ID::RD_ADDR, param(ID::RD_PORTS) * param(ID::ABITS)); - port(ID::RD_DATA, param(ID::RD_PORTS) * param(ID::WIDTH)); - port(ID::WR_CLK, param(ID::WR_PORTS)); - port(ID::WR_EN, param(ID::WR_PORTS) * param(ID::WIDTH)); - port(ID::WR_ADDR, param(ID::WR_PORTS) * param(ID::ABITS)); - port(ID::WR_DATA, param(ID::WR_PORTS) * param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($mem_v2)) { - param(ID::MEMID); - param(ID::SIZE); - param(ID::OFFSET); - param(ID::INIT); - param_bits(ID::RD_CLK_ENABLE, max(1, param(ID::RD_PORTS))); - param_bits(ID::RD_CLK_POLARITY, max(1, param(ID::RD_PORTS))); - param_bits(ID::RD_TRANSPARENCY_MASK, max(1, param(ID::RD_PORTS) * param(ID::WR_PORTS))); - param_bits(ID::RD_COLLISION_X_MASK, max(1, param(ID::RD_PORTS) * param(ID::WR_PORTS))); - param_bits(ID::RD_WIDE_CONTINUATION, max(1, param(ID::RD_PORTS))); - param_bits(ID::RD_CE_OVER_SRST, max(1, param(ID::RD_PORTS))); - param_bits(ID::RD_ARST_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH)); - param_bits(ID::RD_SRST_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH)); - param_bits(ID::RD_INIT_VALUE, param(ID::RD_PORTS) * param(ID::WIDTH)); - param_bits(ID::WR_CLK_ENABLE, max(1, param(ID::WR_PORTS))); - param_bits(ID::WR_CLK_POLARITY, max(1, param(ID::WR_PORTS))); - param_bits(ID::WR_WIDE_CONTINUATION, max(1, param(ID::WR_PORTS))); - param_bits(ID::WR_PRIORITY_MASK, max(1, param(ID::WR_PORTS) * param(ID::WR_PORTS))); - port(ID::RD_CLK, param(ID::RD_PORTS)); - port(ID::RD_EN, param(ID::RD_PORTS)); - port(ID::RD_ARST, param(ID::RD_PORTS)); - port(ID::RD_SRST, param(ID::RD_PORTS)); - port(ID::RD_ADDR, param(ID::RD_PORTS) * param(ID::ABITS)); - port(ID::RD_DATA, param(ID::RD_PORTS) * param(ID::WIDTH)); - port(ID::WR_CLK, param(ID::WR_PORTS)); - port(ID::WR_EN, param(ID::WR_PORTS) * param(ID::WIDTH)); - port(ID::WR_ADDR, param(ID::WR_PORTS) * param(ID::ABITS)); - port(ID::WR_DATA, param(ID::WR_PORTS) * param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($tribuf)) { - port(ID::A, param(ID::WIDTH)); - port(ID::Y, param(ID::WIDTH)); - port(ID::EN, 1); - check_expected(); - return; - } - - if (cell->type == ID($bweqx)) { - port(ID::A, param(ID::WIDTH)); - port(ID::B, param(ID::WIDTH)); - port(ID::Y, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($bwmux)) { - port(ID::A, param(ID::WIDTH)); - port(ID::B, param(ID::WIDTH)); - port(ID::S, param(ID::WIDTH)); - port(ID::Y, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) { - port(ID::A, 1); - port(ID::EN, 1); - check_expected(); - return; - } - - if (cell->type == ID($initstate)) { - port(ID::Y, 1); - check_expected(); - return; - } - - if (cell->type.in(ID($anyconst), ID($anyseq), ID($allconst), ID($allseq))) { - port(ID::Y, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type.in(ID($anyinit))) { - port(ID::D, param(ID::WIDTH)); - port(ID::Q, param(ID::WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($equiv)) { - port(ID::A, 1); - port(ID::B, 1); - port(ID::Y, 1); - check_expected(); - return; - } - - if (cell->type.in(ID($specify2), ID($specify3))) { - param_bool(ID::FULL); - param_bool(ID::SRC_DST_PEN); - param_bool(ID::SRC_DST_POL); - param(ID::T_RISE_MIN); - param(ID::T_RISE_TYP); - param(ID::T_RISE_MAX); - param(ID::T_FALL_MIN); - param(ID::T_FALL_TYP); - param(ID::T_FALL_MAX); - port(ID::EN, 1); - port(ID::SRC, param(ID::SRC_WIDTH)); - port(ID::DST, param(ID::DST_WIDTH)); - if (cell->type == ID($specify3)) { - param_bool(ID::EDGE_EN); - param_bool(ID::EDGE_POL); - param_bool(ID::DAT_DST_PEN); - param_bool(ID::DAT_DST_POL); - port(ID::DAT, param(ID::DST_WIDTH)); - } - check_expected(); - return; - } - - if (cell->type == ID($specrule)) { - param(ID::TYPE); - param_bool(ID::SRC_PEN); - param_bool(ID::SRC_POL); - param_bool(ID::DST_PEN); - param_bool(ID::DST_POL); - param(ID::T_LIMIT_MIN); - param(ID::T_LIMIT_TYP); - param(ID::T_LIMIT_MAX); - param(ID::T_LIMIT2_MIN); - param(ID::T_LIMIT2_TYP); - param(ID::T_LIMIT2_MAX); - port(ID::SRC_EN, 1); - port(ID::DST_EN, 1); - port(ID::SRC, param(ID::SRC_WIDTH)); - port(ID::DST, param(ID::DST_WIDTH)); - check_expected(); - return; - } - - if (cell->type == ID($_BUF_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_NOT_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_AND_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_NAND_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_OR_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_NOR_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_XOR_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_XNOR_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_ANDNOT_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_ORNOT_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_MUX_)) { port(ID::A,1); port(ID::B,1); port(ID::S,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_NMUX_)) { port(ID::A,1); port(ID::B,1); port(ID::S,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_AOI3_)) { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_OAI3_)) { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_AOI4_)) { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::D,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_OAI4_)) { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::D,1); port(ID::Y,1); check_expected(); return; } - - if (cell->type == ID($_TBUF_)) { port(ID::A,1); port(ID::Y,1); port(ID::E,1); check_expected(); return; } - - if (cell->type == ID($_MUX4_)) { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::D,1); port(ID::S,1); port(ID::T,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_MUX8_)) { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::D,1); port(ID::E,1); port(ID::F,1); port(ID::G,1); port(ID::H,1); port(ID::S,1); port(ID::T,1); port(ID::U,1); port(ID::Y,1); check_expected(); return; } - if (cell->type == ID($_MUX16_)) { port(ID::A,1); port(ID::B,1); port(ID::C,1); port(ID::D,1); port(ID::E,1); port(ID::F,1); port(ID::G,1); port(ID::H,1); port(ID::I,1); port(ID::J,1); port(ID::K,1); port(ID::L,1); port(ID::M,1); port(ID::N,1); port(ID::O,1); port(ID::P,1); port(ID::S,1); port(ID::T,1); port(ID::U,1); port(ID::V,1); port(ID::Y,1); check_expected(); return; } - - if (cell->type.in(ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_))) - { port(ID::S,1); port(ID::R,1); port(ID::Q,1); check_expected(); return; } - - if (cell->type == ID($_FF_)) { port(ID::D,1); port(ID::Q,1); check_expected(); return; } - - if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) - { port(ID::D,1); port(ID::Q,1); port(ID::C,1); check_expected(); return; } - - if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) - { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::E,1); check_expected(); return; } - - if (cell->type.in( - ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), - ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_))) - { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; } - - if (cell->type.in( - ID($_DFFE_NN0N_), ID($_DFFE_NN0P_), ID($_DFFE_NN1N_), ID($_DFFE_NN1P_), - ID($_DFFE_NP0N_), ID($_DFFE_NP0P_), ID($_DFFE_NP1N_), ID($_DFFE_NP1P_), - ID($_DFFE_PN0N_), ID($_DFFE_PN0P_), ID($_DFFE_PN1N_), ID($_DFFE_PN1P_), - ID($_DFFE_PP0N_), ID($_DFFE_PP0P_), ID($_DFFE_PP1N_), ID($_DFFE_PP1P_))) - { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); port(ID::E,1); check_expected(); return; } - - if (cell->type.in( - ID($_ALDFF_NN_), ID($_ALDFF_NP_), ID($_ALDFF_PN_), ID($_ALDFF_PP_))) - { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::L,1); port(ID::AD,1); check_expected(); return; } - - if (cell->type.in( - ID($_ALDFFE_NNN_), ID($_ALDFFE_NNP_), ID($_ALDFFE_NPN_), ID($_ALDFFE_NPP_), - ID($_ALDFFE_PNN_), ID($_ALDFFE_PNP_), ID($_ALDFFE_PPN_), ID($_ALDFFE_PPP_))) - { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::L,1); port(ID::AD,1); port(ID::E,1); check_expected(); return; } - - if (cell->type.in( - ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), - ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_))) - { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; } - - if (cell->type.in( - ID($_DFFSRE_NNNN_), ID($_DFFSRE_NNNP_), ID($_DFFSRE_NNPN_), ID($_DFFSRE_NNPP_), - ID($_DFFSRE_NPNN_), ID($_DFFSRE_NPNP_), ID($_DFFSRE_NPPN_), ID($_DFFSRE_NPPP_), - ID($_DFFSRE_PNNN_), ID($_DFFSRE_PNNP_), ID($_DFFSRE_PNPN_), ID($_DFFSRE_PNPP_), - ID($_DFFSRE_PPNN_), ID($_DFFSRE_PPNP_), ID($_DFFSRE_PPPN_), ID($_DFFSRE_PPPP_))) - { port(ID::C,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::E,1); port(ID::Q,1); check_expected(); return; } - - if (cell->type.in( - ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_), - ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_))) - { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); check_expected(); return; } - - if (cell->type.in( - ID($_SDFFE_NN0N_), ID($_SDFFE_NN0P_), ID($_SDFFE_NN1N_), ID($_SDFFE_NN1P_), - ID($_SDFFE_NP0N_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1N_), ID($_SDFFE_NP1P_), - ID($_SDFFE_PN0N_), ID($_SDFFE_PN0P_), ID($_SDFFE_PN1N_), ID($_SDFFE_PN1P_), - ID($_SDFFE_PP0N_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1N_), ID($_SDFFE_PP1P_), - ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NN1P_), - ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1N_), ID($_SDFFCE_NP1P_), - ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PN1P_), - ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1N_), ID($_SDFFCE_PP1P_))) - { port(ID::D,1); port(ID::Q,1); port(ID::C,1); port(ID::R,1); port(ID::E,1); check_expected(); return; } - - if (cell->type.in(ID($_DLATCH_N_), ID($_DLATCH_P_))) - { port(ID::E,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; } - - if (cell->type.in( - ID($_DLATCH_NN0_), ID($_DLATCH_NN1_), ID($_DLATCH_NP0_), ID($_DLATCH_NP1_), - ID($_DLATCH_PN0_), ID($_DLATCH_PN1_), ID($_DLATCH_PP0_), ID($_DLATCH_PP1_))) - { port(ID::E,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; } - - if (cell->type.in( - ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_), - ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_))) - { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; } - - error(__LINE__); - } - }; -} -#endif - -void RTLIL::Module::sort() -{ - wires_.sort(sort_by_id_str()); - cells_.sort(sort_by_id_str()); - parameter_default_values.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()); - } - - pool packed_memids; - - 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(this); - } - 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(); - if (it.second->has_memid()) { - log_assert(memories.count(it.second->parameters.at(ID::MEMID).decode_string())); - } else if (it.second->is_mem_cell()) { - IdString memid = it.second->parameters.at(ID::MEMID).decode_string(); - log_assert(!memories.count(memid)); - log_assert(!packed_memids.count(memid)); - packed_memids.insert(memid); - } - } - - 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(this); - it.second.check(this); - } - - 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; - new_mod->parameter_default_values = parameter_default_values; - - 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->addMemory(it.first, it.second); - - for (auto &it : cells_) - new_mod->addCell(it.first, it.second); - - for (auto &it : processes) - new_mod->addProcess(it.first, it.second); - - struct RewriteSigSpecWorker - { - RTLIL::Module *mod; - void operator()(RTLIL::SigSpec &sig) - { - sig.pack(); - for (auto &c : sig.chunks_) - if (c.wire != NULL) - c.wire = mod->wires_.at(c.wire->name); - } - }; - - 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(cells_.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::add(RTLIL::Process *process) -{ - log_assert(!process->name.empty()); - log_assert(count_id(process->name) == 0); - processes[process->name] = process; - process->module = this; -} - -void RTLIL::Module::add(RTLIL::Binding *binding) -{ - log_assert(binding != nullptr); - bindings_.push_back(binding); -} - -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) { - sig.pack(); - for (auto &c : sig.chunks_) - if (c.wire != NULL && wires_p->count(c.wire)) { - c.wire = module->addWire(stringf("$delete_wire$%d", autoidx++), c.width); - c.offset = 0; - } - } - - void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) { - log_assert(GetSize(lhs) == GetSize(rhs)); - lhs.unpack(); - rhs.unpack(); - for (int i = 0; i < GetSize(lhs); i++) { - RTLIL::SigBit &lhs_bit = lhs.bits_[i]; - RTLIL::SigBit &rhs_bit = rhs.bits_[i]; - if ((lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire)) || (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire))) { - lhs_bit = State::Sx; - rhs_bit = State::Sx; - } - } - } - }; - - 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::remove(RTLIL::Process *process) -{ - log_assert(processes.count(process->name) != 0); - processes.erase(process->name); - delete process; -} - -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->is_signed = other->is_signed; - 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; -} - -RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memory *other) -{ - RTLIL::Memory *mem = new RTLIL::Memory; - mem->name = name; - mem->width = other->width; - mem->start_offset = other->start_offset; - mem->size = other->size; - mem->attributes = other->attributes; - memories[mem->name] = mem; - return mem; -} - -RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name) -{ - RTLIL::Process *proc = new RTLIL::Process; - proc->name = name; - add(proc); - return proc; -} - -RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other) -{ - RTLIL::Process *proc = other->clone(); - proc->name = name; - add(proc); - return proc; -} - -#define DEF_METHOD(_func, _y_size, _type) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters[ID::A_SIGNED] = is_signed; \ - cell->parameters[ID::A_WIDTH] = sig_a.size(); \ - cell->parameters[ID::Y_WIDTH] = sig_y.size(); \ - cell->setPort(ID::A, sig_a); \ - cell->setPort(ID::Y, sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const 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(), ID($not)) -DEF_METHOD(Pos, sig_a.size(), ID($pos)) -DEF_METHOD(Neg, sig_a.size(), ID($neg)) -DEF_METHOD(ReduceAnd, 1, ID($reduce_and)) -DEF_METHOD(ReduceOr, 1, ID($reduce_or)) -DEF_METHOD(ReduceXor, 1, ID($reduce_xor)) -DEF_METHOD(ReduceXnor, 1, ID($reduce_xnor)) -DEF_METHOD(ReduceBool, 1, ID($reduce_bool)) -DEF_METHOD(LogicNot, 1, ID($logic_not)) -#undef DEF_METHOD - -#define DEF_METHOD(_func, _y_size, _type) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters[ID::A_SIGNED] = is_signed; \ - cell->parameters[ID::B_SIGNED] = is_signed; \ - cell->parameters[ID::A_WIDTH] = sig_a.size(); \ - cell->parameters[ID::B_WIDTH] = sig_b.size(); \ - cell->parameters[ID::Y_WIDTH] = sig_y.size(); \ - cell->setPort(ID::A, sig_a); \ - cell->setPort(ID::B, sig_b); \ - cell->setPort(ID::Y, sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const 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()), ID($and)) -DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), ID($or)) -DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), ID($xor)) -DEF_METHOD(Xnor, max(sig_a.size(), sig_b.size()), ID($xnor)) -DEF_METHOD(Shift, sig_a.size(), ID($shift)) -DEF_METHOD(Shiftx, sig_a.size(), ID($shiftx)) -DEF_METHOD(Lt, 1, ID($lt)) -DEF_METHOD(Le, 1, ID($le)) -DEF_METHOD(Eq, 1, ID($eq)) -DEF_METHOD(Ne, 1, ID($ne)) -DEF_METHOD(Eqx, 1, ID($eqx)) -DEF_METHOD(Nex, 1, ID($nex)) -DEF_METHOD(Ge, 1, ID($ge)) -DEF_METHOD(Gt, 1, ID($gt)) -DEF_METHOD(Add, max(sig_a.size(), sig_b.size()), ID($add)) -DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), ID($sub)) -DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), ID($mul)) -DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), ID($div)) -DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), ID($mod)) -DEF_METHOD(DivFloor, max(sig_a.size(), sig_b.size()), ID($divfloor)) -DEF_METHOD(ModFloor, max(sig_a.size(), sig_b.size()), ID($modfloor)) -DEF_METHOD(LogicAnd, 1, ID($logic_and)) -DEF_METHOD(LogicOr, 1, ID($logic_or)) -#undef DEF_METHOD - -#define DEF_METHOD(_func, _y_size, _type) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters[ID::A_SIGNED] = is_signed; \ - cell->parameters[ID::B_SIGNED] = false; \ - cell->parameters[ID::A_WIDTH] = sig_a.size(); \ - cell->parameters[ID::B_WIDTH] = sig_b.size(); \ - cell->parameters[ID::Y_WIDTH] = sig_y.size(); \ - cell->setPort(ID::A, sig_a); \ - cell->setPort(ID::B, sig_b); \ - cell->setPort(ID::Y, sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const 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(Shl, sig_a.size(), ID($shl)) -DEF_METHOD(Shr, sig_a.size(), ID($shr)) -DEF_METHOD(Sshl, sig_a.size(), ID($sshl)) -DEF_METHOD(Sshr, sig_a.size(), ID($sshr)) -#undef DEF_METHOD - -#define DEF_METHOD(_func, _type, _pmux) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters[ID::WIDTH] = sig_a.size(); \ - if (_pmux) cell->parameters[ID::S_WIDTH] = sig_s.size(); \ - cell->setPort(ID::A, sig_a); \ - cell->setPort(ID::B, sig_b); \ - cell->setPort(ID::S, sig_s); \ - cell->setPort(ID::Y, sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const 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, ID($mux), 0) -DEF_METHOD(Bwmux, ID($bwmux), 0) -DEF_METHOD(Pmux, ID($pmux), 1) -#undef DEF_METHOD - -#define DEF_METHOD(_func, _type, _demux) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters[ID::WIDTH] = _demux ? sig_a.size() : sig_y.size(); \ - cell->parameters[ID::S_WIDTH] = sig_s.size(); \ - cell->setPort(ID::A, sig_a); \ - cell->setPort(ID::S, sig_s); \ - cell->setPort(ID::Y, sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src) { \ - RTLIL::SigSpec sig_y = addWire(NEW_ID, _demux ? sig_a.size() << sig_s.size() : sig_a.size() >> sig_s.size()); \ - add ## _func(name, sig_a, sig_s, sig_y, src); \ - return sig_y; \ - } -DEF_METHOD(Bmux, ID($bmux), 0) -DEF_METHOD(Demux, ID($demux), 1) -#undef DEF_METHOD - -#define DEF_METHOD(_func, _type) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src) { \ - RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters[ID::WIDTH] = sig_a.size(); \ - cell->setPort(ID::A, sig_a); \ - cell->setPort(ID::B, sig_b); \ - cell->setPort(ID::Y, sig_y); \ - cell->set_src_attribute(src); \ - return cell; \ - } \ - RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src) { \ - RTLIL::SigSpec sig_y = addWire(NEW_ID, sig_a.size()); \ - add ## _func(name, sig_a, sig_s, sig_y, src); \ - return sig_y; \ - } -DEF_METHOD(Bweqx, ID($bweqx)) -#undef DEF_METHOD - -#define DEF_METHOD_2(_func, _type, _P1, _P2) \ - RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const 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, const 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, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const 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, const RTLIL::SigBit &sig1, const 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, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const 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, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const 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, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const RTLIL::SigBit &sig4, const 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, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const 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, ID($_BUF_), A, Y) -DEF_METHOD_2(NotGate, ID($_NOT_), A, Y) -DEF_METHOD_3(AndGate, ID($_AND_), A, B, Y) -DEF_METHOD_3(NandGate, ID($_NAND_), A, B, Y) -DEF_METHOD_3(OrGate, ID($_OR_), A, B, Y) -DEF_METHOD_3(NorGate, ID($_NOR_), A, B, Y) -DEF_METHOD_3(XorGate, ID($_XOR_), A, B, Y) -DEF_METHOD_3(XnorGate, ID($_XNOR_), A, B, Y) -DEF_METHOD_3(AndnotGate, ID($_ANDNOT_), A, B, Y) -DEF_METHOD_3(OrnotGate, ID($_ORNOT_), A, B, Y) -DEF_METHOD_4(MuxGate, ID($_MUX_), A, B, S, Y) -DEF_METHOD_4(NmuxGate, ID($_NMUX_), A, B, S, Y) -DEF_METHOD_4(Aoi3Gate, ID($_AOI3_), A, B, C, Y) -DEF_METHOD_4(Oai3Gate, ID($_OAI3_), A, B, C, Y) -DEF_METHOD_5(Aoi4Gate, ID($_AOI4_), A, B, C, D, Y) -DEF_METHOD_5(Oai4Gate, ID($_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, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed, bool b_signed, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($pow)); - cell->parameters[ID::A_SIGNED] = a_signed; - cell->parameters[ID::B_SIGNED] = b_signed; - cell->parameters[ID::A_WIDTH] = sig_a.size(); - cell->parameters[ID::B_WIDTH] = sig_b.size(); - cell->parameters[ID::Y_WIDTH] = sig_y.size(); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::B, sig_b); - cell->setPort(ID::Y, sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($slice)); - cell->parameters[ID::A_WIDTH] = sig_a.size(); - cell->parameters[ID::Y_WIDTH] = sig_y.size(); - cell->parameters[ID::OFFSET] = offset; - cell->setPort(ID::A, sig_a); - cell->setPort(ID::Y, sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($concat)); - cell->parameters[ID::A_WIDTH] = sig_a.size(); - cell->parameters[ID::B_WIDTH] = sig_b.size(); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::B, sig_b); - cell->setPort(ID::Y, sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($lut)); - cell->parameters[ID::LUT] = lut; - cell->parameters[ID::WIDTH] = sig_a.size(); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::Y, sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($tribuf)); - cell->parameters[ID::WIDTH] = sig_a.size(); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::Y, sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($assert)); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::EN, sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($assume)); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::EN, sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addLive(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($live)); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::EN, sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addFair(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($fair)); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::EN, sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addCover(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($cover)); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::EN, sig_en); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($equiv)); - cell->setPort(ID::A, sig_a); - cell->setPort(ID::B, sig_b); - cell->setPort(ID::Y, sig_y); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($sr)); - cell->parameters[ID::SET_POLARITY] = set_polarity; - cell->parameters[ID::CLR_POLARITY] = clr_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::SET, sig_set); - cell->setPort(ID::CLR, sig_clr); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addFf(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($ff)); - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($dff)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($dffe)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($dffsr)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::SET_POLARITY] = set_polarity; - cell->parameters[ID::CLR_POLARITY] = clr_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::SET, sig_set); - cell->setPort(ID::CLR, sig_clr); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffsre(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($dffsre)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::SET_POLARITY] = set_polarity; - cell->parameters[ID::CLR_POLARITY] = clr_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::SET, sig_set); - cell->setPort(ID::CLR, sig_clr); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($adff)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::ARST_POLARITY] = arst_polarity; - cell->parameters[ID::ARST_VALUE] = arst_value; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::ARST, sig_arst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAdffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const arst_value, bool clk_polarity, bool en_polarity, bool arst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($adffe)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::ARST_POLARITY] = arst_polarity; - cell->parameters[ID::ARST_VALUE] = arst_value; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::ARST, sig_arst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAldff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($aldff)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::ALOAD_POLARITY] = aload_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::ALOAD, sig_aload); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::AD, sig_ad); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAldffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($aldffe)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::ALOAD_POLARITY] = aload_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::ALOAD, sig_aload); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::AD, sig_ad); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSdff(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const srst_value, bool clk_polarity, bool srst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($sdff)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::SRST_POLARITY] = srst_polarity; - cell->parameters[ID::SRST_VALUE] = srst_value; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::SRST, sig_srst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSdffe(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($sdffe)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::SRST_POLARITY] = srst_polarity; - cell->parameters[ID::SRST_VALUE] = srst_value; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::SRST, sig_srst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSdffce(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($sdffce)); - cell->parameters[ID::CLK_POLARITY] = clk_polarity; - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::SRST_POLARITY] = srst_polarity; - cell->parameters[ID::SRST_VALUE] = srst_value; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::CLK, sig_clk); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::SRST, sig_srst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($dlatch)); - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAdlatch(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - RTLIL::Const arst_value, bool en_polarity, bool arst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($adlatch)); - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::ARST_POLARITY] = arst_polarity; - cell->parameters[ID::ARST_VALUE] = arst_value; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::ARST, sig_arst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($dlatchsr)); - cell->parameters[ID::EN_POLARITY] = en_polarity; - cell->parameters[ID::SET_POLARITY] = set_polarity; - cell->parameters[ID::CLR_POLARITY] = clr_polarity; - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::EN, sig_en); - cell->setPort(ID::SET, sig_set); - cell->setPort(ID::CLR, sig_clr); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - const RTLIL::SigSpec &sig_q, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_SR_%c%c_", set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); - cell->setPort(ID::S, sig_set); - cell->setPort(ID::R, sig_clr); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($_FF_)); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const 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(ID::C, sig_clk); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const 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(ID::C, sig_clk); - cell->setPort(ID::E, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const 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(ID::C, sig_clk); - cell->setPort(ID::S, sig_set); - cell->setPort(ID::R, sig_clr); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDffsreGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DFFSRE_%c%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); - cell->setPort(ID::C, sig_clk); - cell->setPort(ID::S, sig_set); - cell->setPort(ID::R, sig_clr); - cell->setPort(ID::E, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const 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(ID::C, sig_clk); - cell->setPort(ID::R, sig_arst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAdffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value, bool clk_polarity, bool en_polarity, bool arst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DFFE_%c%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0', en_polarity ? 'P' : 'N')); - cell->setPort(ID::C, sig_clk); - cell->setPort(ID::R, sig_arst); - cell->setPort(ID::E, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAldffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool aload_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_ALDFF_%c%c_", clk_polarity ? 'P' : 'N', aload_polarity ? 'P' : 'N')); - cell->setPort(ID::C, sig_clk); - cell->setPort(ID::L, sig_aload); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::AD, sig_ad); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAldffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity, bool en_polarity, bool aload_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_ALDFFE_%c%c%c_", clk_polarity ? 'P' : 'N', aload_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); - cell->setPort(ID::C, sig_clk); - cell->setPort(ID::L, sig_aload); - cell->setPort(ID::E, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::AD, sig_ad); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSdffGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value, bool clk_polarity, bool srst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_SDFF_%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0')); - cell->setPort(ID::C, sig_clk); - cell->setPort(ID::R, sig_srst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSdffeGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_SDFFE_%c%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0', en_polarity ? 'P' : 'N')); - cell->setPort(ID::C, sig_clk); - cell->setPort(ID::R, sig_srst); - cell->setPort(ID::E, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addSdffceGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value, bool clk_polarity, bool en_polarity, bool srst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_SDFFCE_%c%c%c%c_", clk_polarity ? 'P' : 'N', srst_polarity ? 'P' : 'N', srst_value ? '1' : '0', en_polarity ? 'P' : 'N')); - cell->setPort(ID::C, sig_clk); - cell->setPort(ID::R, sig_srst); - cell->setPort(ID::E, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const 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(ID::E, sig_en); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAdlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value, bool en_polarity, bool arst_polarity, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c%c%c_", en_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0')); - cell->setPort(ID::E, sig_en); - cell->setPort(ID::R, sig_arst); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const 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(ID::E, sig_en); - cell->setPort(ID::S, sig_set); - cell->setPort(ID::R, sig_clr); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, sig_q); - cell->set_src_attribute(src); - return cell; -} - -RTLIL::Cell* RTLIL::Module::addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src) -{ - RTLIL::Cell *cell = addCell(name, ID($anyinit)); - cell->parameters[ID::WIDTH] = sig_q.size(); - cell->setPort(ID::D, sig_d); - cell->setPort(ID::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, ID($anyconst)); - cell->setParam(ID::WIDTH, width); - cell->setPort(ID::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, ID($anyseq)); - cell->setParam(ID::WIDTH, width); - cell->setPort(ID::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, ID($allconst)); - cell->setParam(ID::WIDTH, width); - cell->setPort(ID::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, ID($allseq)); - cell->setParam(ID::WIDTH, width); - cell->setPort(ID::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, ID($initstate)); - cell->setPort(ID::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; - is_signed = 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::Process::Process() : module(nullptr) -{ - static unsigned int hashidx_count = 123456789; - hashidx_count = mkhash_xorshift(hashidx_count); - hashidx_ = hashidx_count; -} - -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(const RTLIL::IdString& portname) const -{ - return connections_.count(portname) != 0; -} - -void RTLIL::Cell::unsetPort(const 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(const RTLIL::IdString& portname, RTLIL::SigSpec signal) -{ - auto r = connections_.insert(portname); - auto conn_it = r.first; - if (!r.second && 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 = std::move(signal); -} - -const RTLIL::SigSpec &RTLIL::Cell::getPort(const 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(const 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(const 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(const RTLIL::IdString& paramname) const -{ - return parameters.count(paramname) != 0; -} - -void RTLIL::Cell::unsetParam(const RTLIL::IdString& paramname) -{ - parameters.erase(paramname); -} - -void RTLIL::Cell::setParam(const RTLIL::IdString& paramname, RTLIL::Const value) -{ - parameters[paramname] = std::move(value); -} - -const RTLIL::Const &RTLIL::Cell::getParam(const RTLIL::IdString& paramname) const -{ - const auto &it = parameters.find(paramname); - if (it != parameters.end()) - return it->second; - if (module && module->design) { - RTLIL::Module *m = module->design->module(type); - if (m) - return m->parameter_default_values.at(paramname); - } - throw std::out_of_range("Cell::getParam()"); -} - -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.begins_with("$") || type.begins_with("$_") || type.begins_with("$paramod") || type.begins_with("$fmcombine") || - type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:")) - return; - - if (type == ID($mux) || type == ID($pmux) || type == ID($bmux)) { - parameters[ID::WIDTH] = GetSize(connections_[ID::Y]); - if (type != ID($mux)) - parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]); - check(); - return; - } - - if (type == ID($demux)) { - parameters[ID::WIDTH] = GetSize(connections_[ID::A]); - parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]); - check(); - return; - } - - if (type == ID($lut) || type == ID($sop)) { - parameters[ID::WIDTH] = GetSize(connections_[ID::A]); - return; - } - - if (type == ID($fa)) { - parameters[ID::WIDTH] = GetSize(connections_[ID::Y]); - return; - } - - if (type == ID($lcu)) { - parameters[ID::WIDTH] = GetSize(connections_[ID::CO]); - return; - } - - bool signedness_ab = !type.in(ID($slice), ID($concat), ID($macc)); - - if (connections_.count(ID::A)) { - if (signedness_ab) { - if (set_a_signed) - parameters[ID::A_SIGNED] = true; - else if (parameters.count(ID::A_SIGNED) == 0) - parameters[ID::A_SIGNED] = false; - } - parameters[ID::A_WIDTH] = GetSize(connections_[ID::A]); - } - - if (connections_.count(ID::B)) { - if (signedness_ab) { - if (set_b_signed) - parameters[ID::B_SIGNED] = true; - else if (parameters.count(ID::B_SIGNED) == 0) - parameters[ID::B_SIGNED] = false; - } - parameters[ID::B_WIDTH] = GetSize(connections_[ID::B]); - } - - if (connections_.count(ID::Y)) - parameters[ID::Y_WIDTH] = GetSize(connections_[ID::Y]); - - if (connections_.count(ID::Q)) - parameters[ID::WIDTH] = GetSize(connections_[ID::Q]); - - check(); -} - -bool RTLIL::Cell::has_memid() const -{ - return type.in(ID($memwr), ID($memwr_v2), ID($memrd), ID($memrd_v2), ID($meminit), ID($meminit_v2)); -} - -bool RTLIL::Cell::is_mem_cell() const -{ - return type.in(ID($mem), ID($mem_v2)) || has_memid(); -} - -RTLIL::SigChunk::SigChunk(const 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 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(std::initializer_list parts) -{ - cover("kernel.rtlil.sigspec.init.list"); - - width_ = 0; - hash_ = 0; - - log_assert(parts.size() > 0); - auto ie = parts.begin(); - auto it = ie + parts.size() - 1; - while (it >= ie) - append(*it--); -} - -RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) -{ - cover("kernel.rtlil.sigspec.init.const"); - - if (GetSize(value) != 0) { - chunks_.emplace_back(value); - width_ = chunks_.back().width; - } else { - width_ = 0; - } - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) -{ - cover("kernel.rtlil.sigspec.init.const.move"); - - if (GetSize(value) != 0) { - chunks_.emplace_back(std::move(value)); - width_ = chunks_.back().width; - } else { - width_ = 0; - } - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) -{ - cover("kernel.rtlil.sigspec.init.chunk"); - - if (chunk.width != 0) { - chunks_.emplace_back(chunk); - width_ = chunks_.back().width; - } else { - width_ = 0; - } - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) -{ - cover("kernel.rtlil.sigspec.init.chunk.move"); - - if (chunk.width != 0) { - chunks_.emplace_back(std::move(chunk)); - width_ = chunks_.back().width; - } else { - width_ = 0; - } - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) -{ - cover("kernel.rtlil.sigspec.init.wire"); - - if (wire->width != 0) { - chunks_.emplace_back(wire); - width_ = chunks_.back().width; - } else { - width_ = 0; - } - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) -{ - cover("kernel.rtlil.sigspec.init.wire_part"); - - if (width != 0) { - chunks_.emplace_back(wire, offset, width); - width_ = chunks_.back().width; - } else { - width_ = 0; - } - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(const std::string &str) -{ - cover("kernel.rtlil.sigspec.init.str"); - - if (str.size() != 0) { - chunks_.emplace_back(str); - width_ = chunks_.back().width; - } else { - width_ = 0; - } - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(int val, int width) -{ - cover("kernel.rtlil.sigspec.init.int"); - - if (width != 0) - chunks_.emplace_back(val, width); - width_ = width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) -{ - cover("kernel.rtlil.sigspec.init.state"); - - if (width != 0) - chunks_.emplace_back(bit, width); - width_ = width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width) -{ - cover("kernel.rtlil.sigspec.init.bit"); - - if (width != 0) { - if (bit.wire == NULL) - chunks_.emplace_back(bit.data, width); - else - for (int i = 0; i < width; i++) - chunks_.push_back(bit); - } - width_ = width; - hash_ = 0; - check(); -} - -RTLIL::SigSpec::SigSpec(const std::vector &chunks) -{ - cover("kernel.rtlil.sigspec.init.stdvec_chunks"); - - width_ = 0; - hash_ = 0; - for (const auto &c : chunks) - append(c); - check(); -} - -RTLIL::SigSpec::SigSpec(const std::vector &bits) -{ - cover("kernel.rtlil.sigspec.init.stdvec_bits"); - - width_ = 0; - hash_ = 0; - for (const auto &bit : bits) - append(bit); - check(); -} - -RTLIL::SigSpec::SigSpec(const pool &bits) -{ - cover("kernel.rtlil.sigspec.init.pool_bits"); - - width_ = 0; - hash_ = 0; - for (const auto &bit : bits) - append(bit); - check(); -} - -RTLIL::SigSpec::SigSpec(const std::set &bits) -{ - cover("kernel.rtlil.sigspec.init.stdset_bits"); - - width_ = 0; - hash_ = 0; - for (const auto &bit : bits) - append(bit); - check(); -} - -RTLIL::SigSpec::SigSpec(bool bit) -{ - cover("kernel.rtlil.sigspec.init.bool"); - - width_ = 0; - hash_ = 0; - append(SigBit(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_.emplace_back(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_); - - if (rules.empty()) return; - 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_); - - if (rules.empty()) return; - 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(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(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(bits_other[i]); - } else { - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && pattern.count(bits_match[i])) - ret.append(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) { - if (!new_chunks.empty() && - new_chunks.back().wire == chunk.wire && - new_chunks.back().offset + new_chunks.back().width == chunk.offset) { - new_chunks.back().width += chunk.width; - } else { - 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(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(Module *mod) 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]; - log_assert(chunk.width != 0); - 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); - if (mod != nullptr) - log_assert(chunk.wire->module == mod); - } - w += chunk.width; - } - log_assert(w == width_); - log_assert(bits_.empty()); - } - else - { - cover("kernel.rtlil.sigspec.check.unpacked"); - - if (mod != nullptr) { - for (size_t i = 0; i < bits_.size(); i++) - if (bits_[i].wire != nullptr) - log_assert(bits_[i].wire->module == mod); - } - - 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; - - // Without this, SigSpec() == SigSpec(State::S0, 0) will fail - // since the RHS will contain one SigChunk of width 0 causing - // the size check below to fail - if (width_ == 0) - return true; - - 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::is_onehot(int *pos) const -{ - cover("kernel.rtlil.sigspec.is_onehot"); - - pack(); - if (!is_fully_const()) - return false; - log_assert(GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).is_onehot(pos); - 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; - str.reserve(size()); - for (size_t i = chunks_.size(); i > 0; i--) { - const RTLIL::SigChunk &chunk = chunks_[i-1]; - if (chunk.wire != NULL) - str.append(chunk.width, '?'); - 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(const char* pattern) const -{ - cover("kernel.rtlil.sigspec.match"); - - unpack(); - log_assert(int(strlen(pattern)) == GetSize(bits_)); - - for (auto it = bits_.rbegin(); it != bits_.rend(); it++, pattern++) { - if (*pattern == ' ') - continue; - if (*pattern == '*') { - if (*it != State::Sz && *it != State::Sx) - return false; - continue; - } - if (*pattern == '0') { - if (*it != State::S0) - return false; - } else - if (*pattern == '1') { - if (*it != State::S1) - return false; - } else - log_abort(); - } - - 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; - sigbits.reserve(size()); - 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; - new_map.reserve(size()); - 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"; - - 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; - new_syncrule->mem_write_actions = mem_write_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 7c7669caa88..00000000000 --- a/yosys/kernel/rtlil.h +++ /dev/null @@ -1,1817 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 MemWriteAction; - struct SyncRule; - struct Process; - struct Binding; - - typedef std::pair SigSig; - - struct IdString - { - #undef YOSYS_XTRACE_GET_PUT - #undef YOSYS_SORT_ID_FREE_LIST - #undef YOSYS_USE_STICKY_IDS - #undef YOSYS_NO_IDS_REFCNT - - // the global id string cache - - static 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_id_storage_; - static dict global_id_index_; - #ifndef YOSYS_NO_IDS_REFCNT - static std::vector global_refcount_storage_; - static std::vector global_free_idx_list_; - #endif - - #ifdef YOSYS_USE_STICKY_IDS - static int last_created_idx_ptr_; - static int last_created_idx_[8]; - #endif - - static inline void xtrace_db_dump() - { - #ifdef YOSYS_XTRACE_GET_PUT - for (int idx = 0; idx < GetSize(global_id_storage_); idx++) - { - if (global_id_storage_.at(idx) == nullptr) - log("#X# DB-DUMP index %d: FREE\n", idx); - else - log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx)); - } - #endif - } - - static inline void checkpoint() - { - #ifdef YOSYS_USE_STICKY_IDS - last_created_idx_ptr_ = 0; - for (int i = 0; i < 8; i++) { - if (last_created_idx_[i]) - put_reference(last_created_idx_[i]); - last_created_idx_[i] = 0; - } - #endif - #ifdef YOSYS_SORT_ID_FREE_LIST - std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater()); - #endif - } - - static inline int get_reference(int idx) - { - if (idx) { - #ifndef YOSYS_NO_IDS_REFCNT - global_refcount_storage_[idx]++; - #endif - #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) - log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); - #endif - } - return idx; - } - - static int get_reference(const char *p) - { - log_assert(destruct_guard.ok); - - if (!p[0]) - return 0; - - auto it = global_id_index_.find((char*)p); - if (it != global_id_index_.end()) { - #ifndef YOSYS_NO_IDS_REFCNT - global_refcount_storage_.at(it->second)++; - #endif - #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) - log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second)); - #endif - return it->second; - } - - log_assert(p[0] == '$' || p[0] == '\\'); - log_assert(p[1] != 0); - for (const char *c = p; *c; c++) - if ((unsigned)*c <= (unsigned)' ') - log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p); - - #ifndef YOSYS_NO_IDS_REFCNT - if (global_free_idx_list_.empty()) { - if (global_id_storage_.empty()) { - global_refcount_storage_.push_back(0); - global_id_storage_.push_back((char*)""); - global_id_index_[global_id_storage_.back()] = 0; - } - log_assert(global_id_storage_.size() < 0x40000000); - global_free_idx_list_.push_back(global_id_storage_.size()); - global_id_storage_.push_back(nullptr); - global_refcount_storage_.push_back(0); - } - - int idx = global_free_idx_list_.back(); - global_free_idx_list_.pop_back(); - global_id_storage_.at(idx) = strdup(p); - global_id_index_[global_id_storage_.at(idx)] = idx; - global_refcount_storage_.at(idx)++; - #else - if (global_id_storage_.empty()) { - global_id_storage_.push_back((char*)""); - global_id_index_[global_id_storage_.back()] = 0; - } - int idx = global_id_storage_.size(); - global_id_storage_.push_back(strdup(p)); - global_id_index_[global_id_storage_.back()] = idx; - #endif - - if (yosys_xtrace) { - log("#X# New IdString '%s' with index %d.\n", p, idx); - log_backtrace("-X- ", yosys_xtrace-1); - } - - #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) - log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); - #endif - - #ifdef YOSYS_USE_STICKY_IDS - // Avoid Create->Delete->Create pattern - if (last_created_idx_[last_created_idx_ptr_]) - put_reference(last_created_idx_[last_created_idx_ptr_]); - last_created_idx_[last_created_idx_ptr_] = idx; - get_reference(last_created_idx_[last_created_idx_ptr_]); - last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7; - #endif - - return idx; - } - - #ifndef YOSYS_NO_IDS_REFCNT - static inline void put_reference(int idx) - { - // put_reference() may be called from destructors after the destructor of - // global_refcount_storage_ has been run. in this case we simply do nothing. - if (!destruct_guard.ok || !idx) - return; - - #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) { - log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); - } - #endif - - int &refcount = global_refcount_storage_[idx]; - - if (--refcount > 0) - return; - - log_assert(refcount == 0); - free_reference(idx); - } - static inline void free_reference(int idx) - { - if (yosys_xtrace) { - log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx); - log_backtrace("-X- ", yosys_xtrace-1); - } - - global_id_index_.erase(global_id_storage_.at(idx)); - free(global_id_storage_.at(idx)); - global_id_storage_.at(idx) = nullptr; - global_free_idx_list_.push_back(idx); - } - #else - static inline void put_reference(int) { } - #endif - - // the actual IdString object is just is a single int - - int index_; - - inline IdString() : index_(0) { } - inline IdString(const char *str) : index_(get_reference(str)) { } - inline IdString(const IdString &str) : index_(get_reference(str.index_)) { } - inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } - inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { } - inline ~IdString() { put_reference(index_); } - - inline void operator=(const IdString &rhs) { - put_reference(index_); - index_ = get_reference(rhs.index_); - } - - inline void operator=(const char *rhs) { - IdString id(rhs); - *this = id; - } - - inline void operator=(const std::string &rhs) { - IdString id(rhs); - *this = id; - } - - inline const char *c_str() const { - return global_id_storage_.at(index_); - } - - inline std::string str() const { - return std::string(global_id_storage_.at(index_)); - } - - inline bool operator<(const IdString &rhs) const { - return index_ < rhs.index_; - } - - inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } - inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } - - // The methods below are just convenience functions for better compatibility with std::string. - - bool operator==(const std::string &rhs) const { return c_str() == rhs; } - bool operator!=(const std::string &rhs) const { return c_str() != rhs; } - - bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; } - bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } - - char operator[](size_t i) const { - const char *p = c_str(); - 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); - } - - int compare(size_t pos, size_t len, const char* s) const { - return strncmp(c_str()+pos, s, len); - } - - bool begins_with(const char* prefix) const { - size_t len = strlen(prefix); - if (size() < len) return false; - return compare(0, len, prefix) == 0; - } - - bool ends_with(const char* suffix) const { - size_t len = strlen(suffix); - if (size() < len) return false; - return compare(size()-len, len, suffix) == 0; - } - - bool contains(const char* str) const { - return strstr(c_str(), str); - } - - size_t size() const { - return strlen(c_str()); - } - - bool empty() const { - return c_str()[0] == 0; - } - - void clear() { - *this = IdString(); - } - - unsigned int hash() const { - return index_; - } - - // The following is a helper key_compare class. Instead of for example std::set - // 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(Args... args) const { - // Credit: https://articles.emptycrate.com/2016/05/14/folds_in_cpp11_ish.html - bool result = false; - (void) std::initializer_list{ (result = result || in(args), 0)... }; - return result; - } - - bool in(const IdString &rhs) const { return *this == rhs; } - bool in(const char *rhs) const { return *this == rhs; } - bool in(const std::string &rhs) const { return *this == rhs; } - bool in(const pool &rhs) const { return rhs.count(*this) != 0; } - - bool isPublic() const { return begins_with("\\"); } - }; - - namespace ID { -#define X(_id) extern IdString _id; -#include "kernel/constids.inc" -#undef X - }; - - extern dict constpad; - - const pool &builtin_ff_cell_types(); - - static inline std::string escape_id(const std::string &str) { - if (str.size() > 0 && str[0] != '\\' && str[0] != '$') - return "\\" + str; - return str; - } - - static inline std::string unescape_id(const 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(const 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()(const RTLIL::IdString &a, const RTLIL::IdString &b) const { - return strcmp(a.c_str(), b.c_str()) < 0; - } - }; - - static inline std::string encode_filename(const std::string &filename) - { - std::stringstream val; - if (!std::any_of(filename.begin(), filename.end(), [](char c) { - return static_cast(c) < 33 || static_cast(c) > 126; - })) return filename; - for (unsigned char const c : filename) { - if (c < 33 || c > 126) - val << stringf("$%02x", c); - else - val << c; - } - return val.str(); - } - - // 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_divfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_modfloor (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); - - RTLIL::Const const_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); - RTLIL::Const const_pmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); - RTLIL::Const const_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2); - RTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2); - - RTLIL::Const const_bweqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2); - RTLIL::Const const_bwmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); - - - // 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 { - using iterator_category = std::forward_iterator_tag; - using value_type = T; - using difference_type = ptrdiff_t; - using pointer = T*; - using reference = T&; - 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 bool operator==(const RTLIL::ObjIterator &other) const { - return !(*this != other); - } - - inline ObjIterator& operator++() { - log_assert(list_p != nullptr); - if (++it == list_p->end()) { - (*refcount_p)--; - list_p = nullptr; - refcount_p = nullptr; - } - return *this; - } - - inline ObjIterator& operator+=(int amt) { - log_assert(list_p != nullptr); - it += amt; - if (it == list_p->end()) { - (*refcount_p)--; - list_p = nullptr; - refcount_p = nullptr; - } - return *this; - } - - inline ObjIterator operator+(int amt) { - log_assert(list_p != nullptr); - ObjIterator new_obj(*this); - new_obj.it += amt; - if (new_obj.it == list_p->end()) { - (*(new_obj.refcount_p))--; - new_obj.list_p = nullptr; - new_obj.refcount_p = nullptr; - } - return new_obj; - } - - inline const ObjIterator operator++(int) { - ObjIterator result(*this); - ++(*this); - return result; - } - }; - - 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() : flags(RTLIL::CONST_FLAG_NONE) {} - 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) = default; - 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(const std::string &str); - - std::string decode_string() const; - - inline int size() const { return bits.size(); } - inline bool empty() const { return bits.empty(); } - inline RTLIL::State &operator[](int index) { return bits.at(index); } - inline const RTLIL::State &operator[](int index) const { return bits.at(index); } - inline decltype(bits)::iterator begin() { return bits.begin(); } - inline decltype(bits)::iterator end() { return bits.end(); } - - bool is_fully_zero() const; - bool is_fully_ones() const; - bool is_fully_def() const; - bool is_fully_undef() const; - bool is_fully_undef_x_only() const; - bool is_onehot(int *pos = nullptr) 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; - - bool has_attribute(const RTLIL::IdString &id) const; - - void set_bool_attribute(const RTLIL::IdString &id, bool value=true); - bool get_bool_attribute(const RTLIL::IdString &id) const; - - bool get_blackbox_attribute(bool ignore_wb=false) const { - return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox)); - } - - void set_string_attribute(const RTLIL::IdString& id, string value); - string get_string_attribute(const RTLIL::IdString &id) const; - - void set_strpool_attribute(const RTLIL::IdString& id, const pool &data); - void add_strpool_attribute(const RTLIL::IdString& id, const pool &data); - pool get_strpool_attribute(const RTLIL::IdString &id) const; - - void set_src_attribute(const std::string &src) { - set_string_attribute(ID::src, src); - } - std::string get_src_attribute() const { - return get_string_attribute(ID::src); - } - - void set_hdlname_attribute(const vector &hierarchy); - vector get_hdlname_attribute() const; - - void set_intvec_attribute(const RTLIL::IdString& id, const vector &data); - vector get_intvec_attribute(const RTLIL::IdString &id) const; -}; - -struct RTLIL::SigChunk -{ - RTLIL::Wire *wire; - std::vector data; // only used if wire == NULL, LSB at index 0 - int width, offset; - - SigChunk() : wire(nullptr), width(0), offset(0) {} - SigChunk(const RTLIL::Const &value) : wire(nullptr), data(value.bits), width(GetSize(data)), offset(0) {} - SigChunk(RTLIL::Const &&value) : wire(nullptr), data(std::move(value.bits)), width(GetSize(data)), offset(0) {} - SigChunk(RTLIL::Wire *wire) : wire(wire), width(GetSize(wire)), offset(0) {} - SigChunk(RTLIL::Wire *wire, int offset, int width = 1) : wire(wire), width(width), offset(offset) {} - SigChunk(const std::string &str) : SigChunk(RTLIL::Const(str)) {} - SigChunk(int val, int width = 32) : SigChunk(RTLIL::Const(val, width)) {} - SigChunk(RTLIL::State bit, int width = 1) : SigChunk(RTLIL::Const(bit, width)) {} - SigChunk(const RTLIL::SigBit &bit); - - RTLIL::SigChunk extract(int offset, int length) const; - inline int size() const { return width; } - inline bool is_wire() const { return wire != NULL; } - - 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); - explicit 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) = default; - RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default; - - inline bool is_wire() const { return wire != NULL; } - - 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(); - } - - // Only used by Module::remove(const pool &wires) - // but cannot be more specific as it isn't yet declared - friend struct RTLIL::Module; - -public: - SigSpec() : width_(0), hash_(0) {} - SigSpec(std::initializer_list parts); - - SigSpec(const RTLIL::Const &value); - SigSpec(RTLIL::Const &&value); - SigSpec(const RTLIL::SigChunk &chunk); - SigSpec(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(const RTLIL::SigBit &bit, int width = 1); - SigSpec(const std::vector &chunks); - SigSpec(const std::vector &bits); - SigSpec(const pool &bits); - SigSpec(const std::set &bits); - explicit SigSpec(bool bit); - - 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; - RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); } - - void append(const RTLIL::SigSpec &signal); - inline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); } - inline void append(const RTLIL::SigChunk &chunk) { append(RTLIL::SigSpec(chunk)); } - inline void append(const RTLIL::Const &const_) { append(RTLIL::SigSpec(const_)); } - - void append(const RTLIL::SigBit &bit); - inline void append(RTLIL::State state) { append(RTLIL::SigBit(state)); } - inline void append(bool bool_) { append(RTLIL::SigBit(bool_)); } - - void extend_u0(int width, bool is_signed = false); - - RTLIL::SigSpec repeat(int num) const; - - void reverse() { inline_unpack(); std::reverse(bits_.begin(), bits_.end()); } - - 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 is_onehot(int *pos = nullptr) 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(const char* 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(); } - const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } - - unsigned int hash() const { if (!hash_) updhash(); return hash_; }; - -#ifndef NDEBUG - void check(Module *mod = nullptr) const; -#else - void check(Module *mod = nullptr) const { (void)mod; } -#endif -}; - -struct RTLIL::Selection -{ - bool full_selection; - pool selected_modules; - dict> selected_members; - - Selection(bool full = true) : full_selection(full) { } - - bool selected_module(const RTLIL::IdString &mod_name) const; - bool selected_whole_module(const RTLIL::IdString &mod_name) const; - bool selected_member(const RTLIL::IdString &mod_name, const 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&, const 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*) { } -}; - -// Forward declaration; defined in preproc.h. -struct define_map_t; - -struct RTLIL::Design -{ - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - - pool monitors; - dict scratchpad; - - int refcount_modules_; - dict modules_; - std::vector bindings_; - - std::vector verilog_packages, verilog_globals; - std::unique_ptr verilog_defines; - - std::vector selection_stack; - dict selection_vars; - std::string selected_active_module; - - Design(); - ~Design(); - - RTLIL::ObjRange modules(); - RTLIL::Module *module(const RTLIL::IdString &name); - const RTLIL::Module *module(const RTLIL::IdString &name) const; - RTLIL::Module *top_module(); - - bool has(const RTLIL::IdString &id) const { - return modules_.count(id) != 0; - } - - void add(RTLIL::Module *module); - void add(RTLIL::Binding *binding); - - RTLIL::Module *addModule(RTLIL::IdString name); - void remove(RTLIL::Module *module); - void rename(RTLIL::Module *module, RTLIL::IdString new_name); - - void scratchpad_unset(const std::string &varname); - - void scratchpad_set_int(const std::string &varname, int value); - void scratchpad_set_bool(const std::string &varname, bool value); - void scratchpad_set_string(const std::string &varname, std::string value); - - int scratchpad_get_int(const std::string &varname, int default_value = 0) const; - bool scratchpad_get_bool(const std::string &varname, bool default_value = false) const; - std::string scratchpad_get_string(const std::string &varname, const std::string &default_value = std::string()) const; - - void sort(); - void check(); - void optimize(); - - bool selected_module(const RTLIL::IdString &mod_name) const; - bool selected_whole_module(const RTLIL::IdString &mod_name) const; - bool selected_member(const RTLIL::IdString &mod_name, const 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) { - if (selection_stack.size() > 0) { - RTLIL::Selection &sel = selection_stack.back(); - sel.select(module); - } - } - - 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(bool include_wb = false) 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); - void add(RTLIL::Process *process); - -public: - RTLIL::Design *design; - pool monitors; - - int refcount_wires_; - int refcount_cells_; - - dict wires_; - dict cells_; - - std::vector connections_; - std::vector bindings_; - - RTLIL::IdString name; - idict avail_parameters; - dict parameter_default_values; - dict memories; - dict processes; - - Module(); - virtual ~Module(); - virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail = false); - virtual RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail = false); - virtual size_t count_id(const RTLIL::IdString& id); - virtual void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces); - virtual bool reprocess_if_necessary(RTLIL::Design *design); - - 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(const RTLIL::IdString &id) { - auto it = wires_.find(id); - return it == wires_.end() ? nullptr : it->second; - } - RTLIL::Cell* cell(const RTLIL::IdString &id) { - auto it = cells_.find(id); - return it == cells_.end() ? nullptr : it->second; - } - - const RTLIL::Wire* wire(const RTLIL::IdString &id) const{ - auto it = wires_.find(id); - return it == wires_.end() ? nullptr : it->second; - } - const RTLIL::Cell* cell(const RTLIL::IdString &id) const { - auto it = cells_.find(id); - return it == cells_.end() ? nullptr : it->second; - } - - RTLIL::ObjRange wires() { return RTLIL::ObjRange(&wires_, &refcount_wires_); } - RTLIL::ObjRange cells() { return RTLIL::ObjRange(&cells_, &refcount_cells_); } - - void add(RTLIL::Binding *binding); - - // 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 remove(RTLIL::Process *process); - - 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); - - RTLIL::Memory *addMemory(RTLIL::IdString name, const RTLIL::Memory *other); - - RTLIL::Process *addProcess(RTLIL::IdString name); - RTLIL::Process *addProcess(RTLIL::IdString name, const RTLIL::Process *other); - - // The add* methods create a cell and return the created cell. All signals must exist in advance. - - RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addShl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addShiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addLt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addEq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addEqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addNex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addGe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addGt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - // truncating division - RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - // truncating modulo - RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); - - RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - RTLIL::Cell* addLogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); - - RTLIL::Cell* addMux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addPmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - - RTLIL::Cell* addBweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addBwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - - RTLIL::Cell* addSlice (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = ""); - RTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addLut (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const std::string &src = ""); - RTLIL::Cell* addTribuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - RTLIL::Cell* addAssert (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addAssume (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addLive (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addFair (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addCover (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = ""); - RTLIL::Cell* addEquiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = ""); - - RTLIL::Cell* addSr (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addFf (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = ""); - RTLIL::Cell* addDff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsre (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAldff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAldffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdffce (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const 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, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addNotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addAndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addNandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addOrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addNorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addXorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addXnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addAndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addOrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addMuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addNmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addOai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const std::string &src = ""); - RTLIL::Cell* addOai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const std::string &src = ""); - - RTLIL::Cell* addSrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - const RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addFfGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = ""); - RTLIL::Cell* addDffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDffsreGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value = false, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAldffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAldffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value = false, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addSdffceGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = ""); - RTLIL::Cell* addAdlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, - bool arst_value = false, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); - RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, - RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); - - RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, 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, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Or (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Xor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Xnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec ReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec Shl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Shiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec Lt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Le (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Eq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Ne (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Eqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Nex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Ge (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Gt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - // truncating division - RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - // truncating modulo - RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = ""); - - RTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec LogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - RTLIL::SigSpec LogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); - - RTLIL::SigSpec Mux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = ""); - RTLIL::SigSpec Pmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = ""); - RTLIL::SigSpec Bmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = ""); - RTLIL::SigSpec Demux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = ""); - - RTLIL::SigSpec Bweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const std::string &src = ""); - RTLIL::SigSpec Bwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = ""); - - RTLIL::SigBit BufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = ""); - RTLIL::SigBit NotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = ""); - RTLIL::SigBit AndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit NandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit OrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit NorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit XorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit XnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit AndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit OrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = ""); - RTLIL::SigBit MuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = ""); - RTLIL::SigBit NmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = ""); - RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = ""); - RTLIL::SigBit Oai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = ""); - RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const std::string &src = ""); - RTLIL::SigBit Oai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const 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, is_signed; - -#ifdef WITH_PYTHON - static std::map *get_all_wires(void); -#endif -}; - -inline int GetSize(RTLIL::Wire *wire) { - return wire->width; -} - -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(const RTLIL::IdString &portname) const; - void unsetPort(const RTLIL::IdString &portname); - void setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal); - const RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const; - const dict &connections() const; - - // information about cell ports - bool known() const; - bool input(const RTLIL::IdString &portname) const; - bool output(const RTLIL::IdString &portname) const; - - // access cell parameters - bool hasParam(const RTLIL::IdString ¶mname) const; - void unsetParam(const RTLIL::IdString ¶mname); - void setParam(const RTLIL::IdString ¶mname, RTLIL::Const value); - const RTLIL::Const &getParam(const RTLIL::IdString ¶mname) 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(ID::keep) || (module && module->design && module->design->module(type) && - module->design->module(type)->get_bool_attribute(ID::keep)); - } - - template void rewrite_sigspecs(T &functor); - template void rewrite_sigspecs2(T &functor); - -#ifdef WITH_PYTHON - static std::map *get_all_cells(void); -#endif - - bool has_memid() const; - bool is_mem_cell() const; -}; - -struct RTLIL::CaseRule : public RTLIL::AttrObject -{ - std::vector compare; - std::vector actions; - std::vector switches; - - ~CaseRule(); - - 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::MemWriteAction : RTLIL::AttrObject -{ - RTLIL::IdString memid; - RTLIL::SigSpec address; - RTLIL::SigSpec data; - RTLIL::SigSpec enable; - RTLIL::Const priority_mask; -}; - -struct RTLIL::SyncRule -{ - RTLIL::SyncType type; - RTLIL::SigSpec signal; - std::vector actions; - std::vector mem_write_actions; - - template void rewrite_sigspecs(T &functor); - template void rewrite_sigspecs2(T &functor); - RTLIL::SyncRule *clone() const; -}; - -struct RTLIL::Process : public RTLIL::AttrObject -{ - unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } - -protected: - // use module->addProcess() and module->remove() to create or destroy processes - friend struct RTLIL::Module; - Process(); - ~Process(); - -public: - RTLIL::IdString name; - RTLIL::Module *module; - RTLIL::CaseRule root_case; - std::vector syncs; - - 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 ? State::S1 : State::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 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); - } - for (auto &it : mem_write_actions) { - functor(it.address); - functor(it.data); - functor(it.enable); - } -} - -template -void RTLIL::SyncRule::rewrite_sigspecs2(T &functor) -{ - functor(signal); - for (auto &it : actions) { - functor(it.first, it.second); - } - for (auto &it : mem_write_actions) { - functor(it.address); - functor(it.data); - functor(it.enable); - } -} - -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.cc b/yosys/kernel/satgen.cc deleted file mode 100644 index 3a2fa473568..00000000000 --- a/yosys/kernel/satgen.cc +++ /dev/null @@ -1,1385 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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/satgen.h" -#include "kernel/ff.h" - -USING_YOSYS_NAMESPACE - -bool SatGen::importCell(RTLIL::Cell *cell, int timestep) -{ - bool arith_undef_handled = false; - bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); - - if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor)) || is_arith_compare)) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::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.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { - std::vector b = importSigSpec(cell->getPort(ID::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(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), - ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($sub))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(a, b, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type.in(ID($and), ID($_AND_))) - ez->assume(ez->vec_eq(ez->vec_and(a, b), yy)); - if (cell->type == ID($_NAND_)) - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy)); - if (cell->type.in(ID($or), ID($_OR_))) - ez->assume(ez->vec_eq(ez->vec_or(a, b), yy)); - if (cell->type == ID($_NOR_)) - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy)); - if (cell->type.in(ID($xor), ID($_XOR_))) - ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy)); - if (cell->type.in(ID($xnor), ID($_XNOR_))) - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy)); - if (cell->type == ID($_ANDNOT_)) - ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy)); - if (cell->type == ID($_ORNOT_)) - ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy)); - if (cell->type == ID($add)) - ez->assume(ez->vec_eq(ez->vec_add(a, b), yy)); - if (cell->type == ID($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(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(undef_a, undef_b, undef_y, cell, false); - - if (cell->type.in(ID($and), ID($_AND_), ID($_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(ID($or), ID($_OR_), ID($_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(ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_))) { - std::vector yX = ez->vec_or(undef_a, undef_b); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else if (cell->type == ID($_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 == ID($_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(ID::Y), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) - { - bool aoi_mode = cell->type.in(ID($_AOI3_), ID($_AOI4_)); - bool three_mode = cell->type.in(ID($_AOI3_), ID($_OAI3_)); - - int a = importDefSigSpec(cell->getPort(ID::A), timestep).at(0); - int b = importDefSigSpec(cell->getPort(ID::B), timestep).at(0); - int c = importDefSigSpec(cell->getPort(ID::C), timestep).at(0); - int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort(ID::D), timestep).at(0); - int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); - int yy = model_undef ? ez->literal() : y; - - if (cell->type.in(ID($_AOI3_), ID($_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(ID::A), timestep).at(0); - int undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep).at(0); - int undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep).at(0); - int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort(ID::D), timestep).at(0); - int undef_y = importUndefSigSpec(cell->getPort(ID::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.in(ID($_NOT_), ID($not))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::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(ID::A), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::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 == ID($bweqx)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector bweqx = ez->vec_not(ez->vec_xor(a, b)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector both_undef = ez->vec_and(undef_a, undef_b); - std::vector both_def = ez->vec_and(ez->vec_not(undef_a), ez->vec_not(undef_b)); - - bweqx = ez->vec_or(both_undef, ez->vec_and(both_def, bweqx)); - - for (int yx : undef_y) - ez->assume(ez->NOT(yx)); - } - ez->assume(ez->vec_eq(bweqx, y)); - return true; - } - - if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_), ID($bwmux))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - if (cell->type == ID($_NMUX_)) - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy)); - else if (cell->type == ID($bwmux)) - ez->assume(ez->vec_eq(ez->vec_ite(s, b, a), yy)); - else - ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::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; - if (cell->type == ID($bwmux)) - yX = ez->vec_ite(undef_s, undef_ab, ez->vec_ite(s, undef_b, undef_a)); - else - 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 == ID($bmux)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - std::vector undef_a, undef_s, undef_y; - - if (model_undef) - { - undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); - undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - } - - if (GetSize(s) == 0) { - ez->vec_set(a, y); - if (model_undef) - ez->vec_set(undef_a, undef_y); - } else { - for (int i = GetSize(s)-1; i >= 0; i--) - { - std::vector out = (i == 0) ? y : ez->vec_var(a.size() / 2); - std::vector yy = model_undef ? ez->vec_var(out.size()) : out; - - std::vector a0(a.begin(), a.begin() + a.size() / 2); - std::vector a1(a.begin() + a.size() / 2, a.end()); - ez->assume(ez->vec_eq(ez->vec_ite(s.at(i), a1, a0), yy)); - - if (model_undef) - { - std::vector undef_out = (i == 0) ? undef_y : ez->vec_var(a.size() / 2); - std::vector undef_a0(undef_a.begin(), undef_a.begin() + a.size() / 2); - std::vector undef_a1(undef_a.begin() + a.size() / 2, undef_a.end()); - std::vector unequal_ab = ez->vec_not(ez->vec_iff(a0, a1)); - std::vector undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a0, undef_a1)); - std::vector yX = ez->vec_ite(undef_s.at(i), undef_ab, ez->vec_ite(s.at(i), undef_a1, undef_a0)); - ez->assume(ez->vec_eq(yX, undef_out)); - undefGating(out, yy, undef_out); - - undef_a = undef_out; - } - - a = out; - } - } - return true; - } - - if (cell->type == ID($demux)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - std::vector undef_a, undef_s, undef_y; - - if (model_undef) - { - undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); - undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - } - - if (GetSize(s) == 0) { - ez->vec_set(a, y); - if (model_undef) - ez->vec_set(undef_a, undef_y); - } else { - for (int i = 0; i < (1 << GetSize(s)); i++) - { - std::vector ss; - for (int j = 0; j < GetSize(s); j++) { - if (i & 1 << j) - ss.push_back(s[j]); - else - ss.push_back(ez->NOT(s[j])); - } - int sss = ez->expression(ezSAT::OpAnd, ss); - - for (int j = 0; j < GetSize(a); j++) { - ez->SET(ez->AND(sss, a[j]), yy.at(i * GetSize(a) + j)); - } - - if (model_undef) - { - int s0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(ss), ez->vec_not(undef_s))); - int us = ez->AND(ez->NOT(s0), ez->expression(ezSAT::OpOr, undef_s)); - for (int j = 0; j < GetSize(a); j++) { - int a0 = ez->AND(ez->NOT(a[j]), ez->NOT(undef_a[j])); - int yX = ez->AND(ez->OR(us, undef_a[j]), ez->NOT(ez->OR(s0, a0))); - ez->SET(yX, undef_y.at(i * GetSize(a) + j)); - } - } - } - if (model_undef) - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == ID($pmux)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::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(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - - int all_undef = ez->CONST_FALSE; - int found_active = ez->CONST_FALSE; - - std::vector undef_tmp = undef_a; - - for (size_t i = 0; i < s.size(); i++) - { - std::vector part_of_undef_b(undef_b.begin()+i*a.size(), undef_b.begin()+(i+1)*a.size()); - - undef_tmp = ez->vec_ite(s.at(i), part_of_undef_b, undef_tmp); - all_undef = ez->OR(all_undef, undef_s.at(i)); - all_undef = ez->OR(all_undef, ez->AND(s.at(i), found_active)); - found_active = ez->OR(found_active, s.at(i)); - } - - undef_tmp = ez->vec_or(undef_tmp, std::vector(a.size(), all_undef)); - - ez->assume(ez->vec_eq(undef_tmp, undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in(ID($pos), ID($neg))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidthUnary(a, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == ID($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(ID::A), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell); - - if (cell->type == ID($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.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == ID($reduce_and)) - ez->SET(ez->expression(ez->OpAnd, a), yy.at(0)); - if (cell->type.in(ID($reduce_or), ID($reduce_bool))) - ez->SET(ez->expression(ez->OpOr, a), yy.at(0)); - if (cell->type == ID($reduce_xor)) - ez->SET(ez->expression(ez->OpXor, a), yy.at(0)); - if (cell->type == ID($reduce_xnor)) - ez->SET(ez->NOT(ez->expression(ez->OpXor, a)), yy.at(0)); - if (cell->type == ID($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(ID::A), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - int aX = ez->expression(ezSAT::OpOr, undef_a); - - if (cell->type == ID($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.in(ID($reduce_or), ID($reduce_bool), ID($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.in(ID($reduce_xor), ID($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.in(ID($logic_and), ID($logic_or))) - { - std::vector vec_a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector vec_b = importDefSigSpec(cell->getPort(ID::B), timestep); - - int a = ez->expression(ez->OpOr, vec_a); - int b = ez->expression(ez->OpOr, vec_b); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == ID($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(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::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 == ID($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 == ID($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.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) - { - bool is_signed = cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool(); - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(a, b, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (model_undef && cell->type.in(ID($eqx), ID($nex))) { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::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 == ID($lt)) - ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), yy.at(0)); - if (cell->type == ID($le)) - ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), yy.at(0)); - if (cell->type.in(ID($eq), ID($eqx))) - ez->SET(ez->vec_eq(a, b), yy.at(0)); - if (cell->type.in(ID($ne), ID($nex))) - ez->SET(ez->vec_ne(a, b), yy.at(0)); - if (cell->type == ID($ge)) - ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), yy.at(0)); - if (cell->type == ID($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.in(ID($eqx), ID($nex))) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(undef_a, undef_b, cell, true); - - if (cell->type == ID($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.in(ID($eq), ID($ne))) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::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(ID::Y), timestep); - undefGating(y, yy, undef_y); - } - log_assert(!model_undef || arith_undef_handled); - } - return true; - } - - if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - int extend_bit = ez->CONST_FALSE; - - if (cell->parameters[ID::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.in( ID($shl), ID($sshl))) - shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($shr)) - shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($sshr)) - shifted_a = ez->vec_shift_right(a, b, false, cell->parameters[ID::A_SIGNED].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type.in(ID($shift), ID($shiftx))) - shifted_a = ez->vec_shift_right(a, b, cell->parameters[ID::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(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - std::vector undef_a_shifted; - - extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE; - if (cell->parameters[ID::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.in(ID($shl), ID($sshl))) - undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($shr)) - undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($sshr)) - undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters[ID::A_SIGNED].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($shift)) - undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($shiftx)) - undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID::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 == ID($mul)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::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(ID::Y), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == ID($macc)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::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(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::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(ID::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.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::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[ID::A_SIGNED].as_bool() && cell->parameters[ID::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()); - - // modulo calculation - std::vector modulo_trunc; - int floored_eq_trunc; - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { - modulo_trunc = ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf); - // floor == trunc when sgn(a) == sgn(b) or trunc == 0 - floored_eq_trunc = ez->OR(ez->IFF(a.back(), b.back()), ez->NOT(ez->expression(ezSAT::OpOr, modulo_trunc))); - } else { - modulo_trunc = chain_buf; - floored_eq_trunc = ez->CONST_TRUE; - } - - if (cell->type == ID($div)) { - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::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->type == ID($mod)) { - ez->assume(ez->vec_eq(y_tmp, modulo_trunc)); - } else if (cell->type == ID($divfloor)) { - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite( - ez->XOR(a.back(), b.back()), - ez->vec_neg(ez->vec_ite( - ez->vec_reduce_or(modulo_trunc), - ez->vec_add(y_u, ez->vec_const_unsigned(1, y_u.size())), - y_u - )), - y_u - ))); - else - ez->assume(ez->vec_eq(y_tmp, y_u)); - } else if (cell->type == ID($modfloor)) { - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(floored_eq_trunc, modulo_trunc, ez->vec_add(modulo_trunc, b)))); - } - - if (ignore_div_by_zero) { - ez->assume(ez->expression(ezSAT::OpOr, b)); - } else { - std::vector div_zero_result; - if (cell->type.in(ID($div), ID($divfloor))) { - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::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(ID::A).size(), ez->CONST_TRUE); - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); - } - } else if (cell->type.in(ID($mod), ID($modfloor))) { - // a mod 0 = a - int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size()); - div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::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(ID::Y), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == ID($lut)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector lut; - for (auto bit : cell->getParam(ID::LUT).bits) - lut.push_back(bit == State::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(ID::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(ID::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 == ID($sop)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); - - int width = cell->getParam(ID::WIDTH).as_int(); - int depth = cell->getParam(ID::DEPTH).as_int(); - - vector table_raw = cell->getParam(ID::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(ID::A), timestep); - int undef_y = importUndefSigSpec(cell->getPort(ID::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 == ID($fa)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector c = importDefSigSpec(cell->getPort(ID::C), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - std::vector x = importDefSigSpec(cell->getPort(ID::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(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep); - - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - std::vector undef_x = importUndefSigSpec(cell->getPort(ID::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 == ID($lcu)) - { - std::vector p = importDefSigSpec(cell->getPort(ID::P), timestep); - std::vector g = importDefSigSpec(cell->getPort(ID::G), timestep); - std::vector ci = importDefSigSpec(cell->getPort(ID::CI), timestep); - std::vector co = importDefSigSpec(cell->getPort(ID::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(ID::P), timestep); - std::vector undef_g = importUndefSigSpec(cell->getPort(ID::G), timestep); - std::vector undef_ci = importUndefSigSpec(cell->getPort(ID::CI), timestep); - std::vector undef_co = importUndefSigSpec(cell->getPort(ID::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 == ID($alu)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - std::vector x = importDefSigSpec(cell->getPort(ID::X), timestep); - std::vector ci = importDefSigSpec(cell->getPort(ID::CI), timestep); - std::vector bi = importDefSigSpec(cell->getPort(ID::BI), timestep); - std::vector co = importDefSigSpec(cell->getPort(ID::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(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_ci = importUndefSigSpec(cell->getPort(ID::CI), timestep); - std::vector undef_bi = importUndefSigSpec(cell->getPort(ID::BI), timestep); - - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - std::vector undef_x = importUndefSigSpec(cell->getPort(ID::X), timestep); - std::vector undef_co = importUndefSigSpec(cell->getPort(ID::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 == ID($slice)) - { - RTLIL::SigSpec a = cell->getPort(ID::A); - RTLIL::SigSpec y = cell->getPort(ID::Y); - ez->assume(signals_eq(a.extract(cell->parameters.at(ID::OFFSET).as_int(), y.size()), y, timestep)); - return true; - } - - if (cell->type == ID($concat)) - { - RTLIL::SigSpec a = cell->getPort(ID::A); - RTLIL::SigSpec b = cell->getPort(ID::B); - RTLIL::SigSpec y = cell->getPort(ID::Y); - - RTLIL::SigSpec ab = a; - ab.append(b); - - ez->assume(signals_eq(ab, y, timestep)); - return true; - } - - if (timestep > 0 && (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit))) - { - FfData ff(nullptr, cell); - - // Latches and FFs with async inputs are not supported — use clk2fflogic or async2sync first. - if (ff.has_aload || ff.has_arst || ff.has_sr) - return false; - - if (timestep == 1) - { - initial_state.add((*sigmap)(cell->getPort(ID::Q))); - if (model_undef && def_formal) { - std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Q), timestep); - ez->assume(ez->NOT(ez->vec_reduce_or(undef_q))); - } - } - else - { - std::vector d = importDefSigSpec(cell->getPort(ID::D), timestep-1); - std::vector undef_d; - if (model_undef) - undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1); - if (ff.has_srst && ff.has_ce && ff.ce_over_srst) { - int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0); - std::vector rval = importDefSigSpec(ff.val_srst, timestep-1); - int undef_srst; - std::vector undef_rval; - if (model_undef) { - undef_srst = importUndefSigSpec(ff.sig_srst, timestep-1).at(0); - undef_rval = importUndefSigSpec(ff.val_srst, timestep-1); - } - if (ff.pol_srst) - std::tie(d, undef_d) = mux(srst, undef_srst, d, undef_d, rval, undef_rval); - else - std::tie(d, undef_d) = mux(srst, undef_srst, rval, undef_rval, d, undef_d); - } - if (ff.has_ce) { - int ce = importDefSigSpec(ff.sig_ce, timestep-1).at(0); - std::vector old_q = importDefSigSpec(ff.sig_q, timestep-1); - int undef_ce; - std::vector undef_old_q; - if (model_undef) { - undef_ce = importUndefSigSpec(ff.sig_ce, timestep-1).at(0); - undef_old_q = importUndefSigSpec(ff.sig_q, timestep-1); - } - if (ff.pol_ce) - std::tie(d, undef_d) = mux(ce, undef_ce, old_q, undef_old_q, d, undef_d); - else - std::tie(d, undef_d) = mux(ce, undef_ce, d, undef_d, old_q, undef_old_q); - } - if (ff.has_srst && !(ff.has_ce && ff.ce_over_srst)) { - int srst = importDefSigSpec(ff.sig_srst, timestep-1).at(0); - std::vector rval = importDefSigSpec(ff.val_srst, timestep-1); - int undef_srst; - std::vector undef_rval; - if (model_undef) { - undef_srst = importUndefSigSpec(ff.sig_srst, timestep-1).at(0); - undef_rval = importUndefSigSpec(ff.val_srst, timestep-1); - } - if (ff.pol_srst) - std::tie(d, undef_d) = mux(srst, undef_srst, d, undef_d, rval, undef_rval); - else - std::tie(d, undef_d) = mux(srst, undef_srst, rval, undef_rval, d, undef_d); - } - std::vector q = importDefSigSpec(cell->getPort(ID::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_q = importUndefSigSpec(cell->getPort(ID::Q), timestep); - - ez->assume(ez->vec_eq(undef_d, undef_q)); - undefGating(q, qq, undef_q); - } - } - return true; - } - - if (cell->type == ID($anyconst)) - { - if (timestep < 2) { - if (model_undef && def_formal) { - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - ez->assume(ez->NOT(ez->vec_reduce_or(undef_y))); - } - return true; - } - - std::vector d = importDefSigSpec(cell->getPort(ID::Y), timestep-1); - std::vector q = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector qq = (model_undef && !def_formal) ? ez->vec_var(q.size()) : q; - ez->assume(ez->vec_eq(d, qq)); - - if (model_undef) - { - std::vector undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1); - std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep); - - if (def_formal) { - for (auto &undef_q_bit : undef_q) - ez->SET(ez->CONST_FALSE, undef_q_bit); - } else { - ez->assume(ez->vec_eq(undef_d, undef_q)); - undefGating(q, qq, undef_q); - } - } - return true; - } - - if (cell->type == ID($anyseq)) - { - if (model_undef && def_formal) { - std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep); - for (auto &undef_q_bit : undef_q) - ez->SET(ez->CONST_FALSE, undef_q_bit); - } - return true; - } - - if (cell->type.in(ID($_BUF_), ID($equiv))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::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(ID::A), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::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 == ID($initstate)) - { - auto key = make_pair(prefix, timestep); - if (initstates.count(key) == 0) - initstates[key] = false; - - std::vector y = importDefSigSpec(cell->getPort(ID::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(ID::Y), timestep); - log_assert(GetSize(undef_y) == 1); - ez->SET(undef_y[0], ez->CONST_FALSE); - } - - return true; - } - - if (cell->type == ID($assert)) - { - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - asserts_a[pf].append((*sigmap)(cell->getPort(ID::A))); - asserts_en[pf].append((*sigmap)(cell->getPort(ID::EN))); - return true; - } - - if (cell->type == ID($assume)) - { - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - assumes_a[pf].append((*sigmap)(cell->getPort(ID::A))); - assumes_en[pf].append((*sigmap)(cell->getPort(ID::EN))); - return true; - } - - // Unsupported internal cell types: $pow $fsm $mem* - // .. and all sequential cells with asynchronous inputs - return false; -} diff --git a/yosys/kernel/satgen.h b/yosys/kernel/satgen.h deleted file mode 100644 index 8a89ff9dba4..00000000000 --- a/yosys/kernel/satgen.h +++ /dev/null @@ -1,295 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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; - bool def_formal = false; - - 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(ID::A_SIGNED) > 0 && cell->parameters.count(ID::B_SIGNED) > 0) - is_signed = cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::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(ID::A_SIGNED) > 0 && cell->parameters[ID::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)))); - } - } - - std::pair, std::vector> mux(int s, int undef_s, const std::vector &a, const std::vector &undef_a, const std::vector &b, const std::vector &undef_b) { - std::vector res; - std::vector undef_res; - res = ez->vec_ite(s, b, a); - if (model_undef) { - 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)); - undef_res = ez->vec_ite(undef_s, undef_ab, ez->vec_ite(s, undef_b, undef_a)); - } - return std::make_pair(res, undef_res); - } - - 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); -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/sigtools.h b/yosys/kernel/sigtools.h deleted file mode 100644 index 4ea43d74364..00000000000 --- a/yosys/kernel/sigtools.h +++ /dev/null @@ -1,347 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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(const 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(const 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(const RTLIL::SigSpec &from, const 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(const RTLIL::SigSpec &sig) const - { - RTLIL::SigSpec result; - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit)) - result.append(bit); - return result; - } - - RTLIL::SigSpec remove(const RTLIL::SigSpec &sig) const - { - RTLIL::SigSpec result; - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit) == 0) - result.append(bit); - return result; - } - - bool check(const RTLIL::SigBit &bit) const - { - return bit.wire != NULL && bits.count(bit); - } - - bool check_any(const RTLIL::SigSpec &sig) const - { - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit)) - return true; - return false; - } - - bool check_all(const RTLIL::SigSpec &sig) const - { - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit) == 0) - return false; - return true; - } - - RTLIL::SigSpec export_one() const - { - for (auto &bit : bits) - return RTLIL::SigSpec(bit.first, bit.second); - return RTLIL::SigSpec(); - } - - RTLIL::SigSpec export_all() const - { - 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 -{ - static_assert(!std::is_same::value, "Default value for `Compare' class not found for SigSet. Please specify."); - - 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(const RTLIL::SigSpec &sig, T data) - { - for (const auto &bit : sig) - if (bit.wire != NULL) - bits[bit].insert(data); - } - - void insert(const RTLIL::SigSpec& sig, const std::set &data) - { - for (const auto &bit : sig) - if (bit.wire != NULL) - bits[bit].insert(data.begin(), data.end()); - } - - void erase(const RTLIL::SigSpec& sig) - { - for (const auto &bit : sig) - if (bit.wire != NULL) - bits[bit].clear(); - } - - void erase(const RTLIL::SigSpec &sig, T data) - { - for (const auto &bit : sig) - if (bit.wire != NULL) - bits[bit].erase(data); - } - - void erase(const RTLIL::SigSpec &sig, const std::set &data) - { - for (const auto &bit : sig) - if (bit.wire != NULL) - bits[bit].erase(data.begin(), data.end()); - } - - void find(const RTLIL::SigSpec &sig, std::set &result) - { - for (const auto &bit : sig) - if (bit.wire != NULL) { - auto &data = bits[bit]; - result.insert(data.begin(), data.end()); - } - } - - void find(const RTLIL::SigSpec &sig, pool &result) - { - for (const auto &bit : sig) - if (bit.wire != NULL) { - auto &data = bits[bit]; - result.insert(data.begin(), data.end()); - } - } - - std::set find(const RTLIL::SigSpec &sig) - { - std::set result; - find(sig, result); - return result; - } - - bool has(const RTLIL::SigSpec &sig) - { - for (auto &bit : sig) - if (bit.wire != NULL && bits.count(bit)) - return true; - return false; - } -}; - -template -class SigSet::value>::type> : public SigSet> {}; -template -using sort_by_name_id_guard = typename std::enable_if::value>::type; -template -class SigSet> : public SigSet::type>> {}; - -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(const RTLIL::SigSpec& from, const 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(const RTLIL::SigBit &bit) - { - const auto &b = database.find(bit); - if (b.wire != nullptr) - database.promote(bit); - } - - void add(const RTLIL::SigSpec &sig) - { - for (const auto &bit : sig) - add(bit); - } - - inline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); } - - 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 (const auto &bit : database) - if (bit.wire != nullptr) - sig.append(bit); - return sig; - } -}; - -YOSYS_NAMESPACE_END - -#endif /* SIGTOOLS_H */ diff --git a/yosys/kernel/timinginfo.h b/yosys/kernel/timinginfo.h deleted file mode 100644 index e7e4eab6e2e..00000000000 --- a/yosys/kernel/timinginfo.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * (C) 2020 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 TIMINGINFO_H -#define TIMINGINFO_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -struct TimingInfo -{ - struct NameBit - { - RTLIL::IdString name; - int offset; - NameBit() : offset(0) {} - NameBit(const RTLIL::IdString name, int offset) : name(name), offset(offset) {} - explicit NameBit(const RTLIL::SigBit &b) : name(b.wire->name), offset(b.offset) {} - bool operator==(const NameBit& nb) const { return nb.name == name && nb.offset == offset; } - bool operator!=(const NameBit& nb) const { return !operator==(nb); } - unsigned int hash() const { return mkhash_add(name.hash(), offset); } - }; - struct BitBit - { - NameBit first, second; - BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {} - BitBit(const SigBit &first, const SigBit &second) : first(first), second(second) {} - bool operator==(const BitBit& bb) const { return bb.first == first && bb.second == second; } - unsigned int hash() const { return mkhash_add(first.hash(), second.hash()); } - }; - - struct ModuleTiming - { - dict comb; - dict> arrival, required; - bool has_inputs; - }; - - dict data; - - TimingInfo() - { - } - - TimingInfo(RTLIL::Design *design) - { - setup(design); - } - - void setup(RTLIL::Design *design) - { - for (auto module : design->modules()) { - if (!module->get_blackbox_attribute()) - continue; - setup_module(module); - } - } - - const ModuleTiming& setup_module(RTLIL::Module *module) - { - auto r = data.insert(module->name); - log_assert(r.second); - auto &t = r.first->second; - - for (auto cell : module->cells()) { - if (cell->type == ID($specify2)) { - auto en = cell->getPort(ID::EN); - if (en.is_fully_const() && !en.as_bool()) - continue; - auto src = cell->getPort(ID::SRC); - auto dst = cell->getPort(ID::DST); - for (const auto &c : src.chunks()) - if (!c.wire || !c.wire->port_input) - log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src)); - for (const auto &c : dst.chunks()) - if (!c.wire || !c.wire->port_output) - log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst)); - int rise_max = cell->getParam(ID::T_RISE_MAX).as_int(); - int fall_max = cell->getParam(ID::T_FALL_MAX).as_int(); - int max = std::max(rise_max,fall_max); - if (max < 0) - log_error("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0.\n", log_id(module), log_id(cell)); - if (cell->getParam(ID::FULL).as_bool()) { - for (const auto &s : src) - for (const auto &d : dst) { - auto r = t.comb.insert(BitBit(s,d)); - if (!r.second) - log_error("Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\n", log_id(module), log_signal(s), log_signal(d)); - r.first->second = max; - } - } - else { - log_assert(GetSize(src) == GetSize(dst)); - for (auto i = 0; i < GetSize(src); i++) { - const auto &s = src[i]; - const auto &d = dst[i]; - auto r = t.comb.insert(BitBit(s,d)); - if (!r.second) - log_error("Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\n", log_id(module), log_signal(s), log_signal(d)); - r.first->second = max; - } - } - } - else if (cell->type == ID($specify3)) { - auto src = cell->getPort(ID::SRC).as_bit(); - auto dst = cell->getPort(ID::DST); - if (!src.wire || !src.wire->port_input) - log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src)); - for (const auto &c : dst.chunks()) - if (!c.wire->port_output) - log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst)); - int rise_max = cell->getParam(ID::T_RISE_MAX).as_int(); - int fall_max = cell->getParam(ID::T_FALL_MAX).as_int(); - int max = std::max(rise_max,fall_max); - if (max < 0) { - log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell)); - max = 0; - } - for (const auto &d : dst) { - auto r = t.arrival.insert(NameBit(d)); - auto &v = r.first->second; - if (r.second || v.first < max) { - v.first = max; - v.second = NameBit(src); - } - } - } - else if (cell->type == ID($specrule)) { - IdString type = cell->getParam(ID::TYPE).decode_string(); - if (type != ID($setup) && type != ID($setuphold)) - continue; - auto src = cell->getPort(ID::SRC); - auto dst = cell->getPort(ID::DST).as_bit(); - for (const auto &c : src.chunks()) - if (!c.wire || !c.wire->port_input) - log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src)); - if (!dst.wire || !dst.wire->port_input) - log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst)); - int max = cell->getParam(ID::T_LIMIT_MAX).as_int(); - if (max < 0) { - log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell)); - max = 0; - } - for (const auto &s : src) { - auto r = t.required.insert(NameBit(s)); - auto &v = r.first->second; - if (r.second || v.first < max) { - v.first = max; - v.second = NameBit(dst); - } - } - } - } - - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - if (wire->port_input) { - t.has_inputs = true; - break; - } - } - - return t; - } - - decltype(data)::const_iterator find(RTLIL::IdString module_name) const { return data.find(module_name); } - decltype(data)::const_iterator end() const { return data.end(); } - int count(RTLIL::IdString module_name) const { return data.count(module_name); } - const ModuleTiming& at(RTLIL::IdString module_name) const { return data.at(module_name); } -}; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/utils.h b/yosys/kernel/utils.h deleted file mode 100644 index d37f045ff7c..00000000000 --- a/yosys/kernel/utils.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 bd8dded4b5f..00000000000 --- a/yosys/kernel/yosys.cc +++ /dev/null @@ -1,1558 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 -# if !defined(YOSYS_DISABLE_SPAWN) -# include -# endif -#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 -#include -#endif - -#include -#include - -#include "libs/json11/json11.hpp" - -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; -bool yosys_tcl_repl_active = false; -#endif - -std::set yosys_input_files, yosys_output_files; - -bool memhasher_active = false; -uint32_t memhasher_rng = 123456; -std::vector memhasher_store; - -std::string yosys_share_dirname; -std::string yosys_abc_executable; - -void init_share_dirname(); -void init_abc_executable_name(); - -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 - 2020 Claire Xenia 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; -} - -#if !defined(YOSYS_DISABLE_SPAWN) -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 -} -#endif - -std::string get_base_tmpdir() -{ - static std::string tmpdir; - - if (!tmpdir.empty()) { - return tmpdir; - } - -#if defined(_WIN32) -# 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"); - for (int i = 0; shortpath[i]; i++) - tmpdir += char(shortpath[i]); -#else - char * var = std::getenv("TMPDIR"); - if (var && strlen(var)!=0) { - tmpdir.assign(var); - // We return the directory name without the trailing '/' - while (!tmpdir.empty() && (tmpdir.back() == '/')) { - tmpdir.pop_back(); - } - } else { - tmpdir.assign("/tmp"); - } -#endif - return tmpdir; -} - -std::string make_temp_file(std::string template_str) -{ - size_t pos = template_str.rfind("XXXXXX"); - log_assert(pos != std::string::npos); -#if defined(__wasm) - static size_t index = 0; - template_str.replace(pos, 6, stringf("%06zu", index++)); -#elif defined(_WIN32) -#ifndef YOSYS_WIN32_UNIX_DIR - std::replace(template_str.begin(), template_str.end(), '/', '\\'); -#endif - 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 - 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) -{ -#if defined(_WIN32) - template_str = make_temp_file(template_str); - mkdir(template_str.c_str()); - return template_str; -#elif defined(__wasm) - template_str = make_temp_file(template_str); - mkdir(template_str.c_str(), 0777); - 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()); - char *res = mkdtemp(p); - log_assert(res != 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; -} - -bool already_setup = false; - -void yosys_setup() -{ - if(already_setup) - return; - already_setup = true; - init_share_dirname(); - init_abc_executable_name(); - -#define X(_id) RTLIL::ID::_id = "\\" # _id; -#include "kernel/constids.inc" -#undef X - - #ifdef WITH_PYTHON - PyImport_AppendInittab((char*)"libyosys", INIT_MODULE); - Py_Initialize(); - PyRun_SimpleString("import sys"); - signal(SIGINT, SIG_DFL); - #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(); - - Pass::done_register(); - - delete yosys_design; - yosys_design = NULL; - - for (auto f : log_files) - if (f != stderr) - fclose(f); - log_errfile = NULL; - log_files.clear(); - - yosys_celltypes.clear(); - -#ifdef YOSYS_ENABLE_TCL - if (yosys_tcl_interp != NULL) { - if (!Tcl_InterpDeleted(yosys_tcl_interp)) { - 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 -} - -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::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix) -{ -#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$%s$%d", file.c_str(), line, func.c_str(), suffix.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.compare(0, 1, "\"") == 0 && filename.compare(GetSize(filename)-1, std::string::npos, "\"") == 0) - filename = filename.substr(1, GetSize(filename)-2); - if (filename.compare(0, 2, "+/") == 0) - filename = proc_share_dirname() + filename.substr(2); -#ifndef _WIN32 - if (filename.compare(0, 2, "~/") == 0) - filename = filename.replace(0, 1, getenv("HOME")); -#endif -} - -#ifdef YOSYS_ENABLE_TCL - -static Tcl_Obj *json_to_tcl(Tcl_Interp *interp, const json11::Json &json) -{ - if (json.is_null()) - return Tcl_NewStringObj("null", 4); - else if (json.is_string()) { - auto string = json.string_value(); - return Tcl_NewStringObj(string.data(), string.size()); - } else if (json.is_number()) { - double value = json.number_value(); - double round_val = std::nearbyint(value); - if (std::isfinite(round_val) && value == round_val && value >= LONG_MIN && value < -double(LONG_MIN)) - return Tcl_NewLongObj((long)round_val); - else - return Tcl_NewDoubleObj(value); - } else if (json.is_bool()) { - return Tcl_NewBooleanObj(json.bool_value()); - } else if (json.is_array()) { - auto list = json.array_items(); - Tcl_Obj *result = Tcl_NewListObj(list.size(), nullptr); - for (auto &item : list) - Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item)); - return result; - } else if (json.is_object()) { - auto map = json.object_items(); - Tcl_Obj *result = Tcl_NewListObj(map.size() * 2, nullptr); - for (auto &item : map) { - Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(item.first.data(), item.first.size())); - Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item.second)); - } - return result; - } else { - log_abort(); - } -} - -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; - } - - yosys_get_design()->scratchpad_unset("result.json"); - yosys_get_design()->scratchpad_unset("result.string"); - - bool in_repl = yosys_tcl_repl_active; - bool restore_log_cmd_error_throw = log_cmd_error_throw; - - log_cmd_error_throw = true; - - try { - if (args.size() == 1) { - Pass::call(yosys_get_design(), args[0]); - } else { - Pass::call(yosys_get_design(), args); - } - } catch (log_cmd_error_exception) { - if (in_repl) { - auto design = yosys_get_design(); - while (design->selection_stack.size() > 1) - design->selection_stack.pop_back(); - log_reset_stack(); - } - Tcl_SetResult(interp, (char *)"Yosys command produced an error", TCL_STATIC); - - yosys_tcl_repl_active = in_repl; - log_cmd_error_throw = restore_log_cmd_error_throw; - return TCL_ERROR; - } catch (...) { - log_error("uncaught exception during Yosys command invoked from TCL\n"); - } - - yosys_tcl_repl_active = in_repl; - log_cmd_error_throw = restore_log_cmd_error_throw; - - auto &scratchpad = yosys_get_design()->scratchpad; - auto result = scratchpad.find("result.json"); - if (result != scratchpad.end()) { - std::string err; - auto json = json11::Json::parse(result->second, err); - if (err.empty()) { - Tcl_SetObjResult(interp, json_to_tcl(interp, json)); - } else - log_warning("Ignoring result.json scratchpad value due to parse error: %s\n", err.c_str()); - } else if ((result = scratchpad.find("result.string")) != scratchpad.end()) { - Tcl_SetObjResult(interp, Tcl_NewStringObj(result->second.data(), result->second.size())); - } - - return TCL_OK; -} - -int yosys_tcl_iterp_init(Tcl_Interp *interp) -{ - if (Tcl_Init(interp)!=TCL_OK) - log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno())); - Tcl_CreateCommand(interp, "yosys", tcl_yosys_cmd, NULL, NULL); - return TCL_OK ; -} - -void yosys_tcl_activate_repl() -{ - yosys_tcl_repl_active = true; -} - -extern Tcl_Interp *yosys_get_tcl_interp() -{ - if (yosys_tcl_interp == NULL) { - yosys_tcl_interp = Tcl_CreateInterp(); - yosys_tcl_iterp_init(yosys_tcl_interp); - } - return yosys_tcl_interp; -} - -struct TclPass : public Pass { - TclPass() : Pass("tcl", "execute a TCL script file") { } - void help() 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"); - log("Note, tcl will not recieve the output of any yosys command. If the output\n"); - log("of the tcl commands are needed, use the yosys command 'tee -s result.string'\n"); - log("to redirect yosys's output to the 'result.string' scratchpad value.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *) 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_Preserve(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)); - Tcl_Release(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--; - std::string str(path, buflen); - free(path); - return str; -} -#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) || defined(__wasm) -std::string proc_self_dirname() -{ - return "/"; -} -#elif defined(__OpenBSD__) -char yosys_path[PATH_MAX]; -char *yosys_argv0; - -std::string proc_self_dirname(void) -{ - char buf[PATH_MAX + 1] = "", *path, *p; - // if case argv[0] contains a valid path, return it - if (strlen(yosys_path) > 0) { - p = strrchr(yosys_path, '/'); - snprintf(buf, sizeof buf, "%*s/", (int)(yosys_path - p), yosys_path); - return buf; - } - // if argv[0] does not, reconstruct the path out of $PATH - path = strdup(getenv("PATH")); - if (!path) - log_error("getenv(\"PATH\") failed: %s\n", strerror(errno)); - for (p = strtok(path, ":"); p; p = strtok(NULL, ":")) { - snprintf(buf, sizeof buf, "%s/%s", p, yosys_argv0); - if (access(buf, X_OK) == 0) { - *(strrchr(buf, '/') + 1) = '\0'; - free(path); - return buf; - } - } - free(path); - log_error("Can't determine yosys executable path\n."); - return NULL; -} -#else - #error "Don't know how to determine process executable base path!" -#endif - -#if defined(EMSCRIPTEN) || defined(__wasm) -void init_share_dirname() -{ - yosys_share_dirname = "/share/"; -} -#else -void init_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)) { - yosys_share_dirname = proc_share_path; - return; - } - proc_share_path = proc_self_path + "..\\share\\"; - if (check_file_exists(proc_share_path, true)) { - yosys_share_dirname = proc_share_path; - return; - } -# else - std::string proc_share_path = proc_self_path + "share/"; - if (check_file_exists(proc_share_path, true)) { - yosys_share_dirname = proc_share_path; - return; - } - proc_share_path = proc_self_path + "../share/" + proc_program_prefix()+ "yosys/"; - if (check_file_exists(proc_share_path, true)) { - yosys_share_dirname = proc_share_path; - return; - } -# ifdef YOSYS_DATDIR - proc_share_path = YOSYS_DATDIR "/"; - if (check_file_exists(proc_share_path, true)) { - yosys_share_dirname = proc_share_path; - return; - } -# endif -# endif -} -#endif - -void init_abc_executable_name() -{ -#ifdef ABCEXTERNAL - std::string exe_file; - if (std::getenv("ABC")) { - yosys_abc_executable = std::getenv("ABC"); - } else { - yosys_abc_executable = ABCEXTERNAL; - } -#else - yosys_abc_executable = proc_self_dirname() + proc_program_prefix()+ "yosys-abc"; -#endif -#ifdef _WIN32 -#ifndef ABCEXTERNAL - if (!check_file_exists(yosys_abc_executable + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc.exe")) - yosys_abc_executable = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc"; -#endif -#endif -} - -std::string proc_share_dirname() -{ - if (yosys_share_dirname.empty()) - log_error("init_share_dirname: unable to determine share/ directory!\n"); - return yosys_share_dirname; -} - -std::string proc_program_prefix() -{ - std::string program_prefix; -#ifdef YOSYS_PROGRAM_PREFIX - program_prefix = YOSYS_PROGRAM_PREFIX; -#endif - return program_prefix; -} - -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; - } -} - -bool run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *from_to_label) -{ - if (design == nullptr) - design = yosys_design; - - if (command == "auto") { - std::string filename_trim = filename; - if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".gz") == 0) - filename_trim.erase(filename_trim.size()-3); - if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-2, std::string::npos, ".v") == 0) - command = " -vlog2k"; - else if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".sv") == 0) - command = " -sv"; - else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vhd") == 0) - command = " -vhdl"; - else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".blif") == 0) - command = "blif"; - else if (filename_trim.size() > 5 && filename_trim.compare(filename_trim.size()-6, std::string::npos, ".eblif") == 0) - command = "blif"; - else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".json") == 0) - command = "json"; - else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".il") == 0) - command = "rtlil"; - else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".ys") == 0) - command = "script"; - else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".tcl") == 0) - 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); - design->check(); - } - } - - if (!command.empty()) { - handle_label(command, from_to_active, run_from, run_to); - if (from_to_active) { - Pass::call(design, command); - design->check(); - } - } - } - catch (...) { - Frontend::current_script_file = backup_script_file; - throw; - } - - Frontend::current_script_file = backup_script_file; - - if (filename != "-") - fclose(f); - - return true; - } - - if (command == "tcl") { - Pass::call(design, vector({command, filename})); - return true; - } - - 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[0] == ' ') { - auto argv = split_tokens("read" + command); - argv.push_back(filename); - Pass::call(design, argv); - } else - Frontend::frontend_call(design, NULL, filename, command); - - design->check(); - return false; -} - -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.compare(filename.size()-2, std::string::npos, ".v") == 0) - command = "verilog"; - else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".sv") == 0) - command = "verilog -sv"; - else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0) - command = "rtlil"; - else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".cc") == 0) - command = "cxxrtl"; - else if (filename.size() > 4 && filename.compare(filename.size()-4, std::string::npos, ".aig") == 0) - command = "aiger"; - else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".blif") == 0) - command = "blif"; - else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".edif") == 0) - command = "edif"; - else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".json") == 0) - command = "json"; - else if (filename == "-") - command = "rtlil"; - 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.compare(0, len, text) == 0) - 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 mod : design->modules()) - if (RTLIL::unescape_id(mod->name).compare(0, len, text) == 0) - obj_names.push_back(strdup(log_id(mod->name))); - } - else if (design->module(design->selected_active_module) != nullptr) - { - RTLIL::Module *module = design->module(design->selected_active_module); - - for (auto w : module->wires()) - if (RTLIL::unescape_id(w->name).compare(0, len, text) == 0) - obj_names.push_back(strdup(log_id(w->name))); - - for (auto &it : module->memories) - if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) - obj_names.push_back(strdup(log_id(it.first))); - - for (auto cell : module->cells()) - if (RTLIL::unescape_id(cell->name).compare(0, len, text) == 0) - obj_names.push_back(strdup(log_id(cell->name))); - - for (auto &it : module->processes) - if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) - obj_names.push_back(strdup(log_id(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(); - } - design->check(); - } - 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() 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) 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() 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) 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 file or wire") { } - void help() override { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" script [:]\n"); - log(" script -scriptwire [selection]\n"); - log("\n"); - log("This command executes the yosys commands in the specified file (default\n"); - log("behaviour), or commands embedded in the constant text value connected to the\n"); - log("selected wires.\n"); - log("\n"); - log("In the default (file) case, the 2nd argument can be used to only execute the\n"); - log("section of the file between the specified labels. An empty from label is\n"); - log("synonymous with the beginning of the file and an empty to label is synonymous\n"); - log("with 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"); - log("In \"-scriptwire\" mode, the commands on the selected wire(s) will be executed\n"); - log("in the scope of (and thus, relative to) the wires' owning module(s). This\n"); - log("'-module' mode can be exited by using the 'cd' command.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - bool scriptwire = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-scriptwire") { - scriptwire = true; - continue; - } - break; - } - if (scriptwire) { - extra_args(args, argidx, design); - - for (auto mod : design->selected_modules()) - for (auto &c : mod->connections()) { - if (!c.first.is_wire()) - continue; - auto w = c.first.as_wire(); - if (!mod->selected(w)) - continue; - if (!c.second.is_fully_const()) - log_error("RHS of selected wire %s.%s is not constant.\n", log_id(mod), log_id(w)); - auto v = c.second.as_const(); - Pass::call_on_module(design, mod, v.decode_string()); - } - } - else 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", design, &args[2]); - 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 29415ff842e..00000000000 --- a/yosys/kernel/yosys.h +++ /dev/null @@ -1,384 +0,0 @@ -/* -*- c++ -*- - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 "guidelines/GettingStarted" 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 -#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_Preserve(ClientData data); -extern void Tcl_Release(ClientData clientData); -extern int Tcl_InterpDeleted(Tcl_Interp *interp); -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 -# undef CONST -# undef INLINE -#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 - -// The following defines conflict with our identifiers: -# undef CONST -// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc -# undef TRANSPARENT -#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 defined(__GNUC__) || defined(__clang__) -# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__)) -#elif defined(_MSC_VER) -# define YS_ATTRIBUTE(...) -#else -# define YS_ATTRIBUTE(...) -#endif - -#if defined(__GNUC__) || defined(__clang__) -# define YS_MAYBE_UNUSED __attribute__((__unused__)) -#else -# define YS_MAYBE_UNUSED -#endif - -#if __cplusplus >= 201703L -# define YS_FALLTHROUGH [[fallthrough]]; -#elif defined(__clang__) -# define YS_FALLTHROUGH [[clang::fallthrough]]; -#elif defined(__GNUC__) -# define YS_FALLTHROUGH [[gnu::fallthrough]]; -#else -# define YS_FALLTHROUGH -#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 Memory; - struct Process; - struct Module; - struct Design; - struct Monitor; - enum State : unsigned char; -} - -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 {}; - 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); -#if !defined(YOSYS_DISABLE_SPAWN) -int run_command(const std::string &command, std::function process_line = std::function()); -#endif -std::string get_base_tmpdir(); -std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX"); -std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/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(); } -inline 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); -RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix); - -#define NEW_ID \ - YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__) -#define NEW_ID_SUFFIX(suffix) \ - YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix) - -// Create a statically allocated IdString object, using for example ID::A or ID($add). -// -// Recipe for Converting old code that is using conversion of strings like ID::A and -// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for -// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary. -// -// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' -// -#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \ - static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })() -namespace ID = RTLIL::ID; - -RTLIL::Design *yosys_get_design(); -std::string proc_self_dirname(); -std::string proc_share_dirname(); -std::string proc_program_prefix(); -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); -bool run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr, std::string *from_to_label = 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); - -extern std::string yosys_share_dirname; -extern std::string yosys_abc_executable; - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/kernel/yw.cc b/yosys/kernel/yw.cc deleted file mode 100644 index 73e7710db43..00000000000 --- a/yosys/kernel/yw.cc +++ /dev/null @@ -1,209 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2022 Jannis Harder - * - * 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/yw.h" -#include "libs/json11/json11.hpp" - -USING_YOSYS_NAMESPACE - -// Use the same formatting as witness.py uses -static const char *pretty_name(IdString id) -{ - const char *c_str = id.c_str(); - const char *p = c_str; - - if (*p != '\\') - return c_str; - p++; - - if (*p == '[') { - p++; - while (*p >= '0' && *p <= '9') - p++; - if (p[0] != ']' || p[1] != 0) - return c_str; - return c_str + 1; - } - - if (!(*p >= 'a' && *p <= 'z') && !(*p >= 'A' && *p <= 'Z') && *p != '_') - return c_str; - p++; - while ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '_') - p++; - - if (*p != 0) - return c_str; - return c_str + 1; -} - -std::string IdPath::str() const -{ - std::string result; - - for (auto &item : *this) { - const char *pretty = pretty_name(item); - if (pretty[0] == '[') { - result += pretty; - continue; - } - if (!result.empty()) - result += '.'; - result += pretty; - if (pretty[0] == '\\' || pretty[0] == '$') - result += ' '; - } - - return result; -} - -bool IdPath::get_address(int &addr) const -{ - if (empty()) - return false; - auto &last = back(); - if (!last.begins_with("\\[")) - return false; - if (last == "\\[0]") { - addr = 0; - return true; - } - char first = last.c_str()[2]; - if (first < '1' || first > '9') - return false; - char *endptr; - addr = std::strtol(last.c_str() + 2, &endptr, 10); - return endptr[0] == ']' && endptr[1] == 0; -} - -static std::vector get_path(const json11::Json &json) -{ - std::vector result; - for (auto &path_item : json.array_items()) { - auto const &path_item_str = path_item.string_value(); - if (path_item_str.empty()) - return {};; - result.push_back(path_item_str); - } - return result; -} - -ReadWitness::ReadWitness(const std::string &filename) : - filename(filename) -{ - std::ifstream f(filename.c_str()); - if (f.fail() || GetSize(filename) == 0) - log_error("Cannot open file `%s`\n", filename.c_str()); - std::stringstream buf; - buf << f.rdbuf(); - std::string err; - json11::Json json = json11::Json::parse(buf.str(), err); - if (!err.empty()) - log_error("Failed to parse `%s`: %s\n", filename.c_str(), err.c_str()); - - std::string format = json["format"].string_value(); - - if (format.empty()) - log_error("Failed to parse `%s`: Unknown format\n", filename.c_str()); - if (format != "Yosys Witness Trace") - log_error("Failed to parse `%s`: Unsupported format `%s`\n", filename.c_str(), format.c_str()); - - for (auto &clock_json : json["clocks"].array_items()) { - Clock clock; - clock.path = get_path(clock_json["path"]); - if (clock.path.empty()) - log_error("Failed to parse `%s`: Missing path for clock `%s`\n", filename.c_str(), clock_json.dump().c_str()); - auto edge_str = clock_json["edge"]; - if (edge_str.string_value() == "posedge") - clock.is_posedge = true; - else if (edge_str.string_value() == "negedge") - clock.is_negedge = true; - else - log_error("Failed to parse `%s`: Unknown edge type for clock `%s`\n", filename.c_str(), clock_json.dump().c_str()); - if (!clock_json["offset"].is_number()) - log_error("Failed to parse `%s`: Unknown offset for clock `%s`\n", filename.c_str(), clock_json.dump().c_str()); - clock.offset = clock_json["offset"].int_value(); - if (clock.offset < 0) - log_error("Failed to parse `%s`: Invalid offset for clock `%s`\n", filename.c_str(), clock_json.dump().c_str()); - clocks.push_back(clock); - } - - int bits_offset = 0; - for (auto &signal_json : json["signals"].array_items()) { - Signal signal; - signal.bits_offset = bits_offset; - signal.path = get_path(signal_json["path"]); - if (signal.path.empty()) - log_error("Failed to parse `%s`: Missing path for signal `%s`\n", filename.c_str(), signal_json.dump().c_str()); - if (!signal_json["width"].is_number()) - log_error("Failed to parse `%s`: Unknown width for signal `%s`\n", filename.c_str(), signal_json.dump().c_str()); - signal.width = signal_json["width"].int_value(); - if (signal.width < 0) - log_error("Failed to parse `%s`: Invalid width for signal `%s`\n", filename.c_str(), signal_json.dump().c_str()); - bits_offset += signal.width; - if (!signal_json["offset"].is_number()) - log_error("Failed to parse `%s`: Unknown offset for signal `%s`\n", filename.c_str(), signal_json.dump().c_str()); - signal.offset = signal_json["offset"].int_value(); - if (signal.offset < 0) - log_error("Failed to parse `%s`: Invalid offset for signal `%s`\n", filename.c_str(), signal_json.dump().c_str()); - signal.init_only = signal_json["init_only"].bool_value(); - signals.push_back(signal); - } - - for (auto &step_json : json["steps"].array_items()) { - Step step; - if (!step_json["bits"].is_string()) - log_error("Failed to parse `%s`: Expected string as bits value for step %d\n", filename.c_str(), GetSize(steps)); - step.bits = step_json["bits"].string_value(); - for (char c : step.bits) { - if (c != '0' && c != '1' && c != 'x' && c != '?') - log_error("Failed to parse `%s`: Invalid bit '%c' value for step %d\n", filename.c_str(), c, GetSize(steps)); - } - steps.push_back(step); - } -} - -RTLIL::Const ReadWitness::get_bits(int t, int bits_offset, int width) const -{ - log_assert(t >= 0 && t < GetSize(steps)); - - const std::string &bits = steps[t].bits; - - RTLIL::Const result(State::Sa, width); - result.bits.reserve(width); - - int read_begin = GetSize(bits) - 1 - bits_offset; - int read_end = max(-1, read_begin - width); - - min(width, GetSize(bits) - bits_offset); - - for (int i = read_begin, j = 0; i > read_end; i--, j++) { - RTLIL::State bit = State::Sa; - switch (bits[i]) { - case '0': bit = State::S0; break; - case '1': bit = State::S1; break; - case 'x': bit = State::Sx; break; - case '?': bit = State::Sa; break; - default: - log_abort(); - } - result.bits[j] = bit; - } - - return result; -} diff --git a/yosys/kernel/yw.h b/yosys/kernel/yw.h deleted file mode 100644 index c2f5921b1d9..00000000000 --- a/yosys/kernel/yw.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2022 Jannis Harder - * - * 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 YW_H -#define YW_H - -#include "kernel/yosys.h" -#include "kernel/mem.h" - -YOSYS_NAMESPACE_BEGIN - -struct IdPath : public std::vector -{ - template - IdPath(T&&... args) : std::vector(std::forward(args)...) { } - IdPath prefix() const { return {begin(), end() - !empty()}; } - std::string str() const; - - bool has_address() const { int tmp; return get_address(tmp); }; - bool get_address(int &addr) const; - - int hash() const { return hashlib::hash_ops>::hash(*this); } -}; - -struct WitnessHierarchyItem { - RTLIL::Module *module; - RTLIL::Wire *wire = nullptr; - RTLIL::Cell *cell = nullptr; - Mem *mem = nullptr; - - WitnessHierarchyItem(RTLIL::Module *module, RTLIL::Wire *wire) : module(module), wire(wire) {} - WitnessHierarchyItem(RTLIL::Module *module, RTLIL::Cell *cell) : module(module), cell(cell) {} - WitnessHierarchyItem(RTLIL::Module *module, Mem *mem) : module(module), mem(mem) {} -}; - -template -void witness_hierarchy(RTLIL::Module *module, D data, T callback); - -template static std::vector witness_path(T *obj) { - std::vector path; - if (obj->name.isPublic()) { - auto hdlname = obj->get_string_attribute(ID::hdlname); - for (auto token : split_tokens(hdlname)) - path.push_back("\\" + token); - } - if (path.empty()) - path.push_back(obj->name.str()); - return path; -} - -struct ReadWitness -{ - struct Clock { - IdPath path; - int offset; - bool is_posedge = false; - bool is_negedge = false; - }; - - struct Signal { - IdPath path; - int offset; - int width; - bool init_only; - - int bits_offset; - }; - - struct Step { - std::string bits; - }; - - std::string filename; - std::vector clocks; - std::vector signals; - std::vector steps; - - ReadWitness(const std::string &filename); - - RTLIL::Const get_bits(int t, int bits_offset, int width) const; -}; - -template -void witness_hierarchy_recursion(IdPath &path, int hdlname_mode, RTLIL::Module *module, D data, T &callback) -{ - auto const &const_path = path; - size_t path_size = path.size(); - for (auto wire : module->wires()) - { - auto hdlname = hdlname_mode < 0 ? std::vector() : wire->get_hdlname_attribute(); - for (auto item : hdlname) - path.push_back("\\" + item); - if (hdlname.size() == 1 && path.back() == wire->name) - hdlname.clear(); - if (!hdlname.empty()) - callback(const_path, WitnessHierarchyItem(module, wire), data); - path.resize(path_size); - if (hdlname.empty() || hdlname_mode <= 0) { - path.push_back(wire->name); - callback(const_path, WitnessHierarchyItem(module, wire), data); - path.pop_back(); - } - } - - for (auto cell : module->cells()) - { - Module *child = module->design->module(cell->type); - if (child == nullptr) - continue; - - auto hdlname = hdlname_mode < 0 ? std::vector() : cell->get_hdlname_attribute(); - for (auto item : hdlname) - path.push_back("\\" + item); - if (hdlname.size() == 1 && path.back() == cell->name) - hdlname.clear(); - if (!hdlname.empty()) { - D child_data = callback(const_path, WitnessHierarchyItem(module, cell), data); - witness_hierarchy_recursion(path, 1, child, child_data, callback); - } - path.resize(path_size); - if (hdlname.empty() || hdlname_mode <= 0) { - path.push_back(cell->name); - D child_data = callback(const_path, WitnessHierarchyItem(module, cell), data); - witness_hierarchy_recursion(path, hdlname.empty() ? hdlname_mode : -1, child, child_data, callback); - path.pop_back(); - } - } - - for (auto mem : Mem::get_all_memories(module)) { - std::vector hdlname; - - if (hdlname_mode >= 0 && mem.cell != nullptr) - hdlname = mem.cell->get_hdlname_attribute(); - for (auto item : hdlname) - path.push_back("\\" + item); - if (hdlname.size() == 1 && path.back() == mem.cell->name) - hdlname.clear(); - if (!hdlname.empty()) { - callback(const_path, WitnessHierarchyItem(module, &mem), data); - } - path.resize(path_size); - - if (hdlname.empty() || hdlname_mode <= 0) { - path.push_back(mem.memid); - callback(const_path, WitnessHierarchyItem(module, &mem), data); - path.pop_back(); - - if (mem.cell != nullptr && mem.cell->name != mem.memid) { - path.push_back(mem.cell->name); - callback(const_path, WitnessHierarchyItem(module, &mem), data); - path.pop_back(); - } - } - } -} - -template -void witness_hierarchy(RTLIL::Module *module, D data, T callback) -{ - IdPath path; - witness_hierarchy_recursion(path, 0, module, data, callback); -} - -YOSYS_NAMESPACE_END - -#endif diff --git a/yosys/libs/bigint/.gitignore b/yosys/libs/bigint/.gitignore deleted file mode 100644 index 4467edcf586..00000000000 --- 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 3b23aa1e7b2..00000000000 --- 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 cf6e91056f4..00000000000 --- 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 7edebda76a8..00000000000 --- 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 b1dd9432274..00000000000 --- 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 2a0ebee6a11..00000000000 --- 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 44073af6527..00000000000 --- 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 c815b5d7c52..00000000000 --- 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 d7f9889cc69..00000000000 --- 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 9228753c89f..00000000000 --- 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 999faaf2db0..00000000000 --- 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 0ea89c6ef24..00000000000 --- 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 ac6927c4094..00000000000 --- 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 3018e98e6fd..00000000000 --- 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 53c8e5be8f5..00000000000 --- 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 c6e9bdba617..00000000000 --- a/yosys/libs/bigint/README +++ /dev/null @@ -1,81 +0,0 @@ - -Note by Claire 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 ff737291641..00000000000 --- 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 62b41df3271..00000000000 --- 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 7cb9768e645..00000000000 --- 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/dlfcn-win32/dlfcn.cc b/yosys/libs/dlfcn-win32/dlfcn.cc deleted file mode 100644 index 03ed34dbaa4..00000000000 --- a/yosys/libs/dlfcn-win32/dlfcn.cc +++ /dev/null @@ -1,820 +0,0 @@ -/* - * dlfcn-win32 - * Copyright (c) 2007 Ramiro Polla - * Copyright (c) 2015 Tiancheng "Timothy" Gu - * Copyright (c) 2019 Pali Rohár - * Copyright (c) 2020 Ralf Habacker - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifdef _DEBUG -#define _CRTDBG_MAP_ALLOC -#include -#include -#endif -#include -#include -#include - -/* Older versions do not have this type */ -#if _WIN32_WINNT < 0x0500 -typedef ULONG ULONG_PTR; -#endif - -/* Older SDK versions do not have these macros */ -#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS -#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x4 -#endif -#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT -#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x2 -#endif - -#ifdef _MSC_VER -/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */ -#pragma intrinsic( _ReturnAddress ) -#else -/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */ -#ifndef _ReturnAddress -#define _ReturnAddress( ) ( __builtin_extract_return_addr( __builtin_return_address( 0 ) ) ) -#endif -#endif - -#ifdef DLFCN_WIN32_SHARED -#define DLFCN_WIN32_EXPORTS -#endif -#include "dlfcn.h" - -#if defined( _MSC_VER ) && _MSC_VER >= 1300 -/* https://docs.microsoft.com/en-us/cpp/cpp/noinline */ -#define DLFCN_NOINLINE __declspec( noinline ) -#elif defined( __GNUC__ ) && ( ( __GNUC__ > 3 ) || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) ) -/* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */ -#define DLFCN_NOINLINE __attribute__(( noinline )) -#else -#define DLFCN_NOINLINE -#endif - -/* Note: - * MSDN says these functions are not thread-safe. We make no efforts to have - * any kind of thread safety. - */ - -typedef struct local_object { - HMODULE hModule; - struct local_object *previous; - struct local_object *next; -} local_object; - -static local_object first_object; - -/* These functions implement a double linked list for the local objects. */ -static local_object *local_search( HMODULE hModule ) -{ - local_object *pobject; - - if( hModule == NULL ) - return NULL; - - for( pobject = &first_object; pobject; pobject = pobject->next ) - if( pobject->hModule == hModule ) - return pobject; - - return NULL; -} - -static BOOL local_add( HMODULE hModule ) -{ - local_object *pobject; - local_object *nobject; - - if( hModule == NULL ) - return TRUE; - - pobject = local_search( hModule ); - - /* Do not add object again if it's already on the list */ - if( pobject != NULL ) - return TRUE; - - for( pobject = &first_object; pobject->next; pobject = pobject->next ); - - nobject = (local_object *) malloc( sizeof( local_object ) ); - - if( !nobject ) - return FALSE; - - pobject->next = nobject; - nobject->next = NULL; - nobject->previous = pobject; - nobject->hModule = hModule; - - return TRUE; -} - -static void local_rem( HMODULE hModule ) -{ - local_object *pobject; - - if( hModule == NULL ) - return; - - pobject = local_search( hModule ); - - if( pobject == NULL ) - return; - - if( pobject->next ) - pobject->next->previous = pobject->previous; - if( pobject->previous ) - pobject->previous->next = pobject->next; - - free( pobject ); -} - -/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one - * static buffer. - * MSDN says the buffer cannot be larger than 64K bytes, so we set it to - * the limit. - */ -static char error_buffer[65535]; -static BOOL error_occurred; - -static void save_err_str( const char *str, DWORD dwMessageId ) -{ - DWORD ret; - size_t pos, len; - - len = strlen( str ); - if( len > sizeof( error_buffer ) - 5 ) - len = sizeof( error_buffer ) - 5; - - /* Format error message to: - * "": - */ - pos = 0; - error_buffer[pos++] = '"'; - memcpy( error_buffer + pos, str, len ); - pos += len; - error_buffer[pos++] = '"'; - error_buffer[pos++] = ':'; - error_buffer[pos++] = ' '; - - ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId, - MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), - error_buffer + pos, (DWORD) ( sizeof( error_buffer ) - pos ), NULL ); - pos += ret; - - /* When FormatMessageA() fails it returns zero and does not touch buffer - * so add trailing null byte */ - if( ret == 0 ) - error_buffer[pos] = '\0'; - - if( pos > 1 ) - { - /* POSIX says the string must not have trailing */ - if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' ) - error_buffer[pos-2] = '\0'; - } - - error_occurred = TRUE; -} - -static void save_err_ptr_str( const void *ptr, DWORD dwMessageId ) -{ - char ptr_buf[2 + 2 * sizeof( ptr ) + 1]; - char num; - size_t i; - - ptr_buf[0] = '0'; - ptr_buf[1] = 'x'; - - for( i = 0; i < 2 * sizeof( ptr ); i++ ) - { - num = (char) ( ( ( (ULONG_PTR) ptr ) >> ( 8 * sizeof( ptr ) - 4 * ( i + 1 ) ) ) & 0xF ); - ptr_buf[2 + i] = num + ( ( num < 0xA ) ? '0' : ( 'A' - 0xA ) ); - } - - ptr_buf[2 + 2 * sizeof( ptr )] = 0; - - save_err_str( ptr_buf, dwMessageId ); -} - -static UINT MySetErrorMode( UINT uMode ) -{ - static BOOL (WINAPI *SetThreadErrorModePtr)(DWORD, DWORD *) = NULL; - static BOOL failed = FALSE; - HMODULE kernel32; - DWORD oldMode; - - if( !failed && SetThreadErrorModePtr == NULL ) - { - kernel32 = GetModuleHandleA( "Kernel32.dll" ); - if( kernel32 != NULL ) - SetThreadErrorModePtr = (BOOL (WINAPI *)(DWORD, DWORD *)) (LPVOID) GetProcAddress( kernel32, "SetThreadErrorMode" ); - if( SetThreadErrorModePtr == NULL ) - failed = TRUE; - } - - if( !failed ) - { - if( !SetThreadErrorModePtr( uMode, &oldMode ) ) - return 0; - else - return oldMode; - } - else - { - return SetErrorMode( uMode ); - } -} - -static HMODULE MyGetModuleHandleFromAddress( const void *addr ) -{ - static BOOL (WINAPI *GetModuleHandleExAPtr)(DWORD, LPCSTR, HMODULE *) = NULL; - static BOOL failed = FALSE; - HMODULE kernel32; - HMODULE hModule; - MEMORY_BASIC_INFORMATION info; - SIZE_T sLen; - - if( !failed && GetModuleHandleExAPtr == NULL ) - { - kernel32 = GetModuleHandleA( "Kernel32.dll" ); - if( kernel32 != NULL ) - GetModuleHandleExAPtr = (BOOL (WINAPI *)(DWORD, LPCSTR, HMODULE *)) (LPVOID) GetProcAddress( kernel32, "GetModuleHandleExA" ); - if( GetModuleHandleExAPtr == NULL ) - failed = TRUE; - } - - if( !failed ) - { - /* If GetModuleHandleExA is available use it with GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS */ - if( !GetModuleHandleExAPtr( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (const char *)addr, &hModule ) ) - return NULL; - } - else - { - /* To get HMODULE from address use undocumented hack from https://stackoverflow.com/a/2396380 - * The HMODULE of a DLL is the same value as the module's base address. - */ - sLen = VirtualQuery( addr, &info, sizeof( info ) ); - if( sLen != sizeof( info ) ) - return NULL; - hModule = (HMODULE) info.AllocationBase; - } - - return hModule; -} - -/* Load Psapi.dll at runtime, this avoids linking caveat */ -static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) -{ - static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD) = NULL; - static BOOL failed = FALSE; - UINT uMode; - HMODULE psapi; - - if( failed ) - return FALSE; - - if( EnumProcessModulesPtr == NULL ) - { - /* Windows 7 and newer versions have K32EnumProcessModules in Kernel32.dll which is always pre-loaded */ - psapi = GetModuleHandleA( "Kernel32.dll" ); - if( psapi != NULL ) - EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "K32EnumProcessModules" ); - - /* Windows Vista and older version have EnumProcessModules in Psapi.dll which needs to be loaded */ - if( EnumProcessModulesPtr == NULL ) - { - /* Do not let Windows display the critical-error-handler message box */ - uMode = MySetErrorMode( SEM_FAILCRITICALERRORS ); - psapi = LoadLibraryA( "Psapi.dll" ); - if( psapi != NULL ) - { - EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) (LPVOID) GetProcAddress( psapi, "EnumProcessModules" ); - if( EnumProcessModulesPtr == NULL ) - FreeLibrary( psapi ); - } - MySetErrorMode( uMode ); - } - - if( EnumProcessModulesPtr == NULL ) - { - failed = TRUE; - return FALSE; - } - } - - return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); -} - -DLFCN_EXPORT -void *dlopen( const char *file, int mode ) -{ - HMODULE hModule; - UINT uMode; - - error_occurred = FALSE; - - /* Do not let Windows display the critical-error-handler message box */ - uMode = MySetErrorMode( SEM_FAILCRITICALERRORS ); - - if( file == NULL ) - { - /* POSIX says that if the value of file is NULL, a handle on a global - * symbol object must be provided. That object must be able to access - * all symbols from the original program file, and any objects loaded - * with the RTLD_GLOBAL flag. - * The return value from GetModuleHandle( ) allows us to retrieve - * symbols only from the original program file. EnumProcessModules() is - * used to access symbols from other libraries. For objects loaded - * with the RTLD_LOCAL flag, we create our own list later on. They are - * excluded from EnumProcessModules() iteration. - */ - hModule = GetModuleHandle( NULL ); - - if( !hModule ) - save_err_str( "(null)", GetLastError( ) ); - } - else - { - HANDLE hCurrentProc; - DWORD dwProcModsBefore, dwProcModsAfter; - char lpFileName[MAX_PATH]; - size_t i, len; - - len = strlen( file ); - - if( len >= sizeof( lpFileName ) ) - { - save_err_str( file, ERROR_FILENAME_EXCED_RANGE ); - hModule = NULL; - } - else - { - /* MSDN says backslashes *must* be used instead of forward slashes. */ - for( i = 0; i < len; i++ ) - { - if( file[i] == '/' ) - lpFileName[i] = '\\'; - else - lpFileName[i] = file[i]; - } - lpFileName[len] = '\0'; - - hCurrentProc = GetCurrentProcess( ); - - if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 ) - dwProcModsBefore = 0; - - /* POSIX says the search path is implementation-defined. - * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely - * to UNIX's search paths (start with system folders instead of current - * folder). - */ - hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); - - if( !hModule ) - { - save_err_str( lpFileName, GetLastError( ) ); - } - else - { - if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) - dwProcModsAfter = 0; - - /* If the object was loaded with RTLD_LOCAL, add it to list of local - * objects, so that its symbols cannot be retrieved even if the handle for - * the original program file is passed. POSIX says that if the same - * file is specified in multiple invocations, and any of them are - * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the - * symbols will remain global. If number of loaded modules was not - * changed after calling LoadLibraryEx(), it means that library was - * already loaded. - */ - if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter ) - { - if( !local_add( hModule ) ) - { - save_err_str( lpFileName, ERROR_NOT_ENOUGH_MEMORY ); - FreeLibrary( hModule ); - hModule = NULL; - } - } - else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter ) - { - local_rem( hModule ); - } - } - } - } - - /* Return to previous state of the error-mode bit flags. */ - MySetErrorMode( uMode ); - - return (void *) hModule; -} - -DLFCN_EXPORT -int dlclose( void *handle ) -{ - HMODULE hModule = (HMODULE) handle; - BOOL ret; - - error_occurred = FALSE; - - ret = FreeLibrary( hModule ); - - /* If the object was loaded with RTLD_LOCAL, remove it from list of local - * objects. - */ - if( ret ) - local_rem( hModule ); - else - save_err_ptr_str( handle, GetLastError( ) ); - - /* dlclose's return value in inverted in relation to FreeLibrary's. */ - ret = !ret; - - return (int) ret; -} - -DLFCN_NOINLINE /* Needed for _ReturnAddress() */ -DLFCN_EXPORT -void *dlsym( void *handle, const char *name ) -{ - FARPROC symbol; - HMODULE hCaller; - HMODULE hModule; - DWORD dwMessageId; - - error_occurred = FALSE; - - symbol = NULL; - hCaller = NULL; - hModule = GetModuleHandle( NULL ); - dwMessageId = 0; - - if( handle == RTLD_DEFAULT ) - { - /* The symbol lookup happens in the normal global scope; that is, - * a search for a symbol using this handle would find the same - * definition as a direct use of this symbol in the program code. - * So use same lookup procedure as when filename is NULL. - */ - handle = hModule; - } - else if( handle == RTLD_NEXT ) - { - /* Specifies the next object after this one that defines name. - * This one refers to the object containing the invocation of dlsym(). - * The next object is the one found upon the application of a load - * order symbol resolution algorithm. To get caller function of dlsym() - * use _ReturnAddress() intrinsic. To get HMODULE of caller function - * use MyGetModuleHandleFromAddress() which calls either standard - * GetModuleHandleExA() function or hack via VirtualQuery(). - */ - hCaller = MyGetModuleHandleFromAddress( _ReturnAddress( ) ); - - if( hCaller == NULL ) - { - dwMessageId = ERROR_INVALID_PARAMETER; - goto end; - } - } - - if( handle != RTLD_NEXT ) - { - symbol = GetProcAddress( (HMODULE) handle, name ); - - if( symbol != NULL ) - goto end; - } - - /* If the handle for the original program file is passed, also search - * in all globally loaded objects. - */ - - if( hModule == handle || handle == RTLD_NEXT ) - { - HANDLE hCurrentProc; - HMODULE *modules; - DWORD cbNeeded; - DWORD dwSize; - size_t i; - - hCurrentProc = GetCurrentProcess( ); - - /* GetModuleHandle( NULL ) only returns the current program file. So - * if we want to get ALL loaded module including those in linked DLLs, - * we have to use EnumProcessModules( ). - */ - if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 ) - { - modules = (HMODULE *)malloc( dwSize ); - if( modules ) - { - if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded ) - { - for( i = 0; i < dwSize / sizeof( HMODULE ); i++ ) - { - if( handle == RTLD_NEXT && hCaller ) - { - /* Next modules can be used for RTLD_NEXT */ - if( hCaller == modules[i] ) - hCaller = NULL; - continue; - } - if( local_search( modules[i] ) ) - continue; - symbol = GetProcAddress( modules[i], name ); - if( symbol != NULL ) - { - free( modules ); - goto end; - } - } - - } - free( modules ); - } - else - { - dwMessageId = ERROR_NOT_ENOUGH_MEMORY; - goto end; - } - } - } - -end: - if( symbol == NULL ) - { - if( !dwMessageId ) - dwMessageId = ERROR_PROC_NOT_FOUND; - save_err_str( name, dwMessageId ); - } - - return *(void **) (&symbol); -} - -DLFCN_EXPORT -char *dlerror( void ) -{ - /* If this is the second consecutive call to dlerror, return NULL */ - if( !error_occurred ) - return NULL; - - /* POSIX says that invoking dlerror( ) a second time, immediately following - * a prior invocation, shall result in NULL being returned. - */ - error_occurred = FALSE; - - return error_buffer; -} - -/* See https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2 - * for details */ - -/* Get specific image section */ -static BOOL get_image_section( HMODULE module, int index, void **ptr, DWORD *size ) -{ - IMAGE_DOS_HEADER *dosHeader; - IMAGE_NT_HEADERS *ntHeaders; - IMAGE_OPTIONAL_HEADER *optionalHeader; - - dosHeader = (IMAGE_DOS_HEADER *) module; - - if( dosHeader->e_magic != IMAGE_DOS_SIGNATURE ) - return FALSE; - - ntHeaders = (IMAGE_NT_HEADERS *) ( (BYTE *) dosHeader + dosHeader->e_lfanew ); - - if( ntHeaders->Signature != IMAGE_NT_SIGNATURE ) - return FALSE; - - optionalHeader = &ntHeaders->OptionalHeader; - - if( optionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC ) - return FALSE; - - if( index < 0 || index > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ) - return FALSE; - - if( optionalHeader->DataDirectory[index].Size == 0 || optionalHeader->DataDirectory[index].VirtualAddress == 0 ) - return FALSE; - - if( size != NULL ) - *size = optionalHeader->DataDirectory[index].Size; - - *ptr = (void *)( (BYTE *) module + optionalHeader->DataDirectory[index].VirtualAddress ); - - return TRUE; -} - -/* Return symbol name for a given address from export table */ -static const char *get_export_symbol_name( HMODULE module, IMAGE_EXPORT_DIRECTORY *ied, const void *addr, void **func_address ) -{ - DWORD i; - void *candidateAddr = NULL; - int candidateIndex = -1; - BYTE *base = (BYTE *) module; - DWORD *functionAddressesOffsets = (DWORD *) (base + ied->AddressOfFunctions); - DWORD *functionNamesOffsets = (DWORD *) (base + ied->AddressOfNames); - USHORT *functionNameOrdinalsIndexes = (USHORT *) (base + ied->AddressOfNameOrdinals); - - for( i = 0; i < ied->NumberOfFunctions; i++ ) - { - if( (void *) ( base + functionAddressesOffsets[i] ) > addr || candidateAddr >= (void *) ( base + functionAddressesOffsets[i] ) ) - continue; - - candidateAddr = (void *) ( base + functionAddressesOffsets[i] ); - candidateIndex = i; - } - - if( candidateIndex == -1 ) - return NULL; - - *func_address = candidateAddr; - - for( i = 0; i < ied->NumberOfNames; i++ ) - { - if( functionNameOrdinalsIndexes[i] == candidateIndex ) - return (const char *) ( base + functionNamesOffsets[i] ); - } - - return NULL; -} - -static BOOL is_valid_address( const void *addr ) -{ - MEMORY_BASIC_INFORMATION info; - SIZE_T result; - - if( addr == NULL ) - return FALSE; - - /* check valid pointer */ - result = VirtualQuery( addr, &info, sizeof( info ) ); - - if( result == 0 || info.AllocationBase == NULL || info.AllocationProtect == 0 || info.AllocationProtect == PAGE_NOACCESS ) - return FALSE; - - return TRUE; -} - -/* Return state if address points to an import thunk - * - * An import thunk is setup with a 'jmp' instruction followed by an - * absolute address (32bit) or relative offset (64bit) pointing into - * the import address table (iat), which is partially maintained by - * the runtime linker. - */ -static BOOL is_import_thunk( const void *addr ) -{ - return *(short *) addr == 0x25ff ? TRUE : FALSE; -} - -/* Return adress from the import address table (iat), - * if the original address points to a thunk table entry. - */ -static void *get_address_from_import_address_table( void *iat, DWORD iat_size, const void *addr ) -{ - BYTE *thkp = (BYTE *) addr; - /* Get offset from thunk table (after instruction 0xff 0x25) - * 4018c8 <_VirtualQuery>: ff 25 4a 8a 00 00 - */ - ULONG offset = *(ULONG *)( thkp + 2 ); -#ifdef _WIN64 - /* On 64 bit the offset is relative - * 4018c8: ff 25 4a 8a 00 00 jmpq *0x8a4a(%rip) # 40a318 <__imp_VirtualQuery> - * And can be also negative (MSVC in WDK) - * 100002f20: ff 25 3a e1 ff ff jmpq *-0x1ec6(%rip) # 0x100001060 - * So cast to signed LONG type - */ - BYTE *ptr = (BYTE *)( thkp + 6 + (LONG) offset ); -#else - /* On 32 bit the offset is absolute - * 4019b4: ff 25 90 71 40 00 jmp *0x40719 - */ - BYTE *ptr = (BYTE *) offset; -#endif - - if( !is_valid_address( ptr ) || ptr < (BYTE *) iat || ptr > (BYTE *) iat + iat_size ) - return NULL; - - return *(void **) ptr; -} - -/* Holds module filename */ -static char module_filename[2*MAX_PATH]; - -static BOOL fill_info( const void *addr, Dl_info *info ) -{ - HMODULE hModule; - DWORD dwSize; - IMAGE_EXPORT_DIRECTORY *ied; - void *funcAddress = NULL; - - /* Get module of the specified address */ - hModule = MyGetModuleHandleFromAddress( addr ); - - if( hModule == NULL ) - return FALSE; - - dwSize = GetModuleFileNameA( hModule, module_filename, sizeof( module_filename ) ); - - if( dwSize == 0 || dwSize == sizeof( module_filename ) ) - return FALSE; - - info->dli_fname = module_filename; - info->dli_fbase = (void *) hModule; - - /* Find function name and function address in module's export table */ - if( get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_EXPORT, (void **) &ied, NULL ) ) - info->dli_sname = get_export_symbol_name( hModule, ied, addr, &funcAddress ); - else - info->dli_sname = NULL; - - info->dli_saddr = info->dli_sname == NULL ? NULL : funcAddress != NULL ? funcAddress : (void *) addr; - - return TRUE; -} - -DLFCN_EXPORT -int dladdr( const void *addr, Dl_info *info ) -{ - if( info == NULL ) - return 0; - - if( !is_valid_address( addr ) ) - return 0; - - if( is_import_thunk( addr ) ) - { - void *iat; - DWORD iatSize; - HMODULE hModule; - - /* Get module of the import thunk address */ - hModule = MyGetModuleHandleFromAddress( addr ); - - if( hModule == NULL ) - return 0; - - if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IAT, &iat, &iatSize ) ) - { - /* Fallback for cases where the iat is not defined, - * for example i586-mingw32msvc-gcc */ - IMAGE_IMPORT_DESCRIPTOR *iid; - DWORD iidSize; - - if( !get_image_section( hModule, IMAGE_DIRECTORY_ENTRY_IMPORT, (void **) &iid, &iidSize ) ) - return 0; - - if( iid == NULL || iid->Characteristics == 0 || iid->FirstThunk == 0 ) - return 0; - - iat = (void *)( (BYTE *) hModule + iid->FirstThunk ); - /* We assume that in this case iid and iat's are in linear order */ - iatSize = iidSize - (DWORD) ( (BYTE *) iat - (BYTE *) iid ); - } - - addr = get_address_from_import_address_table( iat, iatSize, addr ); - - if( !is_valid_address( addr ) ) - return 0; - } - - if( !fill_info( addr, info ) ) - return 0; - - return 1; -} - -#ifdef DLFCN_WIN32_SHARED -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) -{ - (void) hinstDLL; - (void) fdwReason; - (void) lpvReserved; - return TRUE; -} -#endif diff --git a/yosys/libs/dlfcn-win32/dlfcn.h b/yosys/libs/dlfcn-win32/dlfcn.h deleted file mode 100644 index 6e8518a6f51..00000000000 --- a/yosys/libs/dlfcn-win32/dlfcn.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * dlfcn-win32 - * Copyright (c) 2007 Ramiro Polla - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef DLFCN_H -#define DLFCN_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(DLFCN_WIN32_SHARED) -#if defined(DLFCN_WIN32_EXPORTS) -# define DLFCN_EXPORT __declspec(dllexport) -#else -# define DLFCN_EXPORT __declspec(dllimport) -#endif -#else -# define DLFCN_EXPORT -#endif - -/* Relocations are performed when the object is loaded. */ -#define RTLD_NOW 0 - -/* Relocations are performed at an implementation-defined time. - * Windows API does not support lazy symbol resolving (when first reference - * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW. - */ -#define RTLD_LAZY RTLD_NOW - -/* All symbols are available for relocation processing of other modules. */ -#define RTLD_GLOBAL (1 << 1) - -/* All symbols are not made available for relocation processing by other modules. */ -#define RTLD_LOCAL (1 << 2) - -/* These two were added in The Open Group Base Specifications Issue 6. - * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant. - */ - -/* The symbol lookup happens in the normal global scope. */ -#define RTLD_DEFAULT ((void *)0) - -/* Specifies the next object after this one that defines name. */ -#define RTLD_NEXT ((void *)-1) - -/* Structure filled in by dladdr() */ -typedef struct dl_info -{ - const char *dli_fname; /* Filename of defining object (thread unsafe and reused on every call to dladdr) */ - void *dli_fbase; /* Load address of that object */ - const char *dli_sname; /* Name of nearest lower symbol */ - void *dli_saddr; /* Exact value of nearest symbol */ -} Dl_info; - -/* Open a symbol table handle. */ -DLFCN_EXPORT void *dlopen(const char *file, int mode); - -/* Close a symbol table handle. */ -DLFCN_EXPORT int dlclose(void *handle); - -/* Get the address of a symbol from a symbol table handle. */ -DLFCN_EXPORT void *dlsym(void *handle, const char *name); - -/* Get diagnostic information. */ -DLFCN_EXPORT char *dlerror(void); - -/* Translate address to symbolic information (no POSIX standard) */ -DLFCN_EXPORT int dladdr(const void *addr, Dl_info *info); - -#ifdef __cplusplus -} -#endif - -#endif /* DLFCN_H */ diff --git a/yosys/libs/ezsat/.gitignore b/yosys/libs/ezsat/.gitignore deleted file mode 100644 index e079bd0964a..00000000000 --- 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 b1f86416093..00000000000 --- 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 db0a18a4e22..00000000000 --- 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 Claire Xenia 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 b4b68970181..00000000000 --- 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 Claire Xenia 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 7b927c66402..00000000000 --- 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 Claire Xenia 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 a13430d5570..00000000000 --- 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 Claire Xenia 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 30df625cbb7..00000000000 --- a/yosys/libs/ezsat/ezminisat.cc +++ /dev/null @@ -1,248 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Claire Xenia 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 - -#if !defined(_WIN32) && !defined(__wasm) -# include -# include -# define HAS_ALARM -#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 - -#if defined(HAS_ALARM) -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 - } - -#if defined(HAS_ALARM) - 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); - -#if defined(HAS_ALARM) - 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 92a91d744a2..00000000000 --- 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 Claire Xenia 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 3b089ccca9d..00000000000 --- a/yosys/libs/ezsat/ezsat.cc +++ /dev/null @@ -1,1581 +0,0 @@ -/* - * ezSAT -- A simple and easy to use CNF generator for SAT solvers - * - * Copyright (C) 2013 Claire Xenia 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)); - - if (vec.size() < 8) - { - // fall-back to simple O(n^2) solution for small cases - for (size_t i = 0; i < vec.size(); i++) - for (size_t j = i+1; j < vec.size(); j++) { - std::vector clause; - clause.push_back(NOT(vec[i])); - clause.push_back(NOT(vec[j])); - formula.push_back(expression(OpOr, clause)); - } - } - else - { - // 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); -} - -#if 0 -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); -} -#else -static std::vector lfsr_sym(ezSAT *that, const std::vector &vec, int poly) -{ - std::vector out; - - for (int i = 0; i < int(vec.size()); i++) - if ((poly & (1 << (i+1))) != 0) { - if (out.empty()) - out.push_back(vec.at(i)); - else - out.at(0) = that->XOR(out.at(0), vec.at(i)); - } - - for (int i = 0; i+1 < int(vec.size()); i++) - out.push_back(vec.at(i)); - - return out; -} - -static int lfsr_num(int vec, int poly, int cnt = 1) -{ - int mask = poly >> 1; - mask |= mask >> 1; - mask |= mask >> 2; - mask |= mask >> 4; - mask |= mask >> 8; - mask |= mask >> 16; - - while (cnt-- > 0) { - int bits = vec & (poly >> 1); - bits = ((bits & 0xAAAAAAAA) >> 1) ^ (bits & 0x55555555); - bits = ((bits & 0x44444444) >> 2) ^ (bits & 0x11111111); - bits = ((bits & 0x10101010) >> 4) ^ (bits & 0x01010101); - bits = ((bits & 0x01000100) >> 8) ^ (bits & 0x00010001); - bits = ((bits & 0x00010000) >> 16) ^ (bits & 0x00000001); - vec = ((vec << 1) | bits) & mask; - } - - return vec; -} - -int ezSAT::manyhot(const std::vector &vec, int min_hot, int max_hot) -{ - // many-hot encoding using LFSR as counter - - int poly = 0; - int nbits = 0; - - if (vec.size() < 3) { - poly = (1 << 2) | (1 << 1) | 1; - nbits = 2; - } else - if (vec.size() < 7) { - poly = (1 << 3) | (1 << 2) | 1; - nbits = 3; - } else - if (vec.size() < 15) { - poly = (1 << 4) | (1 << 3) | 1; - nbits = 4; - } else - if (vec.size() < 31) { - poly = (1 << 5) | (1 << 3) | 1; - nbits = 5; - } else - if (vec.size() < 63) { - poly = (1 << 6) | (1 << 5) | 1; - nbits = 6; - } else - if (vec.size() < 127) { - poly = (1 << 7) | (1 << 6) | 1; - nbits = 7; - } else - // if (vec.size() < 255) { - // poly = (1 << 8) | (1 << 6) | (1 << 5) | (1 << 4) | 1; - // nbits = 8; - // } else - if (vec.size() < 511) { - poly = (1 << 9) | (1 << 5) | 1; - nbits = 9; - } else { - assert(0); - } - - std::vector min_val; - std::vector max_val; - - if (min_hot > 1) - min_val = vec_const_unsigned(lfsr_num(1, poly, min_hot), nbits); - - if (max_hot >= 0) - max_val = vec_const_unsigned(lfsr_num(1, poly, max_hot+1), nbits); - - std::vector state = vec_const_unsigned(1, nbits); - - std::vector match_min; - std::vector match_max; - - if (min_hot == 1) - match_min = vec; - - for (int i = 0; i < int(vec.size()); i++) - { - state = vec_ite(vec[i], lfsr_sym(this, state, poly), state); - - if (!min_val.empty() && i+1 >= min_hot) - match_min.push_back(vec_eq(min_val, state)); - - if (!max_val.empty() && i >= max_hot) - match_max.push_back(vec_eq(max_val, state)); - } - - int min_matched = min_hot ? vec_reduce_or(match_min) : CONST_TRUE; - int max_matched = vec_reduce_or(match_max); - - return AND(min_matched, NOT(max_matched)); -} -#endif - -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 7f3bdf68dd0..00000000000 --- 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 Claire Xenia 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 d39def6c6c8..00000000000 --- 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 Claire Xenia 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 693f8d853c1..00000000000 --- 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 f5a91f3fb68..00000000000 --- 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 Claire Xenia 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/fst/block_format.txt b/yosys/libs/fst/block_format.txt deleted file mode 100644 index e6fe1661b6d..00000000000 --- a/yosys/libs/fst/block_format.txt +++ /dev/null @@ -1,130 +0,0 @@ -See fstapi.h for the values for the FST_BL_XXX enums. - -=========================================================================== - -compressed wrapper (typically over whole file) - -uint8_t FST_BL_ZWRAPPER -uint64_t section length -uint64_t length of uncompressed data -[zlib compressed data] - -=========================================================================== - -header block - -uint8_t FST_BL_HDR -uint64_t section length -uint64_t start time -uint64_t end time -double endian test for "e" -uint64_t memory used by writer -uint64_t scope creation count -uint64_t var creation count -uint64_t max var idcode -uint64_t vc section count -int8_t timescale exponent -[128 bytes] version -[128 bytes] date - -=========================================================================== - -geometry block - -uint8_t FST_BL_GEOM -uint64_t section length -uint64_t length of uncompressed geometry data -uint64_t maxhandle -[compressed data] - -(length of compressed data is section length - 24) - -=========================================================================== - -hierarchy block - -uint8_t FST_BL_HIER -uint64_t section length -uint64_t length of uncompressed hier data -[zlib compressed data] - -or - -uint8_t FST_BL_HIER_LZ4 -uint64_t section length -uint64_t length of uncompressed hier data -[lz4 compressed data] - -uint8_t FST_BL_HIER_LZ4DUO -uint64_t section length -uint64_t length of uncompressed hier data -varint length of hier data compressed once with lz4 -[lz4 double compressed data] - - -=========================================================================== - -dumpon/off block - -uint8_t FST_BL_BLACKOUT -uint64_t section length -varint num blackouts (section below is repeated this # times) -[ -uint8_t on/off (nonzero = on) -varint delta time -] - -=========================================================================== - -1..n value change blocks: - -// header - -uint8_t FST_BL_VCDATA (or FST_BL_VCDATA_DYN_ALIAS) -uint64_t section length -uint64_t begin time of section -uint64_t end time of section -uint64_t amount of buffer memory required in reader for full vc traversal -varint maxvalpos (length of uncompressed data) -varint length of compressed data -varint maxhandle associated with this checkpoint data -[compressed data] - ---- - -// value changes - -varint maxhandle associated with the value change data -uint8_t pack type ('F' is fastlz, '4' is lz4, - others ['Z'/'!'] are zlib) - -varint chain 0 compressed data length (0 = uncompressed) -[compressed data] -... -varint chain n compressed data length (0 = uncompressed) -[compressed data] - ---- - -// index: chain pointer table (from 0..maxhandle-1) - -varint if &1 == 1, this is <<1 literal delta - if &1 == 0, this is <<1 RLE count of zeros - if == 0, next varint is handle of prev chain to use, - bit only if FST_BL_VCDATA_DYN_ALIAS or - later VCDATA format - ---- - -uint64_t index length (subtract from here to get index position) - ---- - -[compressed data for time section] -uint64_t uncompressed data length in bytes -uint64_t compressed data length in bytes -uint64_t number of time items - -// end of section - -=========================================================================== diff --git a/yosys/libs/fst/config.h b/yosys/libs/fst/config.h deleted file mode 100644 index a2f0fca82c4..00000000000 --- a/yosys/libs/fst/config.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Define to 1 if you have and it should be used (not on Ultrix). - */ -#define HAVE_ALLOCA_H 1 - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -#define HAVE_FSEEKO 1 - -/* Define to 1 if you have the `pthread' library (-lpthread). */ -#define HAVE_LIBPTHREAD 1 - -/* Define to 1 if you have the `realpath' function. */ -#define HAVE_REALPATH 1 - -#if defined(__MINGW32__) -#undef HAVE_ALLOCA_H -#undef HAVE_REALPATH -#endif -#if defined(_MSC_VER) -#undef HAVE_ALLOCA_H -#undef HAVE_REALPATH -#undef HAVE_LIBPTHREAD -#undef HAVE_FSEEKO -#endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) -#undef HAVE_ALLOCA_H -#endif - -# ifndef __STDC_FORMAT_MACROS -# define __STDC_FORMAT_MACROS 1 -# endif diff --git a/yosys/libs/fst/fastlz.cc b/yosys/libs/fst/fastlz.cc deleted file mode 100644 index 68bda3346b3..00000000000 --- a/yosys/libs/fst/fastlz.cc +++ /dev/null @@ -1,528 +0,0 @@ -/* - FastLZ - lightning-fast lossless compression library - - Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) - - 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. - - SPDX-License-Identifier: MIT -*/ - -#include "fastlz.h" - -#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) - -/* - * Always check for bound when decompressing. - * Generally it is best to leave it defined. - */ -#define FASTLZ_SAFE - -/* - * Give hints to the compiler for branch prediction optimization. - */ -#if defined(__GNUC__) && (__GNUC__ > 2) -#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) -#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) -#else -#define FASTLZ_EXPECT_CONDITIONAL(c) (c) -#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) -#endif - -/* - * Use inlined functions for supported systems. - */ -#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) -#define FASTLZ_INLINE inline -#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) -#define FASTLZ_INLINE __inline -#else -#define FASTLZ_INLINE -#endif - -/* - * Prevent accessing more than 8-bit at once, except on x86 architectures. - */ -#if !defined(FASTLZ_STRICT_ALIGN) -#define FASTLZ_STRICT_ALIGN -#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__amd64) /* GNU C */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(_M_IX86) /* Intel, MSVC */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__386) -#undef FASTLZ_STRICT_ALIGN -#elif defined(_X86_) /* MinGW */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__I86__) /* Digital Mars */ -#undef FASTLZ_STRICT_ALIGN -#endif -#endif - -/* prototypes */ -int fastlz_compress(const void *input, int length, void *output); -int fastlz_compress_level(int level, const void *input, int length, void *output); -int fastlz_decompress(const void *input, int length, void *output, int maxout); - -#define MAX_COPY 32 -#define MAX_LEN 264 /* 256 + 8 */ -#define MAX_DISTANCE 8192 - -#if !defined(FASTLZ_STRICT_ALIGN) -#define FASTLZ_READU16(p) *((const flzuint16 *)(p)) -#else -#define FASTLZ_READU16(p) ((p)[0] | (p)[1] << 8) -#endif - -#define HASH_LOG 13 -#define HASH_SIZE (1 << HASH_LOG) -#define HASH_MASK (HASH_SIZE - 1) -#define HASH_FUNCTION(v, p) \ - { \ - v = FASTLZ_READU16(p); \ - v ^= FASTLZ_READU16(p + 1) ^ (v >> (16 - HASH_LOG)); \ - v &= HASH_MASK; \ - } - -#undef FASTLZ_LEVEL -#define FASTLZ_LEVEL 1 - -#undef FASTLZ_COMPRESSOR -#undef FASTLZ_DECOMPRESSOR -#define FASTLZ_COMPRESSOR fastlz1_compress -#define FASTLZ_DECOMPRESSOR fastlz1_decompress -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length, void *output); -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length, void *output, int maxout); -#include "fastlz.cc" - -#undef FASTLZ_LEVEL -#define FASTLZ_LEVEL 2 - -#undef MAX_DISTANCE -#define MAX_DISTANCE 8191 -#define MAX_FARDISTANCE (65535 + MAX_DISTANCE - 1) - -#undef FASTLZ_COMPRESSOR -#undef FASTLZ_DECOMPRESSOR -#define FASTLZ_COMPRESSOR fastlz2_compress -#define FASTLZ_DECOMPRESSOR fastlz2_decompress -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length, void *output); -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length, void *output, int maxout); -#include "fastlz.cc" - -int fastlz_compress(const void *input, int length, void *output) -{ - /* for short block, choose fastlz1 */ - if (length < 65536) - return fastlz1_compress(input, length, output); - - /* else... */ - return fastlz2_compress(input, length, output); -} - -int fastlz_decompress(const void *input, int length, void *output, int maxout) -{ - /* magic identifier for compression level */ - int level = ((*(const flzuint8 *)input) >> 5) + 1; - - if (level == 1) - return fastlz1_decompress(input, length, output, maxout); - if (level == 2) - return fastlz2_decompress(input, length, output, maxout); - - /* unknown level, trigger error */ - return 0; -} - -int fastlz_compress_level(int level, const void *input, int length, void *output) -{ - if (level == 1) - return fastlz1_compress(input, length, output); - if (level == 2) - return fastlz2_compress(input, length, output); - - return 0; -} - -#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ - -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length, void *output) -{ - const flzuint8 *ip = (const flzuint8 *)input; - const flzuint8 *ip_bound = ip + length - 2; - const flzuint8 *ip_limit = ip + length - 12; - flzuint8 *op = (flzuint8 *)output; - - const flzuint8 *htab[HASH_SIZE]; - const flzuint8 **hslot; - flzuint32 hval; - - flzuint32 copy; - - /* sanity check */ - if (FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) { - if (length) { - /* create literal copy only */ - *op++ = length - 1; - ip_bound++; - while (ip <= ip_bound) - *op++ = *ip++; - return length + 1; - } else - return 0; - } - - /* initializes hash table */ - for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) - *hslot = ip; - - /* we start with literal copy */ - copy = 2; - *op++ = MAX_COPY - 1; - *op++ = *ip++; - *op++ = *ip++; - - /* main loop */ - while (FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) { - const flzuint8 *ref; - flzuint32 distance; - - /* minimum match length */ - flzuint32 len = 3; - - /* comparison starting-point */ - const flzuint8 *anchor = ip; - - /* check for a run */ -#if FASTLZ_LEVEL == 2 - if (ip[0] == ip[-1] && FASTLZ_READU16(ip - 1) == FASTLZ_READU16(ip + 1)) { - distance = 1; - /* ip += 3; */ /* scan-build, never used */ - ref = anchor - 1 + 3; - goto match; - } -#endif - - /* find potential match */ - HASH_FUNCTION(hval, ip); - hslot = htab + hval; - ref = htab[hval]; - - /* calculate distance to the match */ - distance = anchor - ref; - - /* update hash table */ - *hslot = anchor; - - /* is this a match? check the first 3 bytes */ - if (distance == 0 || -#if FASTLZ_LEVEL == 1 - (distance >= MAX_DISTANCE) || -#else - (distance >= MAX_FARDISTANCE) || -#endif - *ref++ != *ip++ || *ref++ != *ip++ || *ref++ != *ip++) - goto literal; - -#if FASTLZ_LEVEL == 2 - /* far, needs at least 5-byte match */ - if (distance >= MAX_DISTANCE) { - if (*ip++ != *ref++ || *ip++ != *ref++) - goto literal; - len += 2; - } - - match: -#endif - - /* last matched byte */ - ip = anchor + len; - - /* distance is biased */ - distance--; - - if (!distance) { - /* zero distance means a run */ - flzuint8 x = ip[-1]; - while (ip < ip_bound) - if (*ref++ != x) - break; - else - ip++; - } else - for (;;) { - /* safe because the outer check against ip limit */ - if (*ref++ != *ip++) - break; - if (*ref++ != *ip++) - break; - if (*ref++ != *ip++) - break; - if (*ref++ != *ip++) - break; - if (*ref++ != *ip++) - break; - if (*ref++ != *ip++) - break; - if (*ref++ != *ip++) - break; - if (*ref++ != *ip++) - break; - while (ip < ip_bound) - if (*ref++ != *ip++) - break; - break; - } - - /* if we have copied something, adjust the copy count */ - if (copy) - /* copy is biased, '0' means 1 byte copy */ - *(op - copy - 1) = copy - 1; - else - /* back, to overwrite the copy count */ - op--; - - /* reset literal counter */ - copy = 0; - - /* length is biased, '1' means a match of 3 bytes */ - ip -= 3; - len = ip - anchor; - - /* encode the match */ -#if FASTLZ_LEVEL == 2 - if (distance < MAX_DISTANCE) { - if (len < 7) { - *op++ = (len << 5) + (distance >> 8); - *op++ = (distance & 255); - } else { - *op++ = (7 << 5) + (distance >> 8); - for (len -= 7; len >= 255; len -= 255) - *op++ = 255; - *op++ = len; - *op++ = (distance & 255); - } - } else { - /* far away, but not yet in the another galaxy... */ - if (len < 7) { - distance -= MAX_DISTANCE; - *op++ = (len << 5) + 31; - *op++ = 255; - *op++ = distance >> 8; - *op++ = distance & 255; - } else { - distance -= MAX_DISTANCE; - *op++ = (7 << 5) + 31; - for (len -= 7; len >= 255; len -= 255) - *op++ = 255; - *op++ = len; - *op++ = 255; - *op++ = distance >> 8; - *op++ = distance & 255; - } - } -#else - - if (FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN - 2)) - while (len > MAX_LEN - 2) { - *op++ = (7 << 5) + (distance >> 8); - *op++ = MAX_LEN - 2 - 7 - 2; - *op++ = (distance & 255); - len -= MAX_LEN - 2; - } - - if (len < 7) { - *op++ = (len << 5) + (distance >> 8); - *op++ = (distance & 255); - } else { - *op++ = (7 << 5) + (distance >> 8); - *op++ = len - 7; - *op++ = (distance & 255); - } -#endif - - /* update the hash at match boundary */ - HASH_FUNCTION(hval, ip); - htab[hval] = ip++; - HASH_FUNCTION(hval, ip); - htab[hval] = ip++; - - /* assuming literal copy */ - *op++ = MAX_COPY - 1; - - continue; - - literal: - *op++ = *anchor++; - ip = anchor; - copy++; - if (FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) { - copy = 0; - *op++ = MAX_COPY - 1; - } - } - - /* left-over as literal copy */ - ip_bound++; - while (ip <= ip_bound) { - *op++ = *ip++; - copy++; - if (copy == MAX_COPY) { - copy = 0; - *op++ = MAX_COPY - 1; - } - } - - /* if we have copied something, adjust the copy length */ - if (copy) - *(op - copy - 1) = copy - 1; - else - op--; - -#if FASTLZ_LEVEL == 2 - /* marker for fastlz2 */ - *(flzuint8 *)output |= (1 << 5); -#endif - - return op - (flzuint8 *)output; -} - -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length, void *output, int maxout) -{ - const flzuint8 *ip = (const flzuint8 *)input; - const flzuint8 *ip_limit = ip + length; - flzuint8 *op = (flzuint8 *)output; - flzuint8 *op_limit = op + maxout; - flzuint32 ctrl = (*ip++) & 31; - int loop = 1; - - do { - const flzuint8 *ref = op; - flzuint32 len = ctrl >> 5; - flzuint32 ofs = (ctrl & 31) << 8; - - if (ctrl >= 32) { -#if FASTLZ_LEVEL == 2 - flzuint8 code; -#endif - len--; - ref -= ofs; - if (len == 7 - 1) -#if FASTLZ_LEVEL == 1 - len += *ip++; - ref -= *ip++; -#else - do { - code = *ip++; - len += code; - } while (code == 255); - code = *ip++; - ref -= code; - - /* match from 16-bit distance */ - if (FASTLZ_UNEXPECT_CONDITIONAL(code == 255)) - if (FASTLZ_EXPECT_CONDITIONAL(ofs == (31 << 8))) { - ofs = (*ip++) << 8; - ofs += *ip++; - ref = op - ofs - MAX_DISTANCE; - } -#endif - -#ifdef FASTLZ_SAFE - if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) - return 0; - - if (FASTLZ_UNEXPECT_CONDITIONAL(ref - 1 < (flzuint8 *)output)) - return 0; -#endif - - if (FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) - ctrl = *ip++; - else - loop = 0; - - if (ref == op) { - /* optimize copy for a run */ - flzuint8 b = ref[-1]; - *op++ = b; - *op++ = b; - *op++ = b; - for (; len; --len) - *op++ = b; - } else { -#if !defined(FASTLZ_STRICT_ALIGN) - const flzuint16 *p; - flzuint16 *q; -#endif - /* copy from reference */ - ref--; - *op++ = *ref++; - *op++ = *ref++; - *op++ = *ref++; - -#if !defined(FASTLZ_STRICT_ALIGN) - /* copy a byte, so that now it's word aligned */ - if (len & 1) { - *op++ = *ref++; - len--; - } - - /* copy 16-bit at once */ - q = (flzuint16 *)op; - op += len; - p = (const flzuint16 *)ref; - for (len >>= 1; len > 4; len -= 4) { - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - } - for (; len; --len) - *q++ = *p++; -#else - for (; len; --len) - *op++ = *ref++; -#endif - } - } else { - ctrl++; -#ifdef FASTLZ_SAFE - if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) - return 0; - if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) - return 0; -#endif - - *op++ = *ip++; - for (--ctrl; ctrl; ctrl--) - *op++ = *ip++; - - loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); - if (loop) - ctrl = *ip++; - } - } while (FASTLZ_EXPECT_CONDITIONAL(loop)); - - return op - (flzuint8 *)output; -} - -#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ diff --git a/yosys/libs/fst/fastlz.h b/yosys/libs/fst/fastlz.h deleted file mode 100644 index 1ce44a32a8a..00000000000 --- a/yosys/libs/fst/fastlz.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - FastLZ - lightning-fast lossless compression library - - Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) - - 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. - - SPDX-License-Identifier: MIT -*/ - -#ifndef FASTLZ_H -#define FASTLZ_H - -#include - -#define flzuint8 uint8_t -#define flzuint16 uint16_t -#define flzuint32 uint32_t - - -#define FASTLZ_VERSION 0x000100 - -#define FASTLZ_VERSION_MAJOR 0 -#define FASTLZ_VERSION_MINOR 0 -#define FASTLZ_VERSION_REVISION 0 - -#define FASTLZ_VERSION_STRING "0.1.0" - -#if defined (__cplusplus) -extern "C" { -#endif - -/** - Compress a block of data in the input buffer and returns the size of - compressed block. The size of input buffer is specified by length. The - minimum input buffer size is 16. - - The output buffer must be at least 5% larger than the input buffer - and can not be smaller than 66 bytes. - - If the input is not compressible, the return value might be larger than - length (input buffer size). - - The input buffer and the output buffer can not overlap. -*/ - -int fastlz_compress(const void* input, int length, void* output); - -/** - Decompress a block of compressed data and returns the size of the - decompressed block. If error occurs, e.g. the compressed data is - corrupted or the output buffer is not large enough, then 0 (zero) - will be returned instead. - - The input buffer and the output buffer can not overlap. - - Decompression is memory safe and guaranteed not to write the output buffer - more than what is specified in maxout. - */ - -int fastlz_decompress(const void* input, int length, void* output, int maxout); - -/** - Compress a block of data in the input buffer and returns the size of - compressed block. The size of input buffer is specified by length. The - minimum input buffer size is 16. - - The output buffer must be at least 5% larger than the input buffer - and can not be smaller than 66 bytes. - - If the input is not compressible, the return value might be larger than - length (input buffer size). - - The input buffer and the output buffer can not overlap. - - Compression level can be specified in parameter level. At the moment, - only level 1 and level 2 are supported. - Level 1 is the fastest compression and generally useful for short data. - Level 2 is slightly slower but it gives better compression ratio. - - Note that the compressed data, regardless of the level, can always be - decompressed using the function fastlz_decompress above. -*/ - -int fastlz_compress_level(int level, const void* input, int length, void* output); - -#if defined (__cplusplus) -} -#endif - -#endif /* FASTLZ_H */ diff --git a/yosys/libs/fst/fstapi.cc b/yosys/libs/fst/fstapi.cc deleted file mode 100644 index da0d959a0de..00000000000 --- a/yosys/libs/fst/fstapi.cc +++ /dev/null @@ -1,6548 +0,0 @@ -/* - * Copyright (c) 2009-2018 Tony Bybell. - * - * 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. - * - * SPDX-License-Identifier: MIT - */ - -/* - * possible disables: - * - * FST_DYNAMIC_ALIAS_DISABLE : dynamic aliases are not processed - * FST_DYNAMIC_ALIAS2_DISABLE : new encoding for dynamic aliases is not generated - * FST_WRITEX_DISABLE : fast write I/O routines are disabled - * - * possible enables: - * - * FST_DEBUG : not for production use, only enable for development - * FST_REMOVE_DUPLICATE_VC : glitch removal (has writer performance impact) - * HAVE_LIBPTHREAD -> FST_WRITER_PARALLEL : enables inclusion of parallel writer code - * FST_DO_MISALIGNED_OPS (defined automatically for x86 and some others) : CPU architecture can handle misaligned - * loads/stores _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable) - * - */ - -#ifndef FST_CONFIG_INCLUDE -#define FST_CONFIG_INCLUDE "config.h" -#endif -#include FST_CONFIG_INCLUDE - -#include "fstapi.h" -#include "fastlz.h" -#include "lz4.h" -#include - -#ifndef HAVE_LIBPTHREAD -#undef FST_WRITER_PARALLEL -#endif - -#ifdef FST_WRITER_PARALLEL -#include -#endif - -#ifdef __MINGW32__ -#include -#endif - -#ifdef HAVE_ALLOCA_H -#include -#elif defined(__GNUC__) -#ifndef __MINGW32__ -#ifndef alloca -#define alloca __builtin_alloca -#endif -#else -#include -#endif -#elif defined(_MSC_VER) -#include -#define alloca _alloca -#endif - -#ifndef PATH_MAX -#define PATH_MAX (4096) -#endif - -#if defined(_MSC_VER) -typedef int64_t fst_off_t; -#else -typedef off_t fst_off_t; -#endif - -/* note that Judy versus Jenkins requires more experimentation: they are */ -/* functionally equivalent though it appears Jenkins is slightly faster. */ -/* in addition, Jenkins is not bound by the LGPL. */ -#ifdef _WAVE_HAVE_JUDY -#include -#else -/* should be more than enough for fstWriterSetSourceStem() */ -#define FST_PATH_HASHMASK ((1UL << 16) - 1) -typedef const void *Pcvoid_t; -typedef void *Pvoid_t; -typedef void **PPvoid_t; -#define JudyHSIns(a, b, c, d) JenkinsIns((a), (b), (c), (hashmask)) -#define JudyHSFreeArray(a, b) JenkinsFree((a), (hashmask)) -void JenkinsFree(void *base_i, uint32_t hashmask); -void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask); -#endif - -#ifndef FST_WRITEX_DISABLE -#define FST_WRITEX_MAX (64 * 1024) -#else -#define fstWritex(a, b, c) fstFwrite((b), (c), 1, fv) -#endif - -/* these defines have a large impact on writer speed when a model has a */ -/* huge number of symbols. as a default, use 128MB and increment when */ -/* every 1M signals are defined. */ -#define FST_BREAK_SIZE (1UL << 27) -#define FST_BREAK_ADD_SIZE (1UL << 22) -#define FST_BREAK_SIZE_MAX (1UL << 31) -#define FST_ACTIVATE_HUGE_BREAK (1000000) -#define FST_ACTIVATE_HUGE_INC (1000000) - -#define FST_WRITER_STR "fstWriter" -#define FST_ID_NAM_SIZ (512) -#define FST_ID_NAM_ATTR_SIZ (65536 + 4096) -#define FST_DOUBLE_ENDTEST (2.7182818284590452354) -#define FST_HDR_SIM_VERSION_SIZE (128) -#define FST_HDR_DATE_SIZE (119) -#define FST_HDR_FILETYPE_SIZE (1) -#define FST_HDR_TIMEZERO_SIZE (8) -#define FST_GZIO_LEN (32768) -#define FST_HDR_FOURPACK_DUO_SIZE (4 * 1024 * 1024) - -#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) -#define FST_DO_MISALIGNED_OPS -#endif - -#if defined(__APPLE__) && defined(__MACH__) -#define FST_MACOSX -#include -#endif - -#ifdef __GNUC__ -/* Boolean expression more often true than false */ -#define FST_LIKELY(x) __builtin_expect(!!(x), 1) -/* Boolean expression more often false than true */ -#define FST_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -#define FST_LIKELY(x) (!!(x)) -#define FST_UNLIKELY(x) (!!(x)) -#endif - -#define FST_APIMESS "FSTAPI | " - -/***********************/ -/*** ***/ -/*** common function ***/ -/*** ***/ -/***********************/ - -#if defined(__MINGW32__) || defined(_MSC_VER) -#include -#ifndef HAVE_FSEEKO -#define ftello _ftelli64 -#define fseeko _fseeki64 -#endif -#endif - -/* - * the recoded "extra" values... - * note that FST_RCV_Q is currently unused and is for future expansion. - * its intended use is as another level of escape such that any arbitrary - * value can be stored as the value: { time_delta, 8 bits, FST_RCV_Q }. - * this is currently not implemented so that the branchless decode is: - * uint32_t shcnt = 2 << (vli & 1); tdelta = vli >> shcnt; - */ -#define FST_RCV_X (1 | (0 << 1)) -#define FST_RCV_Z (1 | (1 << 1)) -#define FST_RCV_H (1 | (2 << 1)) -#define FST_RCV_U (1 | (3 << 1)) -#define FST_RCV_W (1 | (4 << 1)) -#define FST_RCV_L (1 | (5 << 1)) -#define FST_RCV_D (1 | (6 << 1)) -#define FST_RCV_Q (1 | (7 << 1)) - -#define FST_RCV_STR "xzhuwl-?" -/* 01234567 */ - -/* - * prevent old file overwrite when currently being read - */ -static FILE *unlink_fopen(const char *nam, const char *mode) -{ - unlink(nam); - return (fopen(nam, mode)); -} - -/* - * system-specific temp file handling - */ -#ifdef __MINGW32__ - -static FILE *tmpfile_open(char **nam) -{ - char *fname = NULL; - TCHAR szTempFileName[MAX_PATH]; - TCHAR lpTempPathBuffer[MAX_PATH]; - DWORD dwRetVal = 0; - UINT uRetVal = 0; - FILE *fh = NULL; - - if (nam) /* cppcheck warning fix: nam is always defined, so this is not needed */ - { - dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); - if ((dwRetVal > MAX_PATH) || (dwRetVal == 0)) { - fprintf(stderr, FST_APIMESS "GetTempPath() failed in " __FILE__ " line %d, exiting.\n", __LINE__); - exit(255); - } else { - uRetVal = GetTempFileName(lpTempPathBuffer, TEXT("FSTW"), 0, szTempFileName); - if (uRetVal == 0) { - fprintf(stderr, FST_APIMESS "GetTempFileName() failed in " __FILE__ " line %d, exiting.\n", __LINE__); - exit(255); - } else { - fname = strdup(szTempFileName); - } - } - - if (fname) { - *nam = fname; - fh = unlink_fopen(fname, "w+b"); - } - } - - return (fh); -} - -#else - -static FILE *tmpfile_open(char **nam) -{ - FILE *f = tmpfile(); /* replace with mkstemp() + fopen(), etc if this is not good enough */ - if (nam) { - *nam = NULL; - } - return (f); -} - -#endif - -static void tmpfile_close(FILE **f, char **nam) -{ - if (f) { - if (*f) { - fclose(*f); - *f = NULL; - } - } - - if (nam) { - if (*nam) { - unlink(*nam); - free(*nam); - *nam = NULL; - } - } -} - -/*****************************************/ - -/* - * to remove warn_unused_result compile time messages - * (in the future there needs to be results checking) - */ -static size_t fstFread(void *buf, size_t siz, size_t cnt, FILE *fp) { return (fread(buf, siz, cnt, fp)); } - -static size_t fstFwrite(const void *buf, size_t siz, size_t cnt, FILE *fp) { return (fwrite(buf, siz, cnt, fp)); } - -static int fstFtruncate(int fd, fst_off_t length) { return (ftruncate(fd, length)); } - -/* - * realpath compatibility - */ -static char *fstRealpath(const char *path, char *resolved_path) -{ -#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH -#if (defined(__MACH__) && defined(__APPLE__)) - if (!resolved_path) { - resolved_path = (char *)malloc(PATH_MAX + 1); /* fixes bug on Leopard when resolved_path == NULL */ - } -#endif - - return (realpath(path, resolved_path)); - -#else -#ifdef __MINGW32__ - if (!resolved_path) { - resolved_path = (char *)malloc(PATH_MAX + 1); - } - return (_fullpath(resolved_path, path, PATH_MAX)); -#else - (void)path; - (void)resolved_path; - return (NULL); -#endif -#endif -} - -/* - * mmap compatibility - */ -#if defined __CYGWIN__ || defined __MINGW32__ || defined _MSC_VER -#include -#define fstMmap(__addr, __len, __prot, __flags, __fd, __off) fstMmap2((__len), (__fd), (__off)) -#define fstMunmap(__addr, __len) free(__addr) - -static void *fstMmap2(size_t __len, int __fd, fst_off_t __off) -{ - (void)__off; - - unsigned char *pnt = (unsigned char *)malloc(__len); - fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR); - size_t i; - - lseek(__fd, 0, SEEK_SET); - for (i = 0; i < __len; i += SSIZE_MAX) { - read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); - } - lseek(__fd, cur_offs, SEEK_SET); - return (pnt); -} -#else -#include -#if defined(__SUNPRO_C) -#define FST_CADDR_T_CAST (caddr_t) -#else -#define FST_CADDR_T_CAST -#endif -#define fstMmap(__addr, __len, __prot, __flags, __fd, __off) \ - (void *)mmap(FST_CADDR_T_CAST(__addr), (__len), (__prot), (__flags), (__fd), (__off)) -#define fstMunmap(__addr, __len) \ - { \ - if (__addr) \ - munmap(FST_CADDR_T_CAST(__addr), (__len)); \ - } -#endif - -/* - * regular and variable-length integer access functions - */ -#ifdef FST_DO_MISALIGNED_OPS -#define fstGetUint32(x) (*(uint32_t *)(x)) -#else -static uint32_t fstGetUint32(unsigned char *mem) -{ - uint32_t u32; - unsigned char *buf = (unsigned char *)(&u32); - - buf[0] = mem[0]; - buf[1] = mem[1]; - buf[2] = mem[2]; - buf[3] = mem[3]; - - return (*(uint32_t *)buf); -} -#endif - -static int fstWriterUint64(FILE *handle, uint64_t v) -{ - unsigned char buf[8]; - int i; - - for (i = 7; i >= 0; i--) { - buf[i] = v & 0xff; - v >>= 8; - } - - fstFwrite(buf, 8, 1, handle); - return (8); -} - -static uint64_t fstReaderUint64(FILE *f) -{ - uint64_t val = 0; - unsigned char buf[sizeof(uint64_t)]; - unsigned int i; - - fstFread(buf, sizeof(uint64_t), 1, f); - for (i = 0; i < sizeof(uint64_t); i++) { - val <<= 8; - val |= buf[i]; - } - - return (val); -} - -static uint32_t fstGetVarint32(unsigned char *mem, int *skiplen) -{ - unsigned char *mem_orig = mem; - uint32_t rc = 0; - while (*mem & 0x80) { - mem++; - } - - *skiplen = mem - mem_orig + 1; - for (;;) { - rc <<= 7; - rc |= (uint32_t)(*mem & 0x7f); - if (mem == mem_orig) { - break; - } - mem--; - } - - return (rc); -} - -static uint32_t fstGetVarint32Length(unsigned char *mem) -{ - unsigned char *mem_orig = mem; - - while (*mem & 0x80) { - mem++; - } - - return (mem - mem_orig + 1); -} - -static uint32_t fstGetVarint32NoSkip(unsigned char *mem) -{ - unsigned char *mem_orig = mem; - uint32_t rc = 0; - while (*mem & 0x80) { - mem++; - } - - for (;;) { - rc <<= 7; - rc |= (uint32_t)(*mem & 0x7f); - if (mem == mem_orig) { - break; - } - mem--; - } - - return (rc); -} - -static unsigned char *fstCopyVarint32ToLeft(unsigned char *pnt, uint32_t v) -{ - unsigned char *spnt; - uint32_t nxt = v; - int cnt = 1; - int i; - - while ((nxt = nxt >> 7)) /* determine len to avoid temp buffer copying to cut down on load-hit-store */ - { - cnt++; - } - - pnt -= cnt; - spnt = pnt; - cnt--; - - for (i = 0; i < cnt; i++) /* now generate left to right as normal */ - { - nxt = v >> 7; - *(spnt++) = ((unsigned char)v) | 0x80; - v = nxt; - } - *spnt = (unsigned char)v; - - return (pnt); -} - -static unsigned char *fstCopyVarint64ToRight(unsigned char *pnt, uint64_t v) -{ - uint64_t nxt; - - while ((nxt = v >> 7)) { - *(pnt++) = ((unsigned char)v) | 0x80; - v = nxt; - } - *(pnt++) = (unsigned char)v; - - return (pnt); -} - -static uint64_t fstGetVarint64(unsigned char *mem, int *skiplen) -{ - unsigned char *mem_orig = mem; - uint64_t rc = 0; - while (*mem & 0x80) { - mem++; - } - - *skiplen = mem - mem_orig + 1; - for (;;) { - rc <<= 7; - rc |= (uint64_t)(*mem & 0x7f); - if (mem == mem_orig) { - break; - } - mem--; - } - - return (rc); -} - -static uint32_t fstReaderVarint32(FILE *f) -{ - unsigned char buf[5]; - unsigned char *mem = buf; - uint32_t rc = 0; - int ch; - - do { - ch = fgetc(f); - *(mem++) = ch; - } while (ch & 0x80); - mem--; - - for (;;) { - rc <<= 7; - rc |= (uint32_t)(*mem & 0x7f); - if (mem == buf) { - break; - } - mem--; - } - - return (rc); -} - -static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen) -{ - unsigned char buf[5]; - unsigned char *mem = buf; - uint32_t rc = 0; - int ch; - - do { - ch = fgetc(f); - *(mem++) = ch; - } while (ch & 0x80); - *skiplen = mem - buf; - mem--; - - for (;;) { - rc <<= 7; - rc |= (uint32_t)(*mem & 0x7f); - if (mem == buf) { - break; - } - mem--; - } - - return (rc); -} - -static uint64_t fstReaderVarint64(FILE *f) -{ - unsigned char buf[16]; - unsigned char *mem = buf; - uint64_t rc = 0; - int ch; - - do { - ch = fgetc(f); - *(mem++) = ch; - } while (ch & 0x80); - mem--; - - for (;;) { - rc <<= 7; - rc |= (uint64_t)(*mem & 0x7f); - if (mem == buf) { - break; - } - mem--; - } - - return (rc); -} - -static int fstWriterVarint(FILE *handle, uint64_t v) -{ - uint64_t nxt; - unsigned char buf[10]; /* ceil(64/7) = 10 */ - unsigned char *pnt = buf; - int len; - - while ((nxt = v >> 7)) { - *(pnt++) = ((unsigned char)v) | 0x80; - v = nxt; - } - *(pnt++) = (unsigned char)v; - - len = pnt - buf; - fstFwrite(buf, len, 1, handle); - return (len); -} - -/* signed integer read/write routines are currently unused */ -static int64_t fstGetSVarint64(unsigned char *mem, int *skiplen) -{ - unsigned char *mem_orig = mem; - int64_t rc = 0; - const int64_t one = 1; - const int siz = sizeof(int64_t) * 8; - int shift = 0; - unsigned char byt; - - do { - byt = *(mem++); - rc |= ((int64_t)(byt & 0x7f)) << shift; - shift += 7; - - } while (byt & 0x80); - - if ((shift < siz) && (byt & 0x40)) { - rc |= -(one << shift); /* sign extend */ - } - - *skiplen = mem - mem_orig; - - return (rc); -} - -#ifndef FST_DYNAMIC_ALIAS2_DISABLE -static int fstWriterSVarint(FILE *handle, int64_t v) -{ - unsigned char buf[15]; /* ceil(64/7) = 10 + sign byte padded way up */ - unsigned char byt; - unsigned char *pnt = buf; - int more = 1; - int len; - - do { - byt = v | 0x80; - v >>= 7; - - if (((!v) && (!(byt & 0x40))) || ((v == -1) && (byt & 0x40))) { - more = 0; - byt &= 0x7f; - } - - *(pnt++) = byt; - } while (more); - - len = pnt - buf; - fstFwrite(buf, len, 1, handle); - return (len); -} -#endif - -/***********************/ -/*** ***/ -/*** writer function ***/ -/*** ***/ -/***********************/ - -/* - * private structs - */ -struct fstBlackoutChain -{ - struct fstBlackoutChain *next; - uint64_t tim; - unsigned active : 1; -}; - -struct fstWriterContext -{ - FILE *handle; - FILE *hier_handle; - FILE *geom_handle; - FILE *valpos_handle; - FILE *curval_handle; - FILE *tchn_handle; - - unsigned char *vchg_mem; - - fst_off_t hier_file_len; - - uint32_t *valpos_mem; - unsigned char *curval_mem; - - unsigned char *outval_mem; /* for two-state / Verilator-style value changes */ - uint32_t outval_alloc_siz; - - char *filename; - - fstHandle maxhandle; - fstHandle numsigs; - uint32_t maxvalpos; - - unsigned vc_emitted : 1; - unsigned is_initial_time : 1; - unsigned fourpack : 1; - unsigned fastpack : 1; - - int64_t timezero; - fst_off_t section_header_truncpos; - uint32_t tchn_cnt, tchn_idx; - uint64_t curtime; - uint64_t firsttime; - uint32_t vchg_siz; - uint32_t vchg_alloc_siz; - - uint32_t secnum; - fst_off_t section_start; - - uint32_t numscopes; - double nan; /* nan value for uninitialized doubles */ - - struct fstBlackoutChain *blackout_head; - struct fstBlackoutChain *blackout_curr; - uint32_t num_blackouts; - - uint64_t dump_size_limit; - - unsigned char filetype; /* default is 0, FST_FT_VERILOG */ - - unsigned compress_hier : 1; - unsigned repack_on_close : 1; - unsigned skip_writing_section_hdr : 1; - unsigned size_limit_locked : 1; - unsigned section_header_only : 1; - unsigned flush_context_pending : 1; - unsigned parallel_enabled : 1; - unsigned parallel_was_enabled : 1; - - /* should really be semaphores, but are bytes to cut down on read-modify-write window size */ - unsigned char already_in_flush; /* in case control-c handlers interrupt */ - unsigned char already_in_close; /* in case control-c handlers interrupt */ - -#ifdef FST_WRITER_PARALLEL - pthread_mutex_t mutex; - pthread_t thread; - pthread_attr_t thread_attr; - struct fstWriterContext *xc_parent; -#endif - unsigned in_pthread : 1; - - size_t fst_orig_break_size; - size_t fst_orig_break_add_size; - - size_t fst_break_size; - size_t fst_break_add_size; - - size_t fst_huge_break_size; - - fstHandle next_huge_break; - - Pvoid_t path_array; - uint32_t path_array_count; - - unsigned fseek_failed : 1; - - char *geom_handle_nam; - char *valpos_handle_nam; - char *curval_handle_nam; - char *tchn_handle_nam; - - fstEnumHandle max_enumhandle; -}; - -static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, fst_off_t offset, int whence) -{ - int rc = fseeko(stream, offset, whence); - - if (rc < 0) { - xc->fseek_failed = 1; -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence); - perror("Why"); -#endif - } - - return (rc); -} - -static uint32_t fstWriterUint32WithVarint32(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, - uint32_t siz) -{ - unsigned char *buf = xc->vchg_mem + xc->vchg_siz; - unsigned char *pnt = buf; - uint32_t nxt; - uint32_t len; - -#ifdef FST_DO_MISALIGNED_OPS - (*(uint32_t *)(pnt)) = (*(uint32_t *)(u)); -#else - memcpy(pnt, u, sizeof(uint32_t)); -#endif - pnt += 4; - - while ((nxt = v >> 7)) { - *(pnt++) = ((unsigned char)v) | 0x80; - v = nxt; - } - *(pnt++) = (unsigned char)v; - memcpy(pnt, dbuf, siz); - - len = pnt - buf + siz; - return (len); -} - -static uint32_t fstWriterUint32WithVarint32AndLength(struct fstWriterContext *xc, uint32_t *u, uint32_t v, - const void *dbuf, uint32_t siz) -{ - unsigned char *buf = xc->vchg_mem + xc->vchg_siz; - unsigned char *pnt = buf; - uint32_t nxt; - uint32_t len; - -#ifdef FST_DO_MISALIGNED_OPS - (*(uint32_t *)(pnt)) = (*(uint32_t *)(u)); -#else - memcpy(pnt, u, sizeof(uint32_t)); -#endif - pnt += 4; - - while ((nxt = v >> 7)) { - *(pnt++) = ((unsigned char)v) | 0x80; - v = nxt; - } - *(pnt++) = (unsigned char)v; - - v = siz; - while ((nxt = v >> 7)) { - *(pnt++) = ((unsigned char)v) | 0x80; - v = nxt; - } - *(pnt++) = (unsigned char)v; - - memcpy(pnt, dbuf, siz); - - len = pnt - buf + siz; - return (len); -} - -/* - * header bytes, write here so defines are set up before anything else - * that needs to use them - */ -static void fstWriterEmitHdrBytes(struct fstWriterContext *xc) -{ - char vbuf[FST_HDR_SIM_VERSION_SIZE]; - char dbuf[FST_HDR_DATE_SIZE]; - double endtest = FST_DOUBLE_ENDTEST; - time_t walltime; - -#define FST_HDR_OFFS_TAG (0) - fputc(FST_BL_HDR, xc->handle); /* +0 tag */ - -#define FST_HDR_OFFS_SECLEN (FST_HDR_OFFS_TAG + 1) - fstWriterUint64(xc->handle, 329); /* +1 section length */ - -#define FST_HDR_OFFS_START_TIME (FST_HDR_OFFS_SECLEN + 8) - fstWriterUint64(xc->handle, 0); /* +9 start time */ - -#define FST_HDR_OFFS_END_TIME (FST_HDR_OFFS_START_TIME + 8) - fstWriterUint64(xc->handle, 0); /* +17 end time */ - -#define FST_HDR_OFFS_ENDIAN_TEST (FST_HDR_OFFS_END_TIME + 8) - fstFwrite(&endtest, 8, 1, xc->handle); /* +25 endian test for reals */ - -#define FST_HDR_OFFS_MEM_USED (FST_HDR_OFFS_ENDIAN_TEST + 8) - fstWriterUint64(xc->handle, xc->fst_break_size); /* +33 memory used by writer */ - -#define FST_HDR_OFFS_NUM_SCOPES (FST_HDR_OFFS_MEM_USED + 8) - fstWriterUint64(xc->handle, 0); /* +41 scope creation count */ - -#define FST_HDR_OFFS_NUM_VARS (FST_HDR_OFFS_NUM_SCOPES + 8) - fstWriterUint64(xc->handle, 0); /* +49 var creation count */ - -#define FST_HDR_OFFS_MAXHANDLE (FST_HDR_OFFS_NUM_VARS + 8) - fstWriterUint64(xc->handle, 0); /* +57 max var idcode */ - -#define FST_HDR_OFFS_SECTION_CNT (FST_HDR_OFFS_MAXHANDLE + 8) - fstWriterUint64(xc->handle, 0); /* +65 vc section count */ - -#define FST_HDR_OFFS_TIMESCALE (FST_HDR_OFFS_SECTION_CNT + 8) - fputc((-9) & 255, xc->handle); /* +73 timescale 1ns */ - -#define FST_HDR_OFFS_SIM_VERSION (FST_HDR_OFFS_TIMESCALE + 1) - memset(vbuf, 0, FST_HDR_SIM_VERSION_SIZE); - strcpy(vbuf, FST_WRITER_STR); - fstFwrite(vbuf, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); /* +74 version */ - -#define FST_HDR_OFFS_DATE (FST_HDR_OFFS_SIM_VERSION + FST_HDR_SIM_VERSION_SIZE) - memset(dbuf, 0, FST_HDR_DATE_SIZE); - time(&walltime); - strcpy(dbuf, asctime(localtime(&walltime))); - fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle); /* +202 date */ - - /* date size is deliberately overspecified at 119 bytes (originally 128) in order to provide backfill for new args - */ - -#define FST_HDR_OFFS_FILETYPE (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE) - fputc(xc->filetype, xc->handle); /* +321 filetype */ - -#define FST_HDR_OFFS_TIMEZERO (FST_HDR_OFFS_FILETYPE + FST_HDR_FILETYPE_SIZE) - fstWriterUint64(xc->handle, xc->timezero); /* +322 timezero */ - -#define FST_HDR_LENGTH (FST_HDR_OFFS_TIMEZERO + FST_HDR_TIMEZERO_SIZE) - /* +330 next section starts here */ - fflush(xc->handle); -} - -/* - * mmap functions - */ -static void fstWriterMmapSanity(void *pnt, const char *file, int line, const char *usage) -{ -#if !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(_MSC_VER) - if (pnt == MAP_FAILED) { - fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line); - perror("Why"); - pnt = NULL; - } -#endif -} - -static void fstWriterCreateMmaps(struct fstWriterContext *xc) -{ - fst_off_t curpos = ftello(xc->handle); - - fflush(xc->hier_handle); - - /* write out intermediate header */ - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); - fstWriterUint64(xc->handle, xc->firsttime); - fstWriterUint64(xc->handle, xc->curtime); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET); - fstWriterUint64(xc->handle, xc->numscopes); - fstWriterUint64(xc->handle, xc->numsigs); - fstWriterUint64(xc->handle, xc->maxhandle); - fstWriterUint64(xc->handle, xc->secnum); - fstWriterFseeko(xc, xc->handle, curpos, SEEK_SET); - fflush(xc->handle); - - /* do mappings */ - if (!xc->valpos_mem) { - fflush(xc->valpos_handle); - errno = 0; - if (xc->maxhandle) { - fstWriterMmapSanity(xc->valpos_mem = (uint32_t *)fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), - PROT_READ | PROT_WRITE, MAP_SHARED, - fileno(xc->valpos_handle), 0), - __FILE__, __LINE__, "xc->valpos_mem"); - } - } - if (!xc->curval_mem) { - fflush(xc->curval_handle); - errno = 0; - if (xc->maxvalpos) { - fstWriterMmapSanity(xc->curval_mem = (unsigned char *)fstMmap(NULL, xc->maxvalpos, PROT_READ | PROT_WRITE, - MAP_SHARED, fileno(xc->curval_handle), 0), - __FILE__, __LINE__, "xc->curval_handle"); - } - } -} - -static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing) -{ -#if !defined __CYGWIN__ && !defined __MINGW32__ - (void)is_closing; -#endif - - fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); - xc->valpos_mem = NULL; - -#if defined __CYGWIN__ || defined __MINGW32__ - if (xc->curval_mem) { - if (!is_closing) /* need to flush out for next emulated mmap() read */ - { - unsigned char *pnt = xc->curval_mem; - int __fd = fileno(xc->curval_handle); - fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR); - size_t i; - size_t __len = xc->maxvalpos; - - lseek(__fd, 0, SEEK_SET); - for (i = 0; i < __len; i += SSIZE_MAX) { - write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); - } - lseek(__fd, cur_offs, SEEK_SET); - } - } -#endif - - fstMunmap(xc->curval_mem, xc->maxvalpos); - xc->curval_mem = NULL; -} - -/* - * set up large and small memory usages - * crossover point in model is FST_ACTIVATE_HUGE_BREAK number of signals - */ -static void fstDetermineBreakSize(struct fstWriterContext *xc) -{ -#if defined(__linux__) || defined(FST_MACOSX) - int was_set = 0; - -#ifdef __linux__ - FILE *f = fopen("/proc/meminfo", "rb"); - - if (f) { - char buf[257]; - char *s; - while (!feof(f)) { - buf[0] = 0; - s = fgets(buf, 256, f); - if (s && *s) { - if (!strncmp(s, "MemTotal:", 9)) { - size_t v = atol(s + 10); - v *= 1024; /* convert to bytes */ - v /= 8; /* chop down to 1/8 physical memory */ - if (v > FST_BREAK_SIZE) { - if (v > FST_BREAK_SIZE_MAX) { - v = FST_BREAK_SIZE_MAX; - } - - xc->fst_huge_break_size = v; - was_set = 1; - break; - } - } - } - } - - fclose(f); - } - - if (!was_set) { - xc->fst_huge_break_size = FST_BREAK_SIZE; - } -#else - int mib[2]; - int64_t v; - size_t length; - - mib[0] = CTL_HW; - mib[1] = HW_MEMSIZE; - length = sizeof(int64_t); - if (!sysctl(mib, 2, &v, &length, NULL, 0)) { - v /= 8; - - if (v > (int64_t)FST_BREAK_SIZE) { - if (v > (int64_t)FST_BREAK_SIZE_MAX) { - v = FST_BREAK_SIZE_MAX; - } - - xc->fst_huge_break_size = v; - was_set = 1; - } - } - - if (!was_set) { - xc->fst_huge_break_size = FST_BREAK_SIZE; - } -#endif -#else - xc->fst_huge_break_size = FST_BREAK_SIZE; -#endif - - xc->fst_break_size = xc->fst_orig_break_size = FST_BREAK_SIZE; - xc->fst_break_add_size = xc->fst_orig_break_add_size = FST_BREAK_ADD_SIZE; - xc->next_huge_break = FST_ACTIVATE_HUGE_BREAK; -} - -/* - * file creation and close - */ -void *fstWriterCreate(const char *nam, int use_compressed_hier) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)calloc(1, sizeof(struct fstWriterContext)); - - xc->compress_hier = use_compressed_hier; - fstDetermineBreakSize(xc); - - if ((!nam) || (!(xc->handle = unlink_fopen(nam, "w+b")))) { - free(xc); - xc = NULL; - } else { - int flen = strlen(nam); - char *hf = (char *)calloc(1, flen + 6); - - memcpy(hf, nam, flen); - strcpy(hf + flen, ".hier"); - xc->hier_handle = unlink_fopen(hf, "w+b"); - - xc->geom_handle = tmpfile_open(&xc->geom_handle_nam); /* .geom */ - xc->valpos_handle = tmpfile_open(&xc->valpos_handle_nam); /* .offs */ - xc->curval_handle = tmpfile_open(&xc->curval_handle_nam); /* .bits */ - xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* .tchn */ - xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; - xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz); - - if (xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchg_mem && - xc->tchn_handle) { - xc->filename = strdup(nam); - xc->is_initial_time = 1; - - fstWriterEmitHdrBytes(xc); - xc->nan = strtod("NaN", NULL); -#ifdef FST_WRITER_PARALLEL - pthread_mutex_init(&xc->mutex, NULL); - pthread_attr_init(&xc->thread_attr); - pthread_attr_setdetachstate(&xc->thread_attr, PTHREAD_CREATE_DETACHED); -#endif - } else { - fclose(xc->handle); - if (xc->hier_handle) { - fclose(xc->hier_handle); - unlink(hf); - } - tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam); - tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam); - tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam); - tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); - free(xc->vchg_mem); - free(xc); - xc = NULL; - } - - free(hf); - } - - return (xc); -} - -/* - * generation and writing out of value change data sections - */ -static void fstWriterEmitSectionHeader(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - if (xc) { - unsigned long destlen; - unsigned char *dmem; - int rc; - - destlen = xc->maxvalpos; - dmem = (unsigned char *)malloc(compressBound(destlen)); - rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, - 4); /* was 9...which caused performance drag on traces with many signals */ - - fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */ - xc->section_start = ftello(xc->handle); -#ifdef FST_WRITER_PARALLEL - if (xc->xc_parent) - xc->xc_parent->section_start = xc->section_start; -#endif - xc->section_header_only = 1; /* indicates truncate might be needed */ - fstWriterUint64(xc->handle, 0); /* placeholder = section length */ - fstWriterUint64(xc->handle, xc->is_initial_time ? xc->firsttime : xc->curtime); /* begin time of section */ - fstWriterUint64(xc->handle, xc->curtime); /* end time of section (placeholder) */ - fstWriterUint64(xc->handle, - 0); /* placeholder = amount of buffer memory required in reader for full vc traversal */ - fstWriterVarint(xc->handle, xc->maxvalpos); /* maxvalpos = length of uncompressed data */ - - if ((rc == Z_OK) && (destlen < xc->maxvalpos)) { - fstWriterVarint(xc->handle, destlen); /* length of compressed data */ - } else { - fstWriterVarint(xc->handle, xc->maxvalpos); /* length of (unable to be) compressed data */ - } - fstWriterVarint(xc->handle, - xc->maxhandle); /* max handle associated with this data (in case of dynamic facility adds) */ - - if ((rc == Z_OK) && (destlen < xc->maxvalpos)) { - fstFwrite(dmem, destlen, 1, xc->handle); - } else /* comparison between compressed / decompressed len tells if compressed */ - { - fstFwrite(xc->curval_mem, xc->maxvalpos, 1, xc->handle); - } - - free(dmem); - } -} - -/* - * only to be called directly by fst code...otherwise must - * be synced up with time changes - */ -#ifdef FST_WRITER_PARALLEL -static void fstWriterFlushContextPrivate2(void *ctx) -#else -static void fstWriterFlushContextPrivate(void *ctx) -#endif -{ -#ifdef FST_DEBUG - int cnt = 0; -#endif - unsigned int i; - unsigned char *vchg_mem; - FILE *f; - fst_off_t fpos, indxpos, endpos; - uint32_t prevpos; - int zerocnt; - unsigned char *scratchpad; - unsigned char *scratchpnt; - unsigned char *tmem; - fst_off_t tlen; - fst_off_t unc_memreq = 0; /* for reader */ - unsigned char *packmem; - unsigned int packmemlen; - uint32_t *vm4ip; - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; -#ifdef FST_WRITER_PARALLEL - struct fstWriterContext *xc2 = xc->xc_parent; -#else - struct fstWriterContext *xc2 = xc; -#endif - -#ifndef FST_DYNAMIC_ALIAS_DISABLE - Pvoid_t PJHSArray = (Pvoid_t)NULL; -#ifndef _WAVE_HAVE_JUDY - uint32_t hashmask = xc->maxhandle; - hashmask |= hashmask >> 1; - hashmask |= hashmask >> 2; - hashmask |= hashmask >> 4; - hashmask |= hashmask >> 8; - hashmask |= hashmask >> 16; -#endif -#endif - - if ((xc->vchg_siz <= 1) || (xc->already_in_flush)) - return; - xc->already_in_flush = 1; /* should really do this with a semaphore */ - - xc->section_header_only = 0; - scratchpad = (unsigned char *)malloc(xc->vchg_siz); - - vchg_mem = xc->vchg_mem; - - f = xc->handle; - fstWriterVarint(f, xc->maxhandle); /* emit current number of handles */ - fputc(xc->fourpack ? '4' : (xc->fastpack ? 'F' : 'Z'), f); - fpos = 1; - - packmemlen = 1024; /* maintain a running "longest" allocation to */ - packmem = (unsigned char *)malloc(packmemlen); /* prevent continual malloc...free every loop iter */ - - for (i = 0; i < xc->maxhandle; i++) { - vm4ip = &(xc->valpos_mem[4 * i]); - - if (vm4ip[2]) { - uint32_t offs = vm4ip[2]; - uint32_t next_offs; - unsigned int wrlen; - - vm4ip[2] = fpos; - - scratchpnt = scratchpad + xc->vchg_siz; /* build this buffer backwards */ - if (vm4ip[1] <= 1) { - if (vm4ip[1] == 1) { - wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ -#ifndef FST_REMOVE_DUPLICATE_VC - xc->curval_mem[vm4ip[0]] = vchg_mem[offs + 4 + wrlen]; /* checkpoint variable */ -#endif - while (offs) { - unsigned char val; - uint32_t time_delta, rcv; - next_offs = fstGetUint32(vchg_mem + offs); - offs += 4; - - time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen); - val = vchg_mem[offs + wrlen]; - offs = next_offs; - - switch (val) { - case '0': - case '1': - rcv = ((val & 1) << 1) | (time_delta << 2); - break; /* pack more delta bits in for 0/1 vchs */ - - case 'x': - case 'X': - rcv = FST_RCV_X | (time_delta << 4); - break; - case 'z': - case 'Z': - rcv = FST_RCV_Z | (time_delta << 4); - break; - case 'h': - case 'H': - rcv = FST_RCV_H | (time_delta << 4); - break; - case 'u': - case 'U': - rcv = FST_RCV_U | (time_delta << 4); - break; - case 'w': - case 'W': - rcv = FST_RCV_W | (time_delta << 4); - break; - case 'l': - case 'L': - rcv = FST_RCV_L | (time_delta << 4); - break; - default: - rcv = FST_RCV_D | (time_delta << 4); - break; - } - - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, rcv); - } - } else { - /* variable length */ - /* fstGetUint32 (next_offs) + fstGetVarint32 (time_delta) + fstGetVarint32 (len) + payload */ - unsigned char *pnt; - uint32_t record_len; - uint32_t time_delta; - - while (offs) { - next_offs = fstGetUint32(vchg_mem + offs); - offs += 4; - pnt = vchg_mem + offs; - offs = next_offs; - time_delta = fstGetVarint32(pnt, (int *)&wrlen); - pnt += wrlen; - record_len = fstGetVarint32(pnt, (int *)&wrlen); - pnt += wrlen; - - scratchpnt -= record_len; - memcpy(scratchpnt, pnt, record_len); - - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, record_len); - scratchpnt = fstCopyVarint32ToLeft( - scratchpnt, (time_delta << 1)); /* reserve | 1 case for future expansion */ - } - } - } else { - wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ -#ifndef FST_REMOVE_DUPLICATE_VC - memcpy(xc->curval_mem + vm4ip[0], vchg_mem + offs + 4 + wrlen, vm4ip[1]); /* checkpoint variable */ -#endif - while (offs) { - unsigned int idx; - char is_binary = 1; - unsigned char *pnt; - uint32_t time_delta; - - next_offs = fstGetUint32(vchg_mem + offs); - offs += 4; - - time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen); - - pnt = vchg_mem + offs + wrlen; - offs = next_offs; - - for (idx = 0; idx < vm4ip[1]; idx++) { - if ((pnt[idx] == '0') || (pnt[idx] == '1')) { - continue; - } else { - is_binary = 0; - break; - } - } - - if (is_binary) { - unsigned char acc = 0; - /* new algorithm */ - idx = ((vm4ip[1] + 7) & ~7); - switch (vm4ip[1] & 7) { - case 0: - do { - acc = (pnt[idx + 7 - 8] & 1) << 0; /* fallthrough */ - case 7: - acc |= (pnt[idx + 6 - 8] & 1) << 1; /* fallthrough */ - case 6: - acc |= (pnt[idx + 5 - 8] & 1) << 2; /* fallthrough */ - case 5: - acc |= (pnt[idx + 4 - 8] & 1) << 3; /* fallthrough */ - case 4: - acc |= (pnt[idx + 3 - 8] & 1) << 4; /* fallthrough */ - case 3: - acc |= (pnt[idx + 2 - 8] & 1) << 5; /* fallthrough */ - case 2: - acc |= (pnt[idx + 1 - 8] & 1) << 6; /* fallthrough */ - case 1: - acc |= (pnt[idx + 0 - 8] & 1) << 7; - *(--scratchpnt) = acc; - idx -= 8; - } while (idx); - } - - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); - } else { - scratchpnt -= vm4ip[1]; - memcpy(scratchpnt, pnt, vm4ip[1]); - - scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1) | 1); - } - } - } - - wrlen = scratchpad + xc->vchg_siz - scratchpnt; - unc_memreq += wrlen; - if (wrlen > 32) { - unsigned long destlen = wrlen; - unsigned char *dmem; - unsigned int rc; - - if (!xc->fastpack) { - if (wrlen <= packmemlen) { - dmem = packmem; - } else { - free(packmem); - dmem = packmem = (unsigned char *)malloc(compressBound(packmemlen = wrlen)); - } - - rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4); - if (rc == Z_OK) { -#ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, destlen, NULL); - if (*pv) { - uint32_t pvi = (intptr_t)(*pv); - vm4ip[2] = -pvi; - } else { - *pv = (void *)(intptr_t)(i + 1); -#endif - fpos += fstWriterVarint(f, wrlen); - fpos += destlen; - fstFwrite(dmem, destlen, 1, f); -#ifndef FST_DYNAMIC_ALIAS_DISABLE - } -#endif - } else { -#ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); - if (*pv) { - uint32_t pvi = (intptr_t)(*pv); - vm4ip[2] = -pvi; - } else { - *pv = (void *)(intptr_t)(i + 1); -#endif - fpos += fstWriterVarint(f, 0); - fpos += wrlen; - fstFwrite(scratchpnt, wrlen, 1, f); -#ifndef FST_DYNAMIC_ALIAS_DISABLE - } -#endif - } - } else { - /* this is extremely conservative: fastlz needs +5% for worst case, lz4 needs siz+(siz/255)+16 */ - if (((wrlen * 2) + 2) <= packmemlen) { - dmem = packmem; - } else { - free(packmem); - dmem = packmem = (unsigned char *)malloc(packmemlen = (wrlen * 2) + 2); - } - - rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) - : fastlz_compress(scratchpnt, wrlen, dmem); - if (rc < destlen) { -#ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, rc, NULL); - if (*pv) { - uint32_t pvi = (intptr_t)(*pv); - vm4ip[2] = -pvi; - } else { - *pv = (void *)(intptr_t)(i + 1); -#endif - fpos += fstWriterVarint(f, wrlen); - fpos += rc; - fstFwrite(dmem, rc, 1, f); -#ifndef FST_DYNAMIC_ALIAS_DISABLE - } -#endif - } else { -#ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); - if (*pv) { - uint32_t pvi = (intptr_t)(*pv); - vm4ip[2] = -pvi; - } else { - *pv = (void *)(intptr_t)(i + 1); -#endif - fpos += fstWriterVarint(f, 0); - fpos += wrlen; - fstFwrite(scratchpnt, wrlen, 1, f); -#ifndef FST_DYNAMIC_ALIAS_DISABLE - } -#endif - } - } - } else { -#ifndef FST_DYNAMIC_ALIAS_DISABLE - PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); - if (*pv) { - uint32_t pvi = (intptr_t)(*pv); - vm4ip[2] = -pvi; - } else { - *pv = (void *)(intptr_t)(i + 1); -#endif - fpos += fstWriterVarint(f, 0); - fpos += wrlen; - fstFwrite(scratchpnt, wrlen, 1, f); -#ifndef FST_DYNAMIC_ALIAS_DISABLE - } -#endif - } - - /* vm4ip[3] = 0; ...redundant with clearing below */ -#ifdef FST_DEBUG - cnt++; -#endif - } - } - -#ifndef FST_DYNAMIC_ALIAS_DISABLE - JudyHSFreeArray(&PJHSArray, NULL); -#endif - - free(packmem); - packmem = NULL; /* packmemlen = 0; */ /* scan-build */ - - prevpos = 0; - zerocnt = 0; - free(scratchpad); - scratchpad = NULL; - - indxpos = ftello(f); - xc->secnum++; - -#ifndef FST_DYNAMIC_ALIAS2_DISABLE - if (1) { - uint32_t prev_alias = 0; - - for (i = 0; i < xc->maxhandle; i++) { - vm4ip = &(xc->valpos_mem[4 * i]); - - if (vm4ip[2]) { - if (zerocnt) { - fpos += fstWriterVarint(f, (zerocnt << 1)); - zerocnt = 0; - } - - if (vm4ip[2] & 0x80000000) { - if (vm4ip[2] != prev_alias) { - fpos += fstWriterSVarint(f, (((int64_t)((int32_t)(prev_alias = vm4ip[2]))) << 1) | 1); - } else { - fpos += fstWriterSVarint(f, (0 << 1) | 1); - } - } else { - fpos += fstWriterSVarint(f, ((vm4ip[2] - prevpos) << 1) | 1); - prevpos = vm4ip[2]; - } - vm4ip[2] = 0; - vm4ip[3] = 0; /* clear out tchn idx */ - } else { - zerocnt++; - } - } - } else -#endif - { - for (i = 0; i < xc->maxhandle; i++) { - vm4ip = &(xc->valpos_mem[4 * i]); - - if (vm4ip[2]) { - if (zerocnt) { - fpos += fstWriterVarint(f, (zerocnt << 1)); - zerocnt = 0; - } - - if (vm4ip[2] & 0x80000000) { - fpos += fstWriterVarint(f, 0); /* signal, note that using a *signed* varint would be more efficient - than this byte escape! */ - fpos += fstWriterVarint(f, (-(int32_t)vm4ip[2])); - } else { - fpos += fstWriterVarint(f, ((vm4ip[2] - prevpos) << 1) | 1); - prevpos = vm4ip[2]; - } - vm4ip[2] = 0; - vm4ip[3] = 0; /* clear out tchn idx */ - } else { - zerocnt++; - } - } - } - - if (zerocnt) { - /* fpos += */ fstWriterVarint(f, (zerocnt << 1)); /* scan-build */ - } -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "value chains: %d\n", cnt); -#endif - - xc->vchg_mem[0] = '!'; - xc->vchg_siz = 1; - - endpos = ftello(xc->handle); - fstWriterUint64(xc->handle, endpos - indxpos); /* write delta index position at very end of block */ - - /*emit time changes for block */ - fflush(xc->tchn_handle); - tlen = ftello(xc->tchn_handle); - fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); - - errno = 0; - fstWriterMmapSanity( - tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0), - __FILE__, __LINE__, "tmem"); - if (tmem) { - unsigned long destlen = tlen; - unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen)); - int rc = compress2(dmem, &destlen, tmem, tlen, 9); - - if ((rc == Z_OK) && (((fst_off_t)destlen) < tlen)) { - fstFwrite(dmem, destlen, 1, xc->handle); - } else /* comparison between compressed / decompressed len tells if compressed */ - { - fstFwrite(tmem, tlen, 1, xc->handle); - destlen = tlen; - } - free(dmem); - fstMunmap(tmem, tlen); - fstWriterUint64(xc->handle, tlen); /* uncompressed */ - fstWriterUint64(xc->handle, destlen); /* compressed */ - fstWriterUint64(xc->handle, xc->tchn_cnt); /* number of time items */ - } - - xc->tchn_cnt = xc->tchn_idx = 0; - fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); - fstFtruncate(fileno(xc->tchn_handle), 0); - - /* write block trailer */ - endpos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, xc->section_start, SEEK_SET); - fstWriterUint64(xc->handle, endpos - xc->section_start); /* write block length */ - fstWriterFseeko(xc, xc->handle, 8, SEEK_CUR); /* skip begin time */ - fstWriterUint64(xc->handle, xc->curtime); /* write end time for section */ - fstWriterUint64(xc->handle, unc_memreq); /* amount of buffer memory required in reader for full traversal */ - fflush(xc->handle); - - fstWriterFseeko(xc, xc->handle, xc->section_start - 1, SEEK_SET); /* write out FST_BL_VCDATA over FST_BL_SKIP */ - -#ifndef FST_DYNAMIC_ALIAS_DISABLE -#ifndef FST_DYNAMIC_ALIAS2_DISABLE - fputc(FST_BL_VCDATA_DYN_ALIAS2, xc->handle); -#else - fputc(FST_BL_VCDATA_DYN_ALIAS, xc->handle); -#endif -#else - fputc(FST_BL_VCDATA, xc->handle); -#endif - - fflush(xc->handle); - - fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET); /* seek to end of file */ - - xc2->section_header_truncpos = endpos; /* cache in case of need to truncate */ - if (xc->dump_size_limit) { - if (endpos >= ((fst_off_t)xc->dump_size_limit)) { - xc2->skip_writing_section_hdr = 1; - xc2->size_limit_locked = 1; - xc2->is_initial_time = 1; /* to trick emit value and emit time change */ -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "<< dump file size limit reached, stopping dumping >>\n"); -#endif - } - } - - if (!xc2->skip_writing_section_hdr) { - fstWriterEmitSectionHeader(xc); /* emit next section header */ - } - fflush(xc->handle); - - xc->already_in_flush = 0; -} - -#ifdef FST_WRITER_PARALLEL -static void *fstWriterFlushContextPrivate1(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - struct fstWriterContext *xc_parent; - - pthread_mutex_lock(&(xc->xc_parent->mutex)); - fstWriterFlushContextPrivate2(xc); - -#ifdef FST_REMOVE_DUPLICATE_VC - free(xc->curval_mem); -#endif - free(xc->valpos_mem); - free(xc->vchg_mem); - tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); - xc_parent = xc->xc_parent; - free(xc); - - xc_parent->in_pthread = 0; - pthread_mutex_unlock(&(xc_parent->mutex)); - - return (NULL); -} - -static void fstWriterFlushContextPrivate(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - if (xc->parallel_enabled) { - struct fstWriterContext *xc2 = (struct fstWriterContext *)malloc(sizeof(struct fstWriterContext)); - unsigned int i; - - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); - - xc->xc_parent = xc; - memcpy(xc2, xc, sizeof(struct fstWriterContext)); - - xc2->valpos_mem = (uint32_t *)malloc(xc->maxhandle * 4 * sizeof(uint32_t)); - memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); - - /* curval mem is updated in the thread */ -#ifdef FST_REMOVE_DUPLICATE_VC - xc2->curval_mem = (unsigned char *)malloc(xc->maxvalpos); - memcpy(xc2->curval_mem, xc->curval_mem, xc->maxvalpos); -#endif - - xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz); - xc->vchg_mem[0] = '!'; - xc->vchg_siz = 1; - - for (i = 0; i < xc->maxhandle; i++) { - uint32_t *vm4ip = &(xc->valpos_mem[4 * i]); - vm4ip[2] = 0; /* zero out offset val */ - vm4ip[3] = 0; /* zero out last time change val */ - } - - xc->tchn_cnt = xc->tchn_idx = 0; - xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* child thread will deallocate file/name */ - fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); - fstFtruncate(fileno(xc->tchn_handle), 0); - - xc->section_header_only = 0; - xc->secnum++; - - while (xc->in_pthread) { - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); - }; - - pthread_mutex_lock(&xc->mutex); - xc->in_pthread = 1; - pthread_mutex_unlock(&xc->mutex); - - pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2); - } else { - if (xc->parallel_was_enabled) /* conservatively block */ - { - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); - } - - xc->xc_parent = xc; - fstWriterFlushContextPrivate2(xc); - } -} -#endif - -/* - * queues up a flush context operation - */ -void fstWriterFlushContext(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - if (xc->tchn_idx > 1) { - xc->flush_context_pending = 1; - } - } -} - -/* - * close out FST file - */ -void fstWriterClose(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - -#ifdef FST_WRITER_PARALLEL - if (xc) { - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); - } -#endif - - if (xc && !xc->already_in_close && !xc->already_in_flush) { - unsigned char *tmem = NULL; - fst_off_t fixup_offs, tlen, hlen; - - xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */ - - if (xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time)) { - fstFtruncate(fileno(xc->handle), xc->section_header_truncpos); - fstWriterFseeko(xc, xc->handle, xc->section_header_truncpos, SEEK_SET); - xc->section_header_only = 0; - } else { - xc->skip_writing_section_hdr = 1; - if (!xc->size_limit_locked) { - if (FST_UNLIKELY(xc->is_initial_time)) /* simulation time never advanced so mock up the changes as time - zero ones */ - { - fstHandle dupe_idx; - - fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */ - for (dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */ - { - fstWriterEmitValueChange(xc, dupe_idx + 1, xc->curval_mem + xc->valpos_mem[4 * dupe_idx]); - } - } - fstWriterFlushContextPrivate(xc); -#ifdef FST_WRITER_PARALLEL - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); - - while (xc->in_pthread) { - pthread_mutex_lock(&xc->mutex); - pthread_mutex_unlock(&xc->mutex); - }; -#endif - } - } - fstDestroyMmaps(xc, 1); - if (xc->outval_mem) { - free(xc->outval_mem); - xc->outval_mem = NULL; - xc->outval_alloc_siz = 0; - } - - /* write out geom section */ - fflush(xc->geom_handle); - tlen = ftello(xc->geom_handle); - errno = 0; - if (tlen) { - fstWriterMmapSanity(tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ | PROT_WRITE, MAP_SHARED, - fileno(xc->geom_handle), 0), - __FILE__, __LINE__, "tmem"); - } - - if (tmem) { - unsigned long destlen = tlen; - unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen)); - int rc = compress2(dmem, &destlen, tmem, tlen, 9); - - if ((rc != Z_OK) || (((fst_off_t)destlen) > tlen)) { - destlen = tlen; - } - - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - fstWriterUint64(xc->handle, destlen + 24); /* section length */ - fstWriterUint64(xc->handle, tlen); /* uncompressed */ - /* compressed len is section length - 24 */ - fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */ - fstFwrite((((fst_off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle); - fflush(xc->handle); - - fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); - fputc(FST_BL_GEOM, xc->handle); /* actual tag */ - - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); - - free(dmem); - fstMunmap(tmem, tlen); - } - - if (xc->num_blackouts) { - uint64_t cur_bl = 0; - fst_off_t bpos, eos; - uint32_t i; - - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - bpos = fixup_offs + 1; - fstWriterUint64(xc->handle, 0); /* section length */ - fstWriterVarint(xc->handle, xc->num_blackouts); - - for (i = 0; i < xc->num_blackouts; i++) { - fputc(xc->blackout_head->active, xc->handle); - fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl); - cur_bl = xc->blackout_head->tim; - xc->blackout_curr = xc->blackout_head->next; - free(xc->blackout_head); - xc->blackout_head = xc->blackout_curr; - } - - eos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, bpos, SEEK_SET); - fstWriterUint64(xc->handle, eos - bpos); - fflush(xc->handle); - - fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); - fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */ - - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); - } - - if (xc->compress_hier) { - fst_off_t hl, eos; - gzFile zhandle; - int zfd; - int fourpack_duo = 0; -#ifndef __MINGW32__ - char *fnam = (char *)malloc(strlen(xc->filename) + 5 + 1); -#endif - - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - hlen = ftello(xc->handle); - fstWriterUint64(xc->handle, 0); /* section length */ - fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */ - - if (!xc->fourpack) { - unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN); - zfd = dup(fileno(xc->handle)); - fflush(xc->handle); - zhandle = gzdopen(zfd, "wb4"); - if (zhandle) { - fstWriterFseeko(xc, xc->hier_handle, 0, SEEK_SET); - for (hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN) { - unsigned len = - ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl); - fstFread(mem, len, 1, xc->hier_handle); - gzwrite(zhandle, mem, len); - } - gzclose(zhandle); - } else { - close(zfd); - } - free(mem); - } else { - int lz4_maxlen; - unsigned char *mem; - unsigned char *hmem = NULL; - int packed_len; - - fflush(xc->handle); - - lz4_maxlen = LZ4_compressBound(xc->hier_file_len); - mem = (unsigned char *)malloc(lz4_maxlen); - errno = 0; - if (xc->hier_file_len) { - fstWriterMmapSanity(hmem = (unsigned char *)fstMmap(NULL, xc->hier_file_len, PROT_READ | PROT_WRITE, - MAP_SHARED, fileno(xc->hier_handle), 0), - __FILE__, __LINE__, "hmem"); - } - packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len); - fstMunmap(hmem, xc->hier_file_len); - - fourpack_duo = - (!xc->repack_on_close) && - (xc->hier_file_len > FST_HDR_FOURPACK_DUO_SIZE); /* double pack when hierarchy is large */ - - if (fourpack_duo) /* double packing with LZ4 is faster than gzip */ - { - unsigned char *mem_duo; - int lz4_maxlen_duo; - int packed_len_duo; - - lz4_maxlen_duo = LZ4_compressBound(packed_len); - mem_duo = (unsigned char *)malloc(lz4_maxlen_duo); - packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len); - - fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */ - fstFwrite(mem_duo, packed_len_duo, 1, xc->handle); - free(mem_duo); - } else { - fstFwrite(mem, packed_len, 1, xc->handle); - } - - free(mem); - } - - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); - eos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, hlen, SEEK_SET); - fstWriterUint64(xc->handle, eos - hlen); - fflush(xc->handle); - - fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); - fputc(xc->fourpack ? (fourpack_duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4) : FST_BL_HIER, - xc->handle); /* actual tag now also == compression type */ - - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); - -#ifndef __MINGW32__ - sprintf(fnam, "%s.hier", xc->filename); - unlink(fnam); - free(fnam); -#endif - } - - /* finalize out header */ - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); - fstWriterUint64(xc->handle, xc->firsttime); - fstWriterUint64(xc->handle, xc->curtime); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET); - fstWriterUint64(xc->handle, xc->numscopes); - fstWriterUint64(xc->handle, xc->numsigs); - fstWriterUint64(xc->handle, xc->maxhandle); - fstWriterUint64(xc->handle, xc->secnum); - fflush(xc->handle); - - tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); - free(xc->vchg_mem); - xc->vchg_mem = NULL; - tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam); - tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam); - tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam); - if (xc->hier_handle) { - fclose(xc->hier_handle); - xc->hier_handle = NULL; - } - if (xc->handle) { - if (xc->repack_on_close) { - FILE *fp; - fst_off_t offpnt, uclen; - int flen = strlen(xc->filename); - char *hf = (char *)calloc(1, flen + 5); - - strcpy(hf, xc->filename); - strcpy(hf + flen, ".pak"); - fp = fopen(hf, "wb"); - - if (fp) { - gzFile dsth; - int zfd; - char gz_membuf[FST_GZIO_LEN]; - - fstWriterFseeko(xc, xc->handle, 0, SEEK_END); - uclen = ftello(xc->handle); - - fputc(FST_BL_ZWRAPPER, fp); - fstWriterUint64(fp, 0); - fstWriterUint64(fp, uclen); - fflush(fp); - - fstWriterFseeko(xc, xc->handle, 0, SEEK_SET); - zfd = dup(fileno(fp)); - dsth = gzdopen(zfd, "wb4"); - if (dsth) { - for (offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) { - size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); - fstFread(gz_membuf, this_len, 1, xc->handle); - gzwrite(dsth, gz_membuf, this_len); - } - gzclose(dsth); - } else { - close(zfd); - } - fstWriterFseeko(xc, fp, 0, SEEK_END); - offpnt = ftello(fp); - fstWriterFseeko(xc, fp, 1, SEEK_SET); - fstWriterUint64(fp, offpnt - 1); - fclose(fp); - fclose(xc->handle); - xc->handle = NULL; - - unlink(xc->filename); - rename(hf, xc->filename); - } else { - xc->repack_on_close = 0; - fclose(xc->handle); - xc->handle = NULL; - } - - free(hf); - } else { - fclose(xc->handle); - xc->handle = NULL; - } - } - -#ifdef __MINGW32__ - { - int flen = strlen(xc->filename); - char *hf = (char *)calloc(1, flen + 6); - strcpy(hf, xc->filename); - - if (xc->compress_hier) { - strcpy(hf + flen, ".hier"); - unlink(hf); /* no longer needed as a section now exists for this */ - } - - free(hf); - } -#endif - -#ifdef FST_WRITER_PARALLEL - pthread_mutex_destroy(&xc->mutex); - pthread_attr_destroy(&xc->thread_attr); -#endif - - if (xc->path_array) { -#ifndef _WAVE_HAVE_JUDY - const uint32_t hashmask = FST_PATH_HASHMASK; -#endif - JudyHSFreeArray(&(xc->path_array), NULL); - } - - free(xc->filename); - xc->filename = NULL; - free(xc); - } -} - -/* - * functions to set miscellaneous header/block information - */ -void fstWriterSetDate(void *ctx, const char *dat) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - char s[FST_HDR_DATE_SIZE]; - fst_off_t fpos = ftello(xc->handle); - int len = strlen(dat); - - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_DATE, SEEK_SET); - memset(s, 0, FST_HDR_DATE_SIZE); - memcpy(s, dat, (len < FST_HDR_DATE_SIZE) ? len : FST_HDR_DATE_SIZE); - fstFwrite(s, FST_HDR_DATE_SIZE, 1, xc->handle); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } -} - -void fstWriterSetVersion(void *ctx, const char *vers) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc && vers) { - char s[FST_HDR_SIM_VERSION_SIZE]; - fst_off_t fpos = ftello(xc->handle); - int len = strlen(vers); - - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET); - memset(s, 0, FST_HDR_SIM_VERSION_SIZE); - memcpy(s, vers, (len < FST_HDR_SIM_VERSION_SIZE) ? len : FST_HDR_SIM_VERSION_SIZE); - fstFwrite(s, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } -} - -void fstWriterSetFileType(void *ctx, enum fstFileType filetype) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - if (/*(filetype >= FST_FT_MIN) &&*/ (filetype <= FST_FT_MAX)) { - fst_off_t fpos = ftello(xc->handle); - - xc->filetype = filetype; - - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_FILETYPE, SEEK_SET); - fputc(xc->filetype, xc->handle); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } - } -} - -static void fstWriterSetAttrDoubleArgGeneric(void *ctx, int typ, uint64_t arg1, uint64_t arg2) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - unsigned char buf[11]; /* ceil(64/7) = 10 + null term */ - unsigned char *pnt = fstCopyVarint64ToRight(buf, arg1); - if (arg1) { - *pnt = 0; /* this converts any *nonzero* arg1 when made a varint into a null-term string */ - } - - fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, (char *)buf, arg2); - } -} - -static void fstWriterSetAttrGeneric(void *ctx, const char *comm, int typ, uint64_t arg) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc && comm) { - char *s = strdup(comm); - char *sf = s; - - while (*s) { - if ((*s == '\n') || (*s == '\r')) - *s = ' '; - s++; - } - - fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, sf, arg); - free(sf); - } -} - -static void fstWriterSetSourceStem_2(void *ctx, const char *path, unsigned int line, unsigned int use_realpath, int typ) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - if (xc && path && path[0]) { - uint64_t sidx = 0; - int slen = strlen(path); -#ifndef _WAVE_HAVE_JUDY - const uint32_t hashmask = FST_PATH_HASHMASK; - const unsigned char *path2 = (const unsigned char *)path; - PPvoid_t pv; -#else - char *path2 = (char *)alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */ - PPvoid_t pv; - strcpy(path2, path); -#endif - - pv = JudyHSIns(&(xc->path_array), path2, slen, NULL); - if (*pv) { - sidx = (intptr_t)(*pv); - } else { - char *rp = NULL; - - sidx = ++xc->path_array_count; - *pv = (void *)(intptr_t)(xc->path_array_count); - - if (use_realpath) { - rp = fstRealpath( -#ifndef _WAVE_HAVE_JUDY - (const char *) -#endif - path2, - NULL); - } - - fstWriterSetAttrGeneric(xc, - rp ? rp : -#ifndef _WAVE_HAVE_JUDY - (const char *) -#endif - path2, - FST_MT_PATHNAME, sidx); - - if (rp) { - free(rp); - } - } - - fstWriterSetAttrDoubleArgGeneric(xc, typ, sidx, line); - } -} - -void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath) -{ - fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCESTEM); -} - -void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath) -{ - fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCEISTEM); -} - -void fstWriterSetComment(void *ctx, const char *comm) { fstWriterSetAttrGeneric(ctx, comm, FST_MT_COMMENT, 0); } - -void fstWriterSetValueList(void *ctx, const char *vl) { fstWriterSetAttrGeneric(ctx, vl, FST_MT_VALUELIST, 0); } - -void fstWriterSetEnvVar(void *ctx, const char *envvar) { fstWriterSetAttrGeneric(ctx, envvar, FST_MT_ENVVAR, 0); } - -void fstWriterSetTimescale(void *ctx, int ts) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - fst_off_t fpos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET); - fputc(ts & 255, xc->handle); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } -} - -void fstWriterSetTimescaleFromString(void *ctx, const char *s) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc && s) { - int mat = 0; - int seconds_exp = -9; - int tv = atoi(s); - const char *pnt = s; - - while (*pnt) { - switch (*pnt) { - case 'm': - seconds_exp = -3; - mat = 1; - break; - case 'u': - seconds_exp = -6; - mat = 1; - break; - case 'n': - seconds_exp = -9; - mat = 1; - break; - case 'p': - seconds_exp = -12; - mat = 1; - break; - case 'f': - seconds_exp = -15; - mat = 1; - break; - case 'a': - seconds_exp = -18; - mat = 1; - break; - case 'z': - seconds_exp = -21; - mat = 1; - break; - case 's': - seconds_exp = 0; - mat = 1; - break; - default: - break; - } - - if (mat) - break; - pnt++; - } - - if (tv == 10) { - seconds_exp++; - } else if (tv == 100) { - seconds_exp += 2; - } - - fstWriterSetTimescale(ctx, seconds_exp); - } -} - -void fstWriterSetTimezero(void *ctx, int64_t tim) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - fst_off_t fpos = ftello(xc->handle); - fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET); - fstWriterUint64(xc->handle, (xc->timezero = tim)); - fflush(xc->handle); - fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); - } -} - -void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - xc->fastpack = (typ != FST_WR_PT_ZLIB); - xc->fourpack = (typ == FST_WR_PT_LZ4); - } -} - -void fstWriterSetRepackOnClose(void *ctx, int enable) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - xc->repack_on_close = (enable != 0); - } -} - -void fstWriterSetParallelMode(void *ctx, int enable) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - xc->parallel_was_enabled |= xc->parallel_enabled; /* make sticky */ - xc->parallel_enabled = (enable != 0); -#ifndef FST_WRITER_PARALLEL - if (xc->parallel_enabled) { - fprintf(stderr, FST_APIMESS - "fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n"); - exit(255); - } -#endif - } -} - -void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - xc->dump_size_limit = numbytes; - } -} - -int fstWriterGetDumpSizeLimitReached(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - return (xc->size_limit_locked != 0); - } - - return (0); -} - -int fstWriterGetFseekFailed(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc) { - return (xc->fseek_failed != 0); - } - - return (0); -} - -/* - * writer attr/scope/var creation: - * fstWriterCreateVar2() is used to dump VHDL or other languages, but the - * underlying variable needs to map to Verilog/SV via the proper fstVarType vt - */ -fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam, - fstHandle aliasHandle, const char *type, enum fstSupplementalVarType svt, - enum fstSupplementalDataType sdt) -{ - fstWriterSetAttrGeneric(ctx, type ? type : "", FST_MT_SUPVAR, - (svt << FST_SDT_SVT_SHIFT_COUNT) | (sdt & FST_SDT_ABS_MAX)); - return (fstWriterCreateVar(ctx, vt, vd, len, nam, aliasHandle)); -} - -fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam, - fstHandle aliasHandle) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - unsigned int i; - int nlen, is_real; - - if (xc && nam) { - if (xc->valpos_mem) { - fstDestroyMmaps(xc, 0); - } - - fputc(vt, xc->hier_handle); - fputc(vd, xc->hier_handle); - nlen = strlen(nam); - fstFwrite(nam, nlen, 1, xc->hier_handle); - fputc(0, xc->hier_handle); - xc->hier_file_len += (nlen + 3); - - if ((vt == FST_VT_VCD_REAL) || (vt == FST_VT_VCD_REAL_PARAMETER) || (vt == FST_VT_VCD_REALTIME) || - (vt == FST_VT_SV_SHORTREAL)) { - is_real = 1; - len = 8; /* recast number of bytes to that of what a double is */ - } else { - is_real = 0; - if (vt == FST_VT_GEN_STRING) { - len = 0; - } - } - - xc->hier_file_len += fstWriterVarint(xc->hier_handle, len); - - if (aliasHandle > xc->maxhandle) - aliasHandle = 0; - xc->hier_file_len += fstWriterVarint(xc->hier_handle, aliasHandle); - xc->numsigs++; - if (xc->numsigs == xc->next_huge_break) { - if (xc->fst_break_size < xc->fst_huge_break_size) { - xc->next_huge_break += FST_ACTIVATE_HUGE_INC; - xc->fst_break_size += xc->fst_orig_break_size; - xc->fst_break_add_size += xc->fst_orig_break_add_size; - - xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; - if (xc->vchg_mem) { - xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz); - } - } - } - - if (!aliasHandle) { - uint32_t zero = 0; - - if (len) { - fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */ - } else { - fstWriterVarint(xc->geom_handle, 0xFFFFFFFF); /* geom section encodes zero len as 32b -1 */ - } - - fstFwrite(&xc->maxvalpos, sizeof(uint32_t), 1, xc->valpos_handle); - fstFwrite(&len, sizeof(uint32_t), 1, xc->valpos_handle); - fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle); - fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle); - - if (!is_real) { - for (i = 0; i < len; i++) { - fputc('x', xc->curval_handle); - } - } else { - fstFwrite(&xc->nan, 8, 1, xc->curval_handle); /* initialize doubles to NaN rather than x */ - } - - xc->maxvalpos += len; - xc->maxhandle++; - return (xc->maxhandle); - } else { - return (aliasHandle); - } - } - - return (0); -} - -void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, const char *scopename, const char *scopecomp) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - if (xc) { - fputc(FST_ST_VCD_SCOPE, xc->hier_handle); - if (/*(scopetype < FST_ST_VCD_MODULE) ||*/ (scopetype > FST_ST_MAX)) { - scopetype = FST_ST_VCD_MODULE; - } - fputc(scopetype, xc->hier_handle); - fprintf(xc->hier_handle, "%s%c%s%c", scopename ? scopename : "", 0, scopecomp ? scopecomp : "", 0); - - if (scopename) { - xc->hier_file_len += strlen(scopename); - } - if (scopecomp) { - xc->hier_file_len += strlen(scopecomp); - } - - xc->hier_file_len += 4; /* FST_ST_VCD_SCOPE + scopetype + two string terminating zeros */ - xc->numscopes++; - } -} - -void fstWriterSetUpscope(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - if (xc) { - fputc(FST_ST_VCD_UPSCOPE, xc->hier_handle); - xc->hier_file_len++; - } -} - -void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, const char *attrname, uint64_t arg) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - if (xc) { - fputc(FST_ST_GEN_ATTRBEGIN, xc->hier_handle); - if (/*(attrtype < FST_AT_MISC) ||*/ (attrtype > FST_AT_MAX)) { - attrtype = FST_AT_MISC; - subtype = FST_MT_UNKNOWN; - } - fputc(attrtype, xc->hier_handle); - - switch (attrtype) { - case FST_AT_ARRAY: - if ((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) - subtype = FST_AR_NONE; - break; - case FST_AT_ENUM: - if ((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) - subtype = FST_EV_SV_INTEGER; - break; - case FST_AT_PACK: - if ((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) - subtype = FST_PT_NONE; - break; - - case FST_AT_MISC: - default: - break; - } - - fputc(subtype, xc->hier_handle); - fprintf(xc->hier_handle, "%s%c", attrname ? attrname : "", 0); - - if (attrname) { - xc->hier_file_len += strlen(attrname); - } - - xc->hier_file_len += 4; /* FST_ST_GEN_ATTRBEGIN + type + subtype + string terminating zero */ - xc->hier_file_len += fstWriterVarint(xc->hier_handle, arg); - } -} - -void fstWriterSetAttrEnd(void *ctx) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - if (xc) { - fputc(FST_ST_GEN_ATTREND, xc->hier_handle); - xc->hier_file_len++; - } -} - -fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, - const char **literal_arr, const char **val_arr) -{ - fstEnumHandle handle = 0; - unsigned int *literal_lens = NULL; - unsigned int *val_lens = NULL; - int lit_len_tot = 0; - int val_len_tot = 0; - int name_len; - char elem_count_buf[16]; - int elem_count_len; - int total_len; - int pos = 0; - char *attr_str = NULL; - - if (ctx && name && literal_arr && val_arr && (elem_count != 0)) { - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - uint32_t i; - - name_len = strlen(name); - elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count); - - literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int)); - val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int)); - - for (i = 0; i < elem_count; i++) { - literal_lens[i] = strlen(literal_arr[i]); - lit_len_tot += fstUtilityBinToEscConvertedLen((unsigned char *)literal_arr[i], literal_lens[i]); - - val_lens[i] = strlen(val_arr[i]); - val_len_tot += fstUtilityBinToEscConvertedLen((unsigned char *)val_arr[i], val_lens[i]); - - if (min_valbits > 0) { - if (val_lens[i] < min_valbits) { - val_len_tot += (min_valbits - val_lens[i]); /* additional converted len is same for '0' character */ - } - } - } - - total_len = name_len + 1 + elem_count_len + 1 + lit_len_tot + elem_count + val_len_tot + elem_count; - - attr_str = (char *)malloc(total_len); - pos = 0; - - memcpy(attr_str + pos, name, name_len); - pos += name_len; - attr_str[pos++] = ' '; - - memcpy(attr_str + pos, elem_count_buf, elem_count_len); - pos += elem_count_len; - attr_str[pos++] = ' '; - - for (i = 0; i < elem_count; i++) { - pos += fstUtilityBinToEsc((unsigned char *)attr_str + pos, (unsigned char *)literal_arr[i], - literal_lens[i]); - attr_str[pos++] = ' '; - } - - for (i = 0; i < elem_count; i++) { - if (min_valbits > 0) { - if (val_lens[i] < min_valbits) { - memset(attr_str + pos, '0', min_valbits - val_lens[i]); - pos += (min_valbits - val_lens[i]); - } - } - - pos += fstUtilityBinToEsc((unsigned char *)attr_str + pos, (unsigned char *)val_arr[i], val_lens[i]); - attr_str[pos++] = ' '; - } - - attr_str[pos - 1] = 0; - -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "fstWriterCreateEnumTable() total_len: %d, pos: %d\n", total_len, pos); - fprintf(stderr, FST_APIMESS "*%s*\n", attr_str); -#endif - - fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, attr_str, handle = ++xc->max_enumhandle); - - free(attr_str); - free(val_lens); - free(literal_lens); - } - - return (handle); -} - -void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (xc && handle) { - fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, NULL, handle); - } -} - -/* - * value and time change emission - */ -void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - const unsigned char *buf = (const unsigned char *)val; - uint32_t offs; - int len; - - if (FST_LIKELY((xc) && (handle <= xc->maxhandle))) { - uint32_t fpos; - uint32_t *vm4ip; - - if (FST_UNLIKELY(!xc->valpos_mem)) { - xc->vc_emitted = 1; - fstWriterCreateMmaps(xc); - } - - handle--; /* move starting at 1 index to starting at 0 */ - vm4ip = &(xc->valpos_mem[4 * handle]); - - len = vm4ip[1]; - if (FST_LIKELY(len)) /* len of zero = variable length, use fstWriterEmitVariableLengthValueChange */ - { - if (FST_LIKELY(!xc->is_initial_time)) { - fpos = xc->vchg_siz; - - if (FST_UNLIKELY((fpos + len + 10) > xc->vchg_alloc_siz)) { - xc->vchg_alloc_siz += - (xc->fst_break_add_size + - len); /* +len added in the case of extremely long vectors and small break add sizes */ - xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz); - if (FST_UNLIKELY(!xc->vchg_mem)) { - fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitValueChange, exiting.\n"); - exit(255); - } - } -#ifdef FST_REMOVE_DUPLICATE_VC - offs = vm4ip[0]; - - if (len != 1) { - if ((vm4ip[3] == xc->tchn_idx) && (vm4ip[2])) { - unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */ - while (*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ - } - memcpy(old_value, buf, len); /* overlay new value */ - - memcpy(xc->curval_mem + offs, buf, len); - return; - } else { - if (!memcmp(xc->curval_mem + offs, buf, len)) { - if (!xc->curtime) { - int i; - for (i = 0; i < len; i++) { - if (buf[i] != 'x') - break; - } - - if (i < len) - return; - } else { - return; - } - } - } - - memcpy(xc->curval_mem + offs, buf, len); - } else { - if ((vm4ip[3] == xc->tchn_idx) && (vm4ip[2])) { - unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */ - while (*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ - } - *old_value = *buf; /* overlay new value */ - - *(xc->curval_mem + offs) = *buf; - return; - } else { - if ((*(xc->curval_mem + offs)) == (*buf)) { - if (!xc->curtime) { - if (*buf != 'x') - return; - } else { - return; - } - } - } - - *(xc->curval_mem + offs) = *buf; - } -#endif - xc->vchg_siz += fstWriterUint32WithVarint32(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, - len); /* do one fwrite op only */ - vm4ip[3] = xc->tchn_idx; - vm4ip[2] = fpos; - } else { - offs = vm4ip[0]; - memcpy(xc->curval_mem + offs, buf, len); - } - } - } -} - -void fstWriterEmitValueChange32(void *ctx, fstHandle handle, uint32_t bits, uint32_t val) -{ - char buf[32]; - char *s = buf; - uint32_t i; - for (i = 0; i < bits; ++i) { - *s++ = '0' + ((val >> (bits - i - 1)) & 1); - } - fstWriterEmitValueChange(ctx, handle, buf); -} -void fstWriterEmitValueChange64(void *ctx, fstHandle handle, uint32_t bits, uint64_t val) -{ - char buf[64]; - char *s = buf; - uint32_t i; - for (i = 0; i < bits; ++i) { - *s++ = '0' + ((val >> (bits - i - 1)) & 1); - } - fstWriterEmitValueChange(ctx, handle, buf); -} -void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle, uint32_t bits, const uint32_t *val) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (FST_UNLIKELY(bits <= 32)) { - fstWriterEmitValueChange32(ctx, handle, bits, val[0]); - } else if (FST_LIKELY(xc)) { - int bq = bits / 32; - int br = bits & 31; - int i; - int w; - uint32_t v; - unsigned char *s; - if (FST_UNLIKELY(bits > xc->outval_alloc_siz)) { - xc->outval_alloc_siz = bits * 2 + 1; - xc->outval_mem = (unsigned char *)realloc(xc->outval_mem, xc->outval_alloc_siz); - if (FST_UNLIKELY(!xc->outval_mem)) { - fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitValueChangeVec32, exiting.\n"); - exit(255); - } - } - s = xc->outval_mem; - { - w = bq; - v = val[w]; - for (i = 0; i < br; ++i) { - *s++ = '0' + ((v >> (br - i - 1)) & 1); - } - } - for (w = bq - 1; w >= 0; --w) { - v = val[w]; - for (i = (32 - 4); i >= 0; i -= 4) { - s[0] = '0' + ((v >> (i + 3)) & 1); - s[1] = '0' + ((v >> (i + 2)) & 1); - s[2] = '0' + ((v >> (i + 1)) & 1); - s[3] = '0' + ((v >> (i + 0)) & 1); - s += 4; - } - } - fstWriterEmitValueChange(ctx, handle, xc->outval_mem); - } -} -void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle, uint32_t bits, const uint64_t *val) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - if (FST_UNLIKELY(bits <= 64)) { - fstWriterEmitValueChange64(ctx, handle, bits, val[0]); - } else if (FST_LIKELY(xc)) { - int bq = bits / 64; - int br = bits & 63; - int i; - int w; - uint32_t v; - unsigned char *s; - if (FST_UNLIKELY(bits > xc->outval_alloc_siz)) { - xc->outval_alloc_siz = bits * 2 + 1; - xc->outval_mem = (unsigned char *)realloc(xc->outval_mem, xc->outval_alloc_siz); - if (FST_UNLIKELY(!xc->outval_mem)) { - fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitValueChangeVec64, exiting.\n"); - exit(255); - } - } - s = xc->outval_mem; - { - w = bq; - v = val[w]; - for (i = 0; i < br; ++i) { - *s++ = '0' + ((v >> (br - i - 1)) & 1); - } - } - for (w = bq - 1; w >= 0; --w) { - v = val[w]; - for (i = (64 - 4); i >= 0; i -= 4) { - s[0] = '0' + ((v >> (i + 3)) & 1); - s[1] = '0' + ((v >> (i + 2)) & 1); - s[2] = '0' + ((v >> (i + 1)) & 1); - s[3] = '0' + ((v >> (i + 0)) & 1); - s += 4; - } - } - fstWriterEmitValueChange(ctx, handle, xc->outval_mem); - } -} - -void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - const unsigned char *buf = (const unsigned char *)val; - - if (FST_LIKELY((xc) && (handle <= xc->maxhandle))) { - uint32_t fpos; - uint32_t *vm4ip; - - if (FST_UNLIKELY(!xc->valpos_mem)) { - xc->vc_emitted = 1; - fstWriterCreateMmaps(xc); - } - - handle--; /* move starting at 1 index to starting at 0 */ - vm4ip = &(xc->valpos_mem[4 * handle]); - - /* there is no initial time dump for variable length value changes */ - if (FST_LIKELY(!vm4ip[1])) /* len of zero = variable length */ - { - fpos = xc->vchg_siz; - - if (FST_UNLIKELY((fpos + len + 10 + 5) > xc->vchg_alloc_siz)) { - xc->vchg_alloc_siz += - (xc->fst_break_add_size + len + - 5); /* +len added in the case of extremely long vectors and small break add sizes */ - xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz); - if (FST_UNLIKELY(!xc->vchg_mem)) { - fprintf(stderr, - FST_APIMESS "Could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n"); - exit(255); - } - } - - xc->vchg_siz += fstWriterUint32WithVarint32AndLength(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, - len); /* do one fwrite op only */ - vm4ip[3] = xc->tchn_idx; - vm4ip[2] = fpos; - } - } -} - -void fstWriterEmitTimeChange(void *ctx, uint64_t tim) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - unsigned int i; - int skip = 0; - if (xc) { - if (FST_UNLIKELY(xc->is_initial_time)) { - if (xc->size_limit_locked) /* this resets xc->is_initial_time to one */ - { - return; - } - - if (!xc->valpos_mem) { - fstWriterCreateMmaps(xc); - } - - skip = 1; - - xc->firsttime = (xc->vc_emitted) ? 0 : tim; - xc->curtime = 0; - xc->vchg_mem[0] = '!'; - xc->vchg_siz = 1; - fstWriterEmitSectionHeader(xc); - for (i = 0; i < xc->maxhandle; i++) { - xc->valpos_mem[4 * i + 2] = 0; /* zero out offset val */ - xc->valpos_mem[4 * i + 3] = 0; /* zero out last time change val */ - } - xc->is_initial_time = 0; - } else { - if ((xc->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending)) { - xc->flush_context_pending = 0; - fstWriterFlushContextPrivate(xc); - xc->tchn_cnt++; - fstWriterVarint(xc->tchn_handle, xc->curtime); - } - } - - if (!skip) { - xc->tchn_idx++; - } - fstWriterVarint(xc->tchn_handle, tim - xc->curtime); - xc->tchn_cnt++; - xc->curtime = tim; - } -} - -void fstWriterEmitDumpActive(void *ctx, int enable) -{ - struct fstWriterContext *xc = (struct fstWriterContext *)ctx; - - if (xc) { - struct fstBlackoutChain *b = (struct fstBlackoutChain *)calloc(1, sizeof(struct fstBlackoutChain)); - - b->tim = xc->curtime; - b->active = (enable != 0); - - xc->num_blackouts++; - if (xc->blackout_curr) { - xc->blackout_curr->next = b; - xc->blackout_curr = b; - } else { - xc->blackout_head = b; - xc->blackout_curr = b; - } - } -} - -/***********************/ -/*** ***/ -/*** reader function ***/ -/*** ***/ -/***********************/ - -/* - * private structs - */ -static const char *vartypes[] = {"event", "integer", "parameter", "real", "real_parameter", "reg", "supply0", - "supply1", "time", "tri", "triand", "trior", "trireg", "tri0", - "tri1", "wand", "wire", "wor", "port", "sparray", "realtime", - "string", "bit", "logic", "int", "shortint", "longint", "byte", - "enum", "shortreal"}; - -static const char *modtypes[] = {"module", - "task", - "function", - "begin", - "fork", - "generate", - "struct", - "union", - "class", - "interface", - "package", - "program", - "vhdl_architecture", - "vhdl_procedure", - "vhdl_function", - "vhdl_record", - "vhdl_process", - "vhdl_block", - "vhdl_for_generate", - "vhdl_if_generate", - "vhdl_generate", - "vhdl_package"}; - -static const char *attrtypes[] = {"misc", "array", "enum", "class"}; - -static const char *arraytypes[] = {"none", "unpacked", "packed", "sparse"}; - -static const char *enumvaluetypes[] = {"integer", - "bit", - "logic", - "int", - "shortint", - "longint", - "byte", - "unsigned_integer", - "unsigned_bit", - "unsigned_logic", - "unsigned_int", - "unsigned_shortint", - "unsigned_longint", - "unsigned_byte"}; - -static const char *packtypes[] = {"none", "unpacked", "packed", "tagged_packed"}; - -struct fstCurrHier -{ - struct fstCurrHier *prev; - void *user_info; - int len; -}; - -struct fstReaderContext -{ - /* common entries */ - - FILE *f, *fh; - - uint64_t start_time, end_time; - uint64_t mem_used_by_writer; - uint64_t scope_count; - uint64_t var_count; - fstHandle maxhandle; - uint64_t num_alias; - uint64_t vc_section_count; - - uint32_t *signal_lens; /* maxhandle sized */ - unsigned char *signal_typs; /* maxhandle sized */ - unsigned char *process_mask; /* maxhandle-based, bitwise sized */ - uint32_t longest_signal_value_len; /* longest len value encountered */ - unsigned char *temp_signal_value_buf; /* malloced for len in longest_signal_value_len */ - - signed char timescale; - unsigned char filetype; - - unsigned use_vcd_extensions : 1; - unsigned double_endian_match : 1; - unsigned native_doubles_for_cb : 1; - unsigned contains_geom_section : 1; - unsigned contains_hier_section : 1; /* valid for hier_pos */ - unsigned contains_hier_section_lz4duo : 1; /* valid for hier_pos (contains_hier_section_lz4 always also set) */ - unsigned contains_hier_section_lz4 : 1; /* valid for hier_pos */ - unsigned limit_range_valid : 1; /* valid for limit_range_start, limit_range_end */ - - char version[FST_HDR_SIM_VERSION_SIZE + 1]; - char date[FST_HDR_DATE_SIZE + 1]; - int64_t timezero; - - char *filename, *filename_unpacked; - fst_off_t hier_pos; - - uint32_t num_blackouts; - uint64_t *blackout_times; - unsigned char *blackout_activity; - - uint64_t limit_range_start, limit_range_end; - - /* entries specific to read value at time functions */ - - unsigned rvat_data_valid : 1; - uint64_t *rvat_time_table; - uint64_t rvat_beg_tim, rvat_end_tim; - unsigned char *rvat_frame_data; - uint64_t rvat_frame_maxhandle; - fst_off_t *rvat_chain_table; - uint32_t *rvat_chain_table_lengths; - uint64_t rvat_vc_maxhandle; - fst_off_t rvat_vc_start; - uint32_t *rvat_sig_offs; - int rvat_packtype; - - uint32_t rvat_chain_len; - unsigned char *rvat_chain_mem; - fstHandle rvat_chain_facidx; - - uint32_t rvat_chain_pos_tidx; - uint32_t rvat_chain_pos_idx; - uint64_t rvat_chain_pos_time; - unsigned rvat_chain_pos_valid : 1; - - /* entries specific to hierarchy traversal */ - - struct fstHier hier; - struct fstCurrHier *curr_hier; - fstHandle current_handle; - char *curr_flat_hier_nam; - int flat_hier_alloc_len; - unsigned do_rewind : 1; - char str_scope_nam[FST_ID_NAM_SIZ + 1]; - char str_scope_comp[FST_ID_NAM_SIZ + 1]; - - unsigned fseek_failed : 1; - - /* self-buffered I/O for writes */ - -#ifndef FST_WRITEX_DISABLE - int writex_pos; - int writex_fd; - unsigned char writex_buf[FST_WRITEX_MAX]; -#endif - - char *f_nam; - char *fh_nam; -}; - -int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, fst_off_t offset, int whence) -{ - int rc = fseeko(stream, offset, whence); - - if (rc < 0) { - xc->fseek_failed = 1; -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence); - perror("Why"); -#endif - } - - return (rc); -} - -#ifndef FST_WRITEX_DISABLE -static void fstWritex(struct fstReaderContext *xc, void *v, int len) -{ - unsigned char *s = (unsigned char *)v; - - if (len) { - if (len < FST_WRITEX_MAX) { - if (xc->writex_pos + len >= FST_WRITEX_MAX) { - fstWritex(xc, NULL, 0); - } - - memcpy(xc->writex_buf + xc->writex_pos, s, len); - xc->writex_pos += len; - } else { - fstWritex(xc, NULL, 0); - if (write(xc->writex_fd, s, len)) { - }; - } - } else { - if (xc->writex_pos) { - if (write(xc->writex_fd, xc->writex_buf, xc->writex_pos)) { - }; - xc->writex_pos = 0; - } - } -} -#endif - -/* - * scope -> flat name handling - */ -static void fstReaderDeallocateScopeData(struct fstReaderContext *xc) -{ - struct fstCurrHier *chp; - - free(xc->curr_flat_hier_nam); - xc->curr_flat_hier_nam = NULL; - while (xc->curr_hier) { - chp = xc->curr_hier->prev; - free(xc->curr_hier); - xc->curr_hier = chp; - } -} - -const char *fstReaderGetCurrentFlatScope(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - if (xc) { - return (xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : ""); - } else { - return (NULL); - } -} - -void *fstReaderGetCurrentScopeUserInfo(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - if (xc) { - return (xc->curr_hier ? xc->curr_hier->user_info : NULL); - } else { - return (NULL); - } -} - -const char *fstReaderPopScope(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - if (xc && xc->curr_hier) { - struct fstCurrHier *ch = xc->curr_hier; - if (xc->curr_hier->prev) { - xc->curr_flat_hier_nam[xc->curr_hier->prev->len] = 0; - } else { - *xc->curr_flat_hier_nam = 0; - } - xc->curr_hier = xc->curr_hier->prev; - free(ch); - return (xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : ""); - } - - return (NULL); -} - -void fstReaderResetScope(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - while (fstReaderPopScope(xc)) - ; /* remove any already-built scoping info */ - } -} - -const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - if (xc) { - struct fstCurrHier *ch = (struct fstCurrHier *)malloc(sizeof(struct fstCurrHier)); - int chl = xc->curr_hier ? xc->curr_hier->len : 0; - int len = chl + 1 + strlen(nam); - if (len >= xc->flat_hier_alloc_len) { - xc->curr_flat_hier_nam = - xc->curr_flat_hier_nam ? (char *)realloc(xc->curr_flat_hier_nam, len + 1) : (char *)malloc(len + 1); - } - - if (chl) { - xc->curr_flat_hier_nam[chl] = '.'; - strcpy(xc->curr_flat_hier_nam + chl + 1, nam); - } else { - strcpy(xc->curr_flat_hier_nam, nam); - len--; - } - - ch->len = len; - ch->prev = xc->curr_hier; - ch->user_info = user_info; - xc->curr_hier = ch; - return (xc->curr_flat_hier_nam); - } - - return (NULL); -} - -int fstReaderGetCurrentScopeLen(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc && xc->curr_hier) { - return (xc->curr_hier->len); - } - - return (0); -} - -int fstReaderGetFseekFailed(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - if (xc) { - return (xc->fseek_failed != 0); - } - - return (0); -} - -/* - * iter mask manipulation util functions - */ -int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - facidx--; - if (facidx < xc->maxhandle) { - int process_idx = facidx / 8; - int process_bit = facidx & 7; - - return ((xc->process_mask[process_idx] & (1 << process_bit)) != 0); - } - } - return (0); -} - -void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - facidx--; - if (facidx < xc->maxhandle) { - int idx = facidx / 8; - int bitpos = facidx & 7; - - xc->process_mask[idx] |= (1 << bitpos); - } - } -} - -void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - facidx--; - if (facidx < xc->maxhandle) { - int idx = facidx / 8; - int bitpos = facidx & 7; - - xc->process_mask[idx] &= (~(1 << bitpos)); - } - } -} - -void fstReaderSetFacProcessMaskAll(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - memset(xc->process_mask, 0xff, (xc->maxhandle + 7) / 8); - } -} - -void fstReaderClrFacProcessMaskAll(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - memset(xc->process_mask, 0x00, (xc->maxhandle + 7) / 8); - } -} - -/* - * various utility read/write functions - */ -signed char fstReaderGetTimescale(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->timescale : 0); -} - -uint64_t fstReaderGetStartTime(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->start_time : 0); -} - -uint64_t fstReaderGetEndTime(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->end_time : 0); -} - -uint64_t fstReaderGetMemoryUsedByWriter(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->mem_used_by_writer : 0); -} - -uint64_t fstReaderGetScopeCount(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->scope_count : 0); -} - -uint64_t fstReaderGetVarCount(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->var_count : 0); -} - -fstHandle fstReaderGetMaxHandle(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->maxhandle : 0); -} - -uint64_t fstReaderGetAliasCount(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->num_alias : 0); -} - -uint64_t fstReaderGetValueChangeSectionCount(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->vc_section_count : 0); -} - -int fstReaderGetDoubleEndianMatchState(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->double_endian_match : 0); -} - -const char *fstReaderGetVersionString(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->version : NULL); -} - -const char *fstReaderGetDateString(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->date : NULL); -} - -int fstReaderGetFileType(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? (int)xc->filetype : (int)FST_FT_VERILOG); -} - -int64_t fstReaderGetTimezero(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->timezero : 0); -} - -uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - return (xc ? xc->num_blackouts : 0); -} - -uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc && (idx < xc->num_blackouts) && (xc->blackout_times)) { - return (xc->blackout_times[idx]); - } else { - return (0); - } -} - -unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc && (idx < xc->num_blackouts) && (xc->blackout_activity)) { - return (xc->blackout_activity[idx]); - } else { - return (0); - } -} - -void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - xc->limit_range_valid = 1; - xc->limit_range_start = start_time; - xc->limit_range_end = end_time; - } -} - -void fstReaderSetUnlimitedTimeRange(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - xc->limit_range_valid = 0; - } -} - -void fstReaderSetVcdExtensions(void *ctx, int enable) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - xc->use_vcd_extensions = (enable != 0); - } -} - -void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - if (xc) { - xc->native_doubles_for_cb = (enable != 0); - } -} - -/* - * hierarchy processing - */ -static void fstVcdID(char *buf, unsigned int value) -{ - char *pnt = buf; - - /* zero is illegal for a value...it is assumed they start at one */ - while (value) { - value--; - *(pnt++) = (char)('!' + value % 94); - value = value / 94; - } - - *pnt = 0; -} - -static int fstVcdIDForFwrite(char *buf, unsigned int value) -{ - char *pnt = buf; - - /* zero is illegal for a value...it is assumed they start at one */ - while (value) { - value--; - *(pnt++) = (char)('!' + value % 94); - value = value / 94; - } - - return (pnt - buf); -} - -static int fstReaderRecreateHierFile(struct fstReaderContext *xc) -{ - int pass_status = 1; - - if (!xc->fh) { - fst_off_t offs_cache = ftello(xc->f); - char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); - unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN); - fst_off_t hl, uclen; - fst_off_t clen = 0; - gzFile zhandle = NULL; - int zfd; - int htyp = FST_BL_SKIP; - - /* can't handle both set at once should never happen in a real file */ - if (!xc->contains_hier_section_lz4 && xc->contains_hier_section) { - htyp = FST_BL_HIER; - } else if (xc->contains_hier_section_lz4 && !xc->contains_hier_section) { - htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4; - } - - sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc); - fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET); - uclen = fstReaderUint64(xc->f); -#ifndef __MINGW32__ - fflush(xc->f); -#endif - if (htyp == FST_BL_HIER) { - fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET); - uclen = fstReaderUint64(xc->f); -#ifndef __MINGW32__ - fflush(xc->f); -#endif - zfd = dup(fileno(xc->f)); - lseek(zfd, ftell(xc->f), SEEK_SET); - zhandle = gzdopen(zfd, "rb"); - if (!zhandle) { - close(zfd); - free(mem); - free(fnam); - return (0); - } - } else if ((htyp == FST_BL_HIER_LZ4) || (htyp == FST_BL_HIER_LZ4DUO)) { - fstReaderFseeko(xc, xc->f, xc->hier_pos - 8, SEEK_SET); /* get section len */ - clen = fstReaderUint64(xc->f) - 16; - uclen = fstReaderUint64(xc->f); -#ifndef __MINGW32__ - fflush(xc->f); -#endif - } - -#ifndef __MINGW32__ - xc->fh = fopen(fnam, "w+b"); - if (!xc->fh) -#endif - { - xc->fh = tmpfile_open(&xc->fh_nam); - free(fnam); - fnam = NULL; - if (!xc->fh) { - tmpfile_close(&xc->fh, &xc->fh_nam); - free(mem); - return (0); - } - } - -#ifndef __MINGW32__ - if (fnam) - unlink(fnam); -#endif - - if (htyp == FST_BL_HIER) { - for (hl = 0; hl < uclen; hl += FST_GZIO_LEN) { - size_t len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl); - size_t gzreadlen = gzread(zhandle, mem, len); /* rc should equal len... */ - size_t fwlen; - - if (gzreadlen != len) { - pass_status = 0; - break; - } - - fwlen = fstFwrite(mem, len, 1, xc->fh); - if (fwlen != 1) { - pass_status = 0; - break; - } - } - gzclose(zhandle); - } else if (htyp == FST_BL_HIER_LZ4DUO) { - unsigned char *lz4_cmem = (unsigned char *)malloc(clen); - unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen); - unsigned char *lz4_ucmem2; - uint64_t uclen2; - int skiplen2 = 0; - - fstFread(lz4_cmem, clen, 1, xc->f); - - uclen2 = fstGetVarint64(lz4_cmem, &skiplen2); - lz4_ucmem2 = (unsigned char *)malloc(uclen2); - pass_status = - (uclen2 == (uint64_t)LZ4_decompress_safe_partial((char *)lz4_cmem + skiplen2, (char *)lz4_ucmem2, - clen - skiplen2, uclen2, uclen2)); - if (pass_status) { - pass_status = (uclen == LZ4_decompress_safe_partial((char *)lz4_ucmem2, (char *)lz4_ucmem, uclen2, - uclen, uclen)); - - if (fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1) { - pass_status = 0; - } - } - - free(lz4_ucmem2); - free(lz4_ucmem); - free(lz4_cmem); - } else if (htyp == FST_BL_HIER_LZ4) { - unsigned char *lz4_cmem = (unsigned char *)malloc(clen); - unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen); - - fstFread(lz4_cmem, clen, 1, xc->f); - pass_status = - (uclen == LZ4_decompress_safe_partial((char *)lz4_cmem, (char *)lz4_ucmem, clen, uclen, uclen)); - - if (fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1) { - pass_status = 0; - } - - free(lz4_ucmem); - free(lz4_cmem); - } else /* FST_BL_SKIP */ - { - pass_status = 0; - if (xc->fh) { - fclose(xc->fh); - xc->fh = NULL; /* needed in case .hier file is missing and there are no hier sections */ - } - } - - free(mem); - free(fnam); - - fstReaderFseeko(xc, xc->f, offs_cache, SEEK_SET); - } - - return (pass_status); -} - -int fstReaderIterateHierRewind(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - int pass_status = 0; - - if (xc) { - pass_status = 1; - if (!xc->fh) { - pass_status = fstReaderRecreateHierFile(xc); - } - - xc->do_rewind = 1; - } - - return (pass_status); -} - -struct fstHier *fstReaderIterateHier(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - int isfeof; - fstHandle alias; - char *pnt; - int ch; - - if (!xc) - return (NULL); - - if (!xc->fh) { - if (!fstReaderRecreateHierFile(xc)) { - return (NULL); - } - } - - if (xc->do_rewind) { - xc->do_rewind = 0; - xc->current_handle = 0; - fstReaderFseeko(xc, xc->fh, 0, SEEK_SET); - clearerr(xc->fh); - } - - if (!(isfeof = feof(xc->fh))) { - int tag = fgetc(xc->fh); - switch (tag) { - case FST_ST_VCD_SCOPE: - xc->hier.htyp = FST_HT_SCOPE; - xc->hier.u.scope.typ = fgetc(xc->fh); - xc->hier.u.scope.name = pnt = xc->str_scope_nam; - while ((ch = fgetc(xc->fh))) { - *(pnt++) = ch; - }; /* scopename */ - *pnt = 0; - xc->hier.u.scope.name_length = pnt - xc->hier.u.scope.name; - - xc->hier.u.scope.component = pnt = xc->str_scope_comp; - while ((ch = fgetc(xc->fh))) { - *(pnt++) = ch; - }; /* scopecomp */ - *pnt = 0; - xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component; - break; - - case FST_ST_VCD_UPSCOPE: - xc->hier.htyp = FST_HT_UPSCOPE; - break; - - case FST_ST_GEN_ATTRBEGIN: - xc->hier.htyp = FST_HT_ATTRBEGIN; - xc->hier.u.attr.typ = fgetc(xc->fh); - xc->hier.u.attr.subtype = fgetc(xc->fh); - xc->hier.u.attr.name = pnt = xc->str_scope_nam; - while ((ch = fgetc(xc->fh))) { - *(pnt++) = ch; - }; /* scopename */ - *pnt = 0; - xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name; - - xc->hier.u.attr.arg = fstReaderVarint64(xc->fh); - - if (xc->hier.u.attr.typ == FST_AT_MISC) { - if ((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM) || (xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM)) { - int sidx_skiplen_dummy = 0; - xc->hier.u.attr.arg_from_name = - fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy); - } - } - break; - - case FST_ST_GEN_ATTREND: - xc->hier.htyp = FST_HT_ATTREND; - break; - - case FST_VT_VCD_EVENT: - case FST_VT_VCD_INTEGER: - case FST_VT_VCD_PARAMETER: - case FST_VT_VCD_REAL: - case FST_VT_VCD_REAL_PARAMETER: - case FST_VT_VCD_REG: - case FST_VT_VCD_SUPPLY0: - case FST_VT_VCD_SUPPLY1: - case FST_VT_VCD_TIME: - case FST_VT_VCD_TRI: - case FST_VT_VCD_TRIAND: - case FST_VT_VCD_TRIOR: - case FST_VT_VCD_TRIREG: - case FST_VT_VCD_TRI0: - case FST_VT_VCD_TRI1: - case FST_VT_VCD_WAND: - case FST_VT_VCD_WIRE: - case FST_VT_VCD_WOR: - case FST_VT_VCD_PORT: - case FST_VT_VCD_SPARRAY: - case FST_VT_VCD_REALTIME: - case FST_VT_GEN_STRING: - case FST_VT_SV_BIT: - case FST_VT_SV_LOGIC: - case FST_VT_SV_INT: - case FST_VT_SV_SHORTINT: - case FST_VT_SV_LONGINT: - case FST_VT_SV_BYTE: - case FST_VT_SV_ENUM: - case FST_VT_SV_SHORTREAL: - xc->hier.htyp = FST_HT_VAR; - xc->hier.u.var.svt_workspace = FST_SVT_NONE; - xc->hier.u.var.sdt_workspace = FST_SDT_NONE; - xc->hier.u.var.sxt_workspace = 0; - xc->hier.u.var.typ = tag; - xc->hier.u.var.direction = fgetc(xc->fh); - xc->hier.u.var.name = pnt = xc->str_scope_nam; - while ((ch = fgetc(xc->fh))) { - *(pnt++) = ch; - }; /* varname */ - *pnt = 0; - xc->hier.u.var.name_length = pnt - xc->hier.u.var.name; - xc->hier.u.var.length = fstReaderVarint32(xc->fh); - if (tag == FST_VT_VCD_PORT) { - xc->hier.u.var.length -= 2; /* removal of delimiting spaces */ - xc->hier.u.var.length /= 3; /* port -> signal size adjust */ - } - - alias = fstReaderVarint32(xc->fh); - - if (!alias) { - xc->current_handle++; - xc->hier.u.var.handle = xc->current_handle; - xc->hier.u.var.is_alias = 0; - } else { - xc->hier.u.var.handle = alias; - xc->hier.u.var.is_alias = 1; - } - - break; - - default: - isfeof = 1; - break; - } - } - - return (!isfeof ? &xc->hier : NULL); -} - -int fstReaderProcessHier(void *ctx, FILE *fv) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - char *str; - char *pnt; - int ch, scopetype; - int vartype; - uint32_t len, alias; - /* uint32_t maxvalpos=0; */ - unsigned int num_signal_dyn = 65536; - int attrtype, subtype; - uint64_t attrarg; - fstHandle maxhandle_scanbuild; - - if (!xc) - return (0); - - xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */ - - if (!xc->fh) { - if (!fstReaderRecreateHierFile(xc)) { - return (0); - } - } - - str = (char *)malloc(FST_ID_NAM_ATTR_SIZ + 1); - - if (fv) { - char time_dimension[2] = {0, 0}; - int time_scale = 1; - - fprintf(fv, "$date\n\t%s\n$end\n", xc->date); - fprintf(fv, "$version\n\t%s\n$end\n", xc->version); - if (xc->timezero) - fprintf(fv, "$timezero\n\t%" PRId64 "\n$end\n", xc->timezero); - - switch (xc->timescale) { - case 2: - time_scale = 100; - time_dimension[0] = 0; - break; - case 1: - time_scale = 10; /* fallthrough */ - case 0: - time_dimension[0] = 0; - break; - - case -1: - time_scale = 100; - time_dimension[0] = 'm'; - break; - case -2: - time_scale = 10; /* fallthrough */ - case -3: - time_dimension[0] = 'm'; - break; - - case -4: - time_scale = 100; - time_dimension[0] = 'u'; - break; - case -5: - time_scale = 10; /* fallthrough */ - case -6: - time_dimension[0] = 'u'; - break; - - case -10: - time_scale = 100; - time_dimension[0] = 'p'; - break; - case -11: - time_scale = 10; /* fallthrough */ - case -12: - time_dimension[0] = 'p'; - break; - - case -13: - time_scale = 100; - time_dimension[0] = 'f'; - break; - case -14: - time_scale = 10; /* fallthrough */ - case -15: - time_dimension[0] = 'f'; - break; - - case -16: - time_scale = 100; - time_dimension[0] = 'a'; - break; - case -17: - time_scale = 10; /* fallthrough */ - case -18: - time_dimension[0] = 'a'; - break; - - case -19: - time_scale = 100; - time_dimension[0] = 'z'; - break; - case -20: - time_scale = 10; /* fallthrough */ - case -21: - time_dimension[0] = 'z'; - break; - - case -7: - time_scale = 100; - time_dimension[0] = 'n'; - break; - case -8: - time_scale = 10; /* fallthrough */ - case -9: - default: - time_dimension[0] = 'n'; - break; - } - - if (fv) - fprintf(fv, "$timescale\n\t%d%ss\n$end\n", time_scale, time_dimension); - } - - xc->maxhandle = 0; - xc->num_alias = 0; - - free(xc->signal_lens); - xc->signal_lens = (uint32_t *)malloc(num_signal_dyn * sizeof(uint32_t)); - - free(xc->signal_typs); - xc->signal_typs = (unsigned char *)malloc(num_signal_dyn * sizeof(unsigned char)); - - fstReaderFseeko(xc, xc->fh, 0, SEEK_SET); - while (!feof(xc->fh)) { - int tag = fgetc(xc->fh); - switch (tag) { - case FST_ST_VCD_SCOPE: - scopetype = fgetc(xc->fh); - if ((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) - scopetype = FST_ST_VCD_MODULE; - pnt = str; - while ((ch = fgetc(xc->fh))) { - *(pnt++) = ch; - }; /* scopename */ - *pnt = 0; - while (fgetc(xc->fh)) { - }; /* scopecomp */ - - if (fv) - fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str); - break; - - case FST_ST_VCD_UPSCOPE: - if (fv) - fprintf(fv, "$upscope $end\n"); - break; - - case FST_ST_GEN_ATTRBEGIN: - attrtype = fgetc(xc->fh); - subtype = fgetc(xc->fh); - pnt = str; - while ((ch = fgetc(xc->fh))) { - *(pnt++) = ch; - }; /* attrname */ - *pnt = 0; - - if (!str[0]) { - strcpy(str, "\"\""); - } - - attrarg = fstReaderVarint64(xc->fh); - - if (fv && xc->use_vcd_extensions) { - switch (attrtype) { - case FST_AT_ARRAY: - if ((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) - subtype = FST_AR_NONE; - fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], arraytypes[subtype], str, - attrarg); - break; - case FST_AT_ENUM: - if ((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) - subtype = FST_EV_SV_INTEGER; - fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], enumvaluetypes[subtype], - str, attrarg); - break; - case FST_AT_PACK: - if ((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) - subtype = FST_PT_NONE; - fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], packtypes[subtype], str, - attrarg); - break; - case FST_AT_MISC: - default: - attrtype = FST_AT_MISC; - if (subtype == FST_MT_COMMENT) { - fprintf(fv, "$comment\n\t%s\n$end\n", str); - } else { - if ((subtype == FST_MT_SOURCESTEM) || (subtype == FST_MT_SOURCEISTEM)) { - int sidx_skiplen_dummy = 0; - uint64_t sidx = fstGetVarint64((unsigned char *)str, &sidx_skiplen_dummy); - - fprintf(fv, "$attrbegin %s %02x %" PRId64 " %" PRId64 " $end\n", attrtypes[attrtype], - subtype, sidx, attrarg); - } else { - fprintf(fv, "$attrbegin %s %02x %s %" PRId64 " $end\n", attrtypes[attrtype], subtype, str, - attrarg); - } - } - break; - } - } - break; - - case FST_ST_GEN_ATTREND: - if (fv && xc->use_vcd_extensions) - fprintf(fv, "$attrend $end\n"); - break; - - case FST_VT_VCD_EVENT: - case FST_VT_VCD_INTEGER: - case FST_VT_VCD_PARAMETER: - case FST_VT_VCD_REAL: - case FST_VT_VCD_REAL_PARAMETER: - case FST_VT_VCD_REG: - case FST_VT_VCD_SUPPLY0: - case FST_VT_VCD_SUPPLY1: - case FST_VT_VCD_TIME: - case FST_VT_VCD_TRI: - case FST_VT_VCD_TRIAND: - case FST_VT_VCD_TRIOR: - case FST_VT_VCD_TRIREG: - case FST_VT_VCD_TRI0: - case FST_VT_VCD_TRI1: - case FST_VT_VCD_WAND: - case FST_VT_VCD_WIRE: - case FST_VT_VCD_WOR: - case FST_VT_VCD_PORT: - case FST_VT_VCD_SPARRAY: - case FST_VT_VCD_REALTIME: - case FST_VT_GEN_STRING: - case FST_VT_SV_BIT: - case FST_VT_SV_LOGIC: - case FST_VT_SV_INT: - case FST_VT_SV_SHORTINT: - case FST_VT_SV_LONGINT: - case FST_VT_SV_BYTE: - case FST_VT_SV_ENUM: - case FST_VT_SV_SHORTREAL: - vartype = tag; - /* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */ - pnt = str; - while ((ch = fgetc(xc->fh))) { - *(pnt++) = ch; - }; /* varname */ - *pnt = 0; - len = fstReaderVarint32(xc->fh); - alias = fstReaderVarint32(xc->fh); - - if (!alias) { - if (xc->maxhandle == num_signal_dyn) { - num_signal_dyn *= 2; - xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, num_signal_dyn * sizeof(uint32_t)); - xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, num_signal_dyn * sizeof(unsigned char)); - } - xc->signal_lens[xc->maxhandle] = len; - xc->signal_typs[xc->maxhandle] = vartype; - - /* maxvalpos+=len; */ - if (len > xc->longest_signal_value_len) { - xc->longest_signal_value_len = len; - } - - if ((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || - (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL)) { - len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32; - xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; - } - if (fv) { - char vcdid_buf[16]; - uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); - fstVcdID(vcdid_buf, xc->maxhandle + 1); - fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); - } - xc->maxhandle++; - } else { - if ((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || - (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL)) { - len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32; - xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; - } - if (fv) { - char vcdid_buf[16]; - uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); - fstVcdID(vcdid_buf, alias); - fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); - } - xc->num_alias++; - } - - break; - - default: - break; - } - } - if (fv) - fprintf(fv, "$enddefinitions $end\n"); - - maxhandle_scanbuild = xc->maxhandle ? xc->maxhandle - : 1; /*scan-build warning suppression, in reality we have at least one signal */ - - xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, maxhandle_scanbuild * sizeof(uint32_t)); - xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, maxhandle_scanbuild * sizeof(unsigned char)); - - free(xc->process_mask); - xc->process_mask = (unsigned char *)calloc(1, (maxhandle_scanbuild + 7) / 8); - - free(xc->temp_signal_value_buf); - xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1); - - xc->var_count = xc->maxhandle + xc->num_alias; - - free(str); - return (1); -} - -/* - * reader file open/close functions - */ -int fstReaderInit(struct fstReaderContext *xc) -{ - fst_off_t blkpos = 0; - fst_off_t endfile; - uint64_t seclen; - int sectype; - uint64_t vc_section_count_actual = 0; - int hdr_incomplete = 0; - int hdr_seen = 0; - int gzread_pass_status = 1; - - sectype = fgetc(xc->f); - if (sectype == FST_BL_ZWRAPPER) { - FILE *fcomp; - fst_off_t offpnt, uclen; - char gz_membuf[FST_GZIO_LEN]; - gzFile zhandle; - int zfd; - int flen = strlen(xc->filename); - char *hf; - - seclen = fstReaderUint64(xc->f); - uclen = fstReaderUint64(xc->f); - - if (!seclen) - return (0); /* not finished compressing, this is a failed read */ - - hf = (char *)calloc(1, flen + 16 + 32 + 1); - - sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc); - fcomp = fopen(hf, "w+b"); - if (!fcomp) { - fcomp = tmpfile_open(&xc->f_nam); - free(hf); - hf = NULL; - if (!fcomp) { - tmpfile_close(&fcomp, &xc->f_nam); - return (0); - } - } - -#if defined(FST_MACOSX) - setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ -#endif - -#ifdef __MINGW32__ - setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ - xc->filename_unpacked = hf; -#else - if (hf) { - unlink(hf); - free(hf); - } -#endif - - fstReaderFseeko(xc, xc->f, 1 + 8 + 8, SEEK_SET); -#ifndef __MINGW32__ - fflush(xc->f); -#endif - - zfd = dup(fileno(xc->f)); - lseek(zfd, ftell(xc->f), SEEK_SET); - zhandle = gzdopen(zfd, "rb"); - if (zhandle) { - for (offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) { - size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); - size_t gzreadlen = gzread(zhandle, gz_membuf, this_len); - size_t fwlen; - - if (gzreadlen != this_len) { - gzread_pass_status = 0; - break; - } - fwlen = fstFwrite(gz_membuf, this_len, 1, fcomp); - if (fwlen != 1) { - gzread_pass_status = 0; - break; - } - } - gzclose(zhandle); - } else { - close(zfd); - } - fflush(fcomp); - fclose(xc->f); - xc->f = fcomp; - } - - if (gzread_pass_status) { - fstReaderFseeko(xc, xc->f, 0, SEEK_END); - endfile = ftello(xc->f); - - while (blkpos < endfile) { - fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); - - sectype = fgetc(xc->f); - seclen = fstReaderUint64(xc->f); - - if (sectype == EOF) { - break; - } - - if ((hdr_incomplete) && (!seclen)) { - break; - } - - if (!hdr_seen && (sectype != FST_BL_HDR)) { - break; - } - - blkpos++; - if (sectype == FST_BL_HDR) { - if (!hdr_seen) { - int ch; - double dcheck; - - xc->start_time = fstReaderUint64(xc->f); - xc->end_time = fstReaderUint64(xc->f); - - hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0); - - fstFread(&dcheck, 8, 1, xc->f); - xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST); - if (!xc->double_endian_match) { - union - { - unsigned char rvs_buf[8]; - double d; - } vu; - - unsigned char *dcheck_alias = (unsigned char *)&dcheck; - int rvs_idx; - - for (rvs_idx = 0; rvs_idx < 8; rvs_idx++) { - vu.rvs_buf[rvs_idx] = dcheck_alias[7 - rvs_idx]; - } - if (vu.d != FST_DOUBLE_ENDTEST) { - break; /* either corrupt file or wrong architecture (offset +33 also functions as matchword) - */ - } - } - - hdr_seen = 1; - - xc->mem_used_by_writer = fstReaderUint64(xc->f); - xc->scope_count = fstReaderUint64(xc->f); - xc->var_count = fstReaderUint64(xc->f); - xc->maxhandle = fstReaderUint64(xc->f); - xc->num_alias = xc->var_count - xc->maxhandle; - xc->vc_section_count = fstReaderUint64(xc->f); - ch = fgetc(xc->f); - xc->timescale = (signed char)ch; - fstFread(xc->version, FST_HDR_SIM_VERSION_SIZE, 1, xc->f); - xc->version[FST_HDR_SIM_VERSION_SIZE] = 0; - fstFread(xc->date, FST_HDR_DATE_SIZE, 1, xc->f); - xc->date[FST_HDR_DATE_SIZE] = 0; - ch = fgetc(xc->f); - xc->filetype = (unsigned char)ch; - xc->timezero = fstReaderUint64(xc->f); - } - } else if ((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS) || - (sectype == FST_BL_VCDATA_DYN_ALIAS2)) { - if (hdr_incomplete) { - uint64_t bt = fstReaderUint64(xc->f); - xc->end_time = fstReaderUint64(xc->f); - - if (!vc_section_count_actual) { - xc->start_time = bt; - } - } - - vc_section_count_actual++; - } else if (sectype == FST_BL_GEOM) { - if (!hdr_incomplete) { - uint64_t clen = seclen - 24; - uint64_t uclen = fstReaderUint64(xc->f); - unsigned char *ucdata = (unsigned char *)malloc(uclen); - unsigned char *pnt = ucdata; - unsigned int i; - - xc->contains_geom_section = 1; - xc->maxhandle = fstReaderUint64(xc->f); - xc->longest_signal_value_len = - 32; /* arbitrarily set at 32...this is much longer than an expanded double */ - - free(xc->process_mask); - xc->process_mask = (unsigned char *)calloc(1, (xc->maxhandle + 7) / 8); - - if (clen != uclen) { - unsigned char *cdata = (unsigned char *)malloc(clen); - unsigned long destlen = uclen; - unsigned long sourcelen = clen; - int rc; - - fstFread(cdata, clen, 1, xc->f); - rc = uncompress(ucdata, &destlen, cdata, sourcelen); - - if (rc != Z_OK) { - fprintf(stderr, FST_APIMESS "fstReaderInit(), geom uncompress rc = %d, exiting.\n", rc); - exit(255); - } - - free(cdata); - } else { - fstFread(ucdata, uclen, 1, xc->f); - } - - free(xc->signal_lens); - xc->signal_lens = (uint32_t *)malloc(sizeof(uint32_t) * xc->maxhandle); - free(xc->signal_typs); - xc->signal_typs = (unsigned char *)malloc(sizeof(unsigned char) * xc->maxhandle); - - for (i = 0; i < xc->maxhandle; i++) { - int skiplen; - uint64_t val = fstGetVarint32(pnt, &skiplen); - - pnt += skiplen; - - if (val) { - xc->signal_lens[i] = (val != 0xFFFFFFFF) ? val : 0; - xc->signal_typs[i] = FST_VT_VCD_WIRE; - if (xc->signal_lens[i] > xc->longest_signal_value_len) { - xc->longest_signal_value_len = xc->signal_lens[i]; - } - } else { - xc->signal_lens[i] = 8; /* backpatch in real */ - xc->signal_typs[i] = FST_VT_VCD_REAL; - /* xc->longest_signal_value_len handled above by overly large init size */ - } - } - - free(xc->temp_signal_value_buf); - xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1); - - free(ucdata); - } - } else if (sectype == FST_BL_HIER) { - xc->contains_hier_section = 1; - xc->hier_pos = ftello(xc->f); - } else if (sectype == FST_BL_HIER_LZ4DUO) { - xc->contains_hier_section_lz4 = 1; - xc->contains_hier_section_lz4duo = 1; - xc->hier_pos = ftello(xc->f); - } else if (sectype == FST_BL_HIER_LZ4) { - xc->contains_hier_section_lz4 = 1; - xc->hier_pos = ftello(xc->f); - } else if (sectype == FST_BL_BLACKOUT) { - uint32_t i; - uint64_t cur_bl = 0; - uint64_t delta; - - xc->num_blackouts = fstReaderVarint32(xc->f); - free(xc->blackout_times); - xc->blackout_times = (uint64_t *)calloc(xc->num_blackouts, sizeof(uint64_t)); - free(xc->blackout_activity); - xc->blackout_activity = (unsigned char *)calloc(xc->num_blackouts, sizeof(unsigned char)); - - for (i = 0; i < xc->num_blackouts; i++) { - xc->blackout_activity[i] = fgetc(xc->f) != 0; - delta = fstReaderVarint64(xc->f); - cur_bl += delta; - xc->blackout_times[i] = cur_bl; - } - } - - blkpos += seclen; - if (!hdr_seen) - break; - } - - if (hdr_seen) { - if (xc->vc_section_count != vc_section_count_actual) { - xc->vc_section_count = vc_section_count_actual; - } - - if (!xc->contains_geom_section) { - fstReaderProcessHier(xc, NULL); /* recreate signal_lens/signal_typs info */ - } - } - } - - return (hdr_seen); -} - -void *fstReaderOpenForUtilitiesOnly(void) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext)); - - return (xc); -} - -void *fstReaderOpen(const char *nam) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext)); - - if ((!nam) || (!(xc->f = fopen(nam, "rb")))) { - free(xc); - xc = NULL; - } else { - int flen = strlen(nam); - char *hf = (char *)calloc(1, flen + 6); - int rc; - -#if defined(__MINGW32__) || defined(FST_MACOSX) - setvbuf(xc->f, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ -#endif - - memcpy(hf, nam, flen); - strcpy(hf + flen, ".hier"); - xc->fh = fopen(hf, "rb"); - - free(hf); - xc->filename = strdup(nam); - rc = fstReaderInit(xc); - - if ((rc) && (xc->vc_section_count) && (xc->maxhandle) && - ((xc->fh) || (xc->contains_hier_section || (xc->contains_hier_section_lz4)))) { - /* more init */ - xc->do_rewind = 1; - } else { - fstReaderClose(xc); - xc = NULL; - } - } - - return (xc); -} - -static void fstReaderDeallocateRvatData(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - if (xc) { - free(xc->rvat_chain_mem); - xc->rvat_chain_mem = NULL; - free(xc->rvat_frame_data); - xc->rvat_frame_data = NULL; - free(xc->rvat_time_table); - xc->rvat_time_table = NULL; - free(xc->rvat_chain_table); - xc->rvat_chain_table = NULL; - free(xc->rvat_chain_table_lengths); - xc->rvat_chain_table_lengths = NULL; - - xc->rvat_data_valid = 0; - } -} - -void fstReaderClose(void *ctx) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - if (xc) { - fstReaderDeallocateScopeData(xc); - fstReaderDeallocateRvatData(xc); - free(xc->rvat_sig_offs); - xc->rvat_sig_offs = NULL; - - free(xc->process_mask); - xc->process_mask = NULL; - free(xc->blackout_times); - xc->blackout_times = NULL; - free(xc->blackout_activity); - xc->blackout_activity = NULL; - free(xc->temp_signal_value_buf); - xc->temp_signal_value_buf = NULL; - free(xc->signal_typs); - xc->signal_typs = NULL; - free(xc->signal_lens); - xc->signal_lens = NULL; - free(xc->filename); - xc->filename = NULL; - - if (xc->fh) { - tmpfile_close(&xc->fh, &xc->fh_nam); - } - - if (xc->f) { - tmpfile_close(&xc->f, &xc->f_nam); - if (xc->filename_unpacked) { - unlink(xc->filename_unpacked); - free(xc->filename_unpacked); - } - } - - free(xc); - } -} - -/* - * read processing - */ - -/* normal read which re-interleaves the value change data */ -int fstReaderIterBlocks(void *ctx, - void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, - const unsigned char *value), - void *user_callback_data_pointer, FILE *fv) -{ - return (fstReaderIterBlocks2(ctx, value_change_callback, NULL, user_callback_data_pointer, fv)); -} - -int fstReaderIterBlocks2(void *ctx, - void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, - fstHandle facidx, const unsigned char *value), - void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, - fstHandle facidx, const unsigned char *value, - uint32_t len), - void *user_callback_data_pointer, FILE *fv) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - - uint64_t previous_time = UINT64_MAX; - uint64_t *time_table = NULL; - uint64_t tsec_nitems; - unsigned int secnum = 0; - int blocks_skipped = 0; - fst_off_t blkpos = 0; - uint64_t seclen, beg_tim; - uint64_t end_tim; - uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle; - fst_off_t vc_start; - fst_off_t indx_pntr, indx_pos; - fst_off_t *chain_table = NULL; - uint32_t *chain_table_lengths = NULL; - unsigned char *chain_cmem; - unsigned char *pnt; - long chain_clen; - fstHandle idx, pidx = 0, i; - uint64_t pval; - uint64_t vc_maxhandle_largest = 0; - uint64_t tsec_uclen = 0, tsec_clen = 0; - int sectype; - uint64_t mem_required_for_traversal; - unsigned char *mem_for_traversal = NULL; - uint32_t traversal_mem_offs; - uint32_t *scatterptr, *headptr, *length_remaining; - uint32_t cur_blackout = 0; - int packtype; - unsigned char *mc_mem = NULL; - uint32_t mc_mem_len; /* corresponds to largest value encountered in chain_table_lengths[i] */ - int dumpvars_state = 0; - - if (!xc) - return (0); - - scatterptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t)); - headptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t)); - length_remaining = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t)); - - if (fv) { -#ifndef FST_WRITEX_DISABLE - fflush(fv); - setvbuf(fv, (char *)NULL, _IONBF, - 0); /* even buffered IO is slow so disable it and use our own routines that don't need seeking */ - xc->writex_fd = fileno(fv); -#endif - } - - for (;;) { - uint32_t *tc_head = NULL; - traversal_mem_offs = 0; - - fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); - - sectype = fgetc(xc->f); - seclen = fstReaderUint64(xc->f); - - if ((sectype == EOF) || (sectype == FST_BL_SKIP)) { -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "<< EOF >>\n"); -#endif - break; - } - - blkpos++; - if ((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && - (sectype != FST_BL_VCDATA_DYN_ALIAS2)) { - blkpos += seclen; - continue; - } - - if (!seclen) - break; - - beg_tim = fstReaderUint64(xc->f); - end_tim = fstReaderUint64(xc->f); - - if (xc->limit_range_valid) { - if (end_tim < xc->limit_range_start) { - blocks_skipped++; - blkpos += seclen; - continue; - } - - if (beg_tim > - xc->limit_range_end) /* likely the compare in for(i=0;if); - mem_for_traversal = - (unsigned char *)malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */ -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "sec: %u seclen: %d begtim: %d endtim: %d\n", secnum, (int)seclen, (int)beg_tim, - (int)end_tim); - fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal); -#endif - /* process time block */ - { - unsigned char *ucdata; - unsigned char *cdata; - unsigned long destlen /* = tsec_uclen */; /* scan-build */ - unsigned long sourcelen /*= tsec_clen */; /* scan-build */ - int rc; - unsigned char *tpnt; - uint64_t tpval; - unsigned int ti; - - if (fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET) != 0) - break; - tsec_uclen = fstReaderUint64(xc->f); - tsec_clen = fstReaderUint64(xc->f); - tsec_nitems = fstReaderUint64(xc->f); -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "time section unc: %d, com: %d (%d items)\n", (int)tsec_uclen, (int)tsec_clen, - (int)tsec_nitems); -#endif - if (tsec_clen > seclen) - break; /* corrupted tsec_clen: by definition it can't be larger than size of section */ - ucdata = (unsigned char *)malloc(tsec_uclen); - if (!ucdata) - break; /* malloc fail as tsec_uclen out of range from corrupted file */ - destlen = tsec_uclen; - sourcelen = tsec_clen; - - fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR); - - if (tsec_uclen != tsec_clen) { - cdata = (unsigned char *)malloc(tsec_clen); - fstFread(cdata, tsec_clen, 1, xc->f); - - rc = uncompress(ucdata, &destlen, cdata, sourcelen); - - if (rc != Z_OK) { - fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), tsec uncompress rc = %d, exiting.\n", rc); - exit(255); - } - - free(cdata); - } else { - fstFread(ucdata, tsec_uclen, 1, xc->f); - } - - free(time_table); - time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t)); - tpnt = ucdata; - tpval = 0; - for (ti = 0; ti < tsec_nitems; ti++) { - int skiplen; - uint64_t val = fstGetVarint64(tpnt, &skiplen); - tpval = time_table[ti] = tpval + val; - tpnt += skiplen; - } - - tc_head = (uint32_t *)calloc(tsec_nitems /* scan-build */ ? tsec_nitems : 1, sizeof(uint32_t)); - free(ucdata); - } - - fstReaderFseeko(xc, xc->f, blkpos + 32, SEEK_SET); - - frame_uclen = fstReaderVarint64(xc->f); - frame_clen = fstReaderVarint64(xc->f); - frame_maxhandle = fstReaderVarint64(xc->f); - - if (secnum == 0) { - if ((beg_tim != time_table[0]) || (blocks_skipped)) { - unsigned char *mu = (unsigned char *)malloc(frame_uclen); - uint32_t sig_offs = 0; - - if (fv) { - char wx_buf[32]; - int wx_len; - - if (beg_tim) { - if (dumpvars_state == 1) { - wx_len = sprintf(wx_buf, "$end\n"); - fstWritex(xc, wx_buf, wx_len); - dumpvars_state = 2; - } - wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", beg_tim); - fstWritex(xc, wx_buf, wx_len); - if (!dumpvars_state) { - wx_len = sprintf(wx_buf, "$dumpvars\n"); - fstWritex(xc, wx_buf, wx_len); - dumpvars_state = 1; - } - } - if ((xc->num_blackouts) && (cur_blackout != xc->num_blackouts)) { - if (beg_tim == xc->blackout_times[cur_blackout]) { - wx_len = sprintf(wx_buf, "$dump%s $end\n", - (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); - fstWritex(xc, wx_buf, wx_len); - } - } - } - - if (frame_uclen == frame_clen) { - fstFread(mu, frame_uclen, 1, xc->f); - } else { - unsigned char *mc = (unsigned char *)malloc(frame_clen); - int rc; - - unsigned long destlen = frame_uclen; - unsigned long sourcelen = frame_clen; - - fstFread(mc, sourcelen, 1, xc->f); - rc = uncompress(mu, &destlen, mc, sourcelen); - if (rc != Z_OK) { - fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), frame uncompress rc: %d, exiting.\n", rc); - exit(255); - } - free(mc); - } - - for (idx = 0; idx < frame_maxhandle; idx++) { - int process_idx = idx / 8; - int process_bit = idx & 7; - - if (xc->process_mask[process_idx] & (1 << process_bit)) { - if (xc->signal_lens[idx] <= 1) { - if (xc->signal_lens[idx] == 1) { - unsigned char val = mu[sig_offs]; - if (value_change_callback) { - xc->temp_signal_value_buf[0] = val; - xc->temp_signal_value_buf[1] = 0; - value_change_callback(user_callback_data_pointer, beg_tim, idx + 1, - xc->temp_signal_value_buf); - } else { - if (fv) { - char vcd_id[16]; - - int vcdid_len = fstVcdIDForFwrite(vcd_id + 1, idx + 1); - vcd_id[0] = val; /* collapse 3 writes into one I/O call */ - vcd_id[vcdid_len + 1] = '\n'; - fstWritex(xc, vcd_id, vcdid_len + 2); - } - } - } else { - /* variable-length ("0" length) records have no initial state */ - } - } else { - if (xc->signal_typs[idx] != FST_VT_VCD_REAL) { - if (value_change_callback) { - memcpy(xc->temp_signal_value_buf, mu + sig_offs, xc->signal_lens[idx]); - xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0; - value_change_callback(user_callback_data_pointer, beg_tim, idx + 1, - xc->temp_signal_value_buf); - } else { - if (fv) { - char vcd_id[16]; - int vcdid_len = fstVcdIDForFwrite(vcd_id + 1, idx + 1); - - vcd_id[0] = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; - fstWritex(xc, vcd_id, 1); - fstWritex(xc, mu + sig_offs, xc->signal_lens[idx]); - - vcd_id[0] = ' '; /* collapse 3 writes into one I/O call */ - vcd_id[vcdid_len + 1] = '\n'; - fstWritex(xc, vcd_id, vcdid_len + 2); - } - } - } else { - double d; - unsigned char *clone_d; - unsigned char *srcdata = mu + sig_offs; - - if (value_change_callback) { - if (xc->native_doubles_for_cb) { - if (xc->double_endian_match) { - clone_d = srcdata; - } else { - int j; - - clone_d = (unsigned char *)&d; - for (j = 0; j < 8; j++) { - clone_d[j] = srcdata[7 - j]; - } - } - value_change_callback(user_callback_data_pointer, beg_tim, idx + 1, clone_d); - } else { - clone_d = (unsigned char *)&d; - if (xc->double_endian_match) { - memcpy(clone_d, srcdata, 8); - } else { - int j; - - for (j = 0; j < 8; j++) { - clone_d[j] = srcdata[7 - j]; - } - } - sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); - value_change_callback(user_callback_data_pointer, beg_tim, idx + 1, - xc->temp_signal_value_buf); - } - } else { - if (fv) { - char vcdid_buf[16]; - char wx_buf[64]; - int wx_len; - - clone_d = (unsigned char *)&d; - if (xc->double_endian_match) { - memcpy(clone_d, srcdata, 8); - } else { - int j; - - for (j = 0; j < 8; j++) { - clone_d[j] = srcdata[7 - j]; - } - } - - fstVcdID(vcdid_buf, idx + 1); - wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf); - fstWritex(xc, wx_buf, wx_len); - } - } - } - } - } - - sig_offs += xc->signal_lens[idx]; - } - - free(mu); - fstReaderFseeko(xc, xc->f, -((fst_off_t)frame_clen), SEEK_CUR); - } - } - - fstReaderFseeko(xc, xc->f, (fst_off_t)frame_clen, SEEK_CUR); /* skip past compressed data */ - - vc_maxhandle = fstReaderVarint64(xc->f); - vc_start = ftello(xc->f); /* points to '!' character */ - packtype = fgetc(xc->f); - -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", (int)frame_uclen, - (int)frame_clen, (int)frame_maxhandle); - fprintf(stderr, FST_APIMESS "vc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype); -#endif - - indx_pntr = blkpos + seclen - 24 - tsec_clen - 8; - fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET); - chain_clen = fstReaderUint64(xc->f); - indx_pos = indx_pntr - chain_clen; -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); -#endif - chain_cmem = (unsigned char *)malloc(chain_clen); - if (!chain_cmem) - goto block_err; - fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); - fstFread(chain_cmem, chain_clen, 1, xc->f); - - if (vc_maxhandle > vc_maxhandle_largest) { - free(chain_table); - free(chain_table_lengths); - - vc_maxhandle_largest = vc_maxhandle; - chain_table = (fst_off_t *)calloc((vc_maxhandle + 1), sizeof(fst_off_t)); - chain_table_lengths = (uint32_t *)calloc((vc_maxhandle + 1), sizeof(uint32_t)); - } - - if (!chain_table || !chain_table_lengths) - goto block_err; - - pnt = chain_cmem; - idx = 0; - pval = 0; - - if (sectype == FST_BL_VCDATA_DYN_ALIAS2) { - uint32_t prev_alias = 0; - - do { - int skiplen; - - if (*pnt & 0x01) { - int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1; - if (shval > 0) { - pval = chain_table[idx] = pval + shval; - if (idx) { - chain_table_lengths[pidx] = pval - chain_table[pidx]; - } - pidx = idx++; - } else if (shval < 0) { - chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ - chain_table_lengths[idx] = prev_alias = - shval; /* because during this loop iter would give stale data! */ - idx++; - } else { - chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ - chain_table_lengths[idx] = - prev_alias; /* because during this loop iter would give stale data! */ - idx++; - } - } else { - uint64_t val = fstGetVarint32(pnt, &skiplen); - - fstHandle loopcnt = val >> 1; - for (i = 0; i < loopcnt; i++) { - chain_table[idx++] = 0; - } - } - - pnt += skiplen; - } while (pnt != (chain_cmem + chain_clen)); - } else { - do { - int skiplen; - uint64_t val = fstGetVarint32(pnt, &skiplen); - - if (!val) { - pnt += skiplen; - val = fstGetVarint32(pnt, &skiplen); - chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ - chain_table_lengths[idx] = -val; /* because during this loop iter would give stale data! */ - idx++; - } else if (val & 1) { - pval = chain_table[idx] = pval + (val >> 1); - if (idx) { - chain_table_lengths[pidx] = pval - chain_table[pidx]; - } - pidx = idx++; - } else { - fstHandle loopcnt = val >> 1; - for (i = 0; i < loopcnt; i++) { - chain_table[idx++] = 0; - } - } - - pnt += skiplen; - } while (pnt != (chain_cmem + chain_clen)); - } - - chain_table[idx] = indx_pos - vc_start; - chain_table_lengths[pidx] = chain_table[idx] - chain_table[pidx]; - - for (i = 0; i < idx; i++) { - int32_t v32 = chain_table_lengths[i]; - if ((v32 < 0) && (!chain_table[i])) { - v32 = -v32; - v32--; - if (((uint32_t)v32) < i) /* sanity check */ - { - chain_table[i] = chain_table[v32]; - chain_table_lengths[i] = chain_table_lengths[v32]; - } - } - } - -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "decompressed chain idx len: %" PRIu32 "\n", idx); -#endif - - mc_mem_len = 16384; - mc_mem = (unsigned char *)malloc(mc_mem_len); /* buffer for compressed reads */ - - /* check compressed VC data */ - if (idx > xc->maxhandle) - idx = xc->maxhandle; - for (i = 0; i < idx; i++) { - if (chain_table[i]) { - int process_idx = i / 8; - int process_bit = i & 7; - - if (xc->process_mask[process_idx] & (1 << process_bit)) { - int rc = Z_OK; - uint32_t val; - uint32_t skiplen; - uint32_t tdelta; - - fstReaderFseeko(xc, xc->f, vc_start + chain_table[i], SEEK_SET); - val = fstReaderVarint32WithSkip(xc->f, &skiplen); - if (val) { - unsigned char *mu = mem_for_traversal + traversal_mem_offs; /* uncomp: dst */ - unsigned char *mc; /* comp: src */ - unsigned long destlen = val; - unsigned long sourcelen = chain_table_lengths[i]; - - if (mc_mem_len < chain_table_lengths[i]) { - free(mc_mem); - mc_mem = (unsigned char *)malloc(mc_mem_len = chain_table_lengths[i]); - } - mc = mc_mem; - - fstFread(mc, chain_table_lengths[i], 1, xc->f); - - switch (packtype) { - case '4': - rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, - sourcelen, destlen, destlen)) - ? Z_OK - : Z_DATA_ERROR; - break; - case 'F': - fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */ - break; - default: - rc = uncompress(mu, &destlen, mc, sourcelen); - break; - } - - /* data to process is for(j=0;jf); - /* data to process is for(j=0;jsignal_lens[i] == 1) { - uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]); - uint32_t shcnt = 2 << (vli & 1); - tdelta = vli >> shcnt; - } else { - uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]); - tdelta = vli >> 1; - } - - scatterptr[i] = tc_head[tdelta]; - tc_head[tdelta] = i + 1; - } - } - } - - free(mc_mem); /* there is no usage below for this, no real need to clear out mc_mem or mc_mem_len */ - - for (i = 0; i < tsec_nitems; i++) { - uint32_t tdelta; - int skiplen, skiplen2; - uint32_t vli; - - if (fv) { - char wx_buf[32]; - int wx_len; - - if (time_table[i] != previous_time) { - if (xc->limit_range_valid) { - if (time_table[i] > xc->limit_range_end) { - break; - } - } - - if (dumpvars_state == 1) { - wx_len = sprintf(wx_buf, "$end\n"); - fstWritex(xc, wx_buf, wx_len); - dumpvars_state = 2; - } - wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]); - fstWritex(xc, wx_buf, wx_len); - if (!dumpvars_state) { - wx_len = sprintf(wx_buf, "$dumpvars\n"); - fstWritex(xc, wx_buf, wx_len); - dumpvars_state = 1; - } - - if ((xc->num_blackouts) && (cur_blackout != xc->num_blackouts)) { - if (time_table[i] == xc->blackout_times[cur_blackout]) { - wx_len = sprintf(wx_buf, "$dump%s $end\n", - (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); - fstWritex(xc, wx_buf, wx_len); - } - } - previous_time = time_table[i]; - } - } else { - if (time_table[i] != previous_time) { - if (xc->limit_range_valid) { - if (time_table[i] > xc->limit_range_end) { - break; - } - } - previous_time = time_table[i]; - } - } - - while (tc_head[i]) { - idx = tc_head[i] - 1; - vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); - - if (xc->signal_lens[idx] <= 1) { - if (xc->signal_lens[idx] == 1) { - unsigned char val; - if (!(vli & 1)) { - /* tdelta = vli >> 2; */ /* scan-build */ - val = ((vli >> 1) & 1) | '0'; - } else { - /* tdelta = vli >> 4; */ /* scan-build */ - val = FST_RCV_STR[((vli >> 1) & 7)]; - } - - if (value_change_callback) { - xc->temp_signal_value_buf[0] = val; - xc->temp_signal_value_buf[1] = 0; - value_change_callback(user_callback_data_pointer, time_table[i], idx + 1, - xc->temp_signal_value_buf); - } else { - if (fv) { - char vcd_id[16]; - int vcdid_len = fstVcdIDForFwrite(vcd_id + 1, idx + 1); - - vcd_id[0] = val; - vcd_id[vcdid_len + 1] = '\n'; - fstWritex(xc, vcd_id, vcdid_len + 2); - } - } - headptr[idx] += skiplen; - length_remaining[idx] -= skiplen; - - tc_head[i] = scatterptr[idx]; - scatterptr[idx] = 0; - - if (length_remaining[idx]) { - int shamt; - vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); - shamt = 2 << (vli & 1); - tdelta = vli >> shamt; - - scatterptr[idx] = tc_head[i + tdelta]; - tc_head[i + tdelta] = idx + 1; - } - } else { - unsigned char *vdata; - uint32_t len; - - vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); - len = fstGetVarint32(mem_for_traversal + headptr[idx] + skiplen, &skiplen2); - /* tdelta = vli >> 1; */ /* scan-build */ - skiplen += skiplen2; - vdata = mem_for_traversal + headptr[idx] + skiplen; - - if (!(vli & 1)) { - if (value_change_callback_varlen) { - value_change_callback_varlen(user_callback_data_pointer, time_table[i], idx + 1, vdata, - len); - } else { - if (fv) { - char vcd_id[16]; - int vcdid_len; - - vcd_id[0] = 's'; - fstWritex(xc, vcd_id, 1); - - vcdid_len = fstVcdIDForFwrite(vcd_id + 1, idx + 1); - { - unsigned char *vesc = (unsigned char *)malloc(len * 4 + 1); - int vlen = fstUtilityBinToEsc(vesc, vdata, len); - fstWritex(xc, vesc, vlen); - free(vesc); - } - - vcd_id[0] = ' '; - vcd_id[vcdid_len + 1] = '\n'; - fstWritex(xc, vcd_id, vcdid_len + 2); - } - } - } - - skiplen += len; - headptr[idx] += skiplen; - length_remaining[idx] -= skiplen; - - tc_head[i] = scatterptr[idx]; - scatterptr[idx] = 0; - - if (length_remaining[idx]) { - vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); - tdelta = vli >> 1; - - scatterptr[idx] = tc_head[i + tdelta]; - tc_head[i + tdelta] = idx + 1; - } - } - } else { - uint32_t len = xc->signal_lens[idx]; - unsigned char *vdata; - - vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); - /* tdelta = vli >> 1; */ /* scan-build */ - vdata = mem_for_traversal + headptr[idx] + skiplen; - - if (xc->signal_typs[idx] != FST_VT_VCD_REAL) { - if (!(vli & 1)) { - int byte = 0; - int bit; - unsigned int j; - - for (j = 0; j < len; j++) { - unsigned char ch; - byte = j / 8; - bit = 7 - (j & 7); - ch = ((vdata[byte] >> bit) & 1) | '0'; - xc->temp_signal_value_buf[j] = ch; - } - xc->temp_signal_value_buf[j] = 0; - - if (value_change_callback) { - value_change_callback(user_callback_data_pointer, time_table[i], idx + 1, - xc->temp_signal_value_buf); - } else { - if (fv) { - unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; - - fstWritex(xc, &ch_bp, 1); - fstWritex(xc, xc->temp_signal_value_buf, len); - } - } - - len = byte + 1; - } else { - if (value_change_callback) { - memcpy(xc->temp_signal_value_buf, vdata, len); - xc->temp_signal_value_buf[len] = 0; - value_change_callback(user_callback_data_pointer, time_table[i], idx + 1, - xc->temp_signal_value_buf); - } else { - if (fv) { - unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; - - fstWritex(xc, &ch_bp, 1); - fstWritex(xc, vdata, len); - } - } - } - } else { - double d; - unsigned char *clone_d /*= (unsigned char *)&d */; /* scan-build */ - unsigned char buf[8]; - unsigned char *srcdata; - - if (!(vli & 1)) /* very rare case, but possible */ - { - int bit; - int j; - - for (j = 0; j < 8; j++) { - unsigned char ch; - bit = 7 - (j & 7); - ch = ((vdata[0] >> bit) & 1) | '0'; - buf[j] = ch; - } - - len = 1; - srcdata = buf; - } else { - srcdata = vdata; - } - - if (value_change_callback) { - if (xc->native_doubles_for_cb) { - if (xc->double_endian_match) { - clone_d = srcdata; - } else { - int j; - - clone_d = (unsigned char *)&d; - for (j = 0; j < 8; j++) { - clone_d[j] = srcdata[7 - j]; - } - } - value_change_callback(user_callback_data_pointer, time_table[i], idx + 1, clone_d); - } else { - clone_d = (unsigned char *)&d; - if (xc->double_endian_match) { - memcpy(clone_d, srcdata, 8); - } else { - int j; - - for (j = 0; j < 8; j++) { - clone_d[j] = srcdata[7 - j]; - } - } - sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); - value_change_callback(user_callback_data_pointer, time_table[i], idx + 1, - xc->temp_signal_value_buf); - } - } else { - if (fv) { - char wx_buf[32]; - int wx_len; - - clone_d = (unsigned char *)&d; - if (xc->double_endian_match) { - memcpy(clone_d, srcdata, 8); - } else { - int j; - - for (j = 0; j < 8; j++) { - clone_d[j] = srcdata[7 - j]; - } - } - - wx_len = sprintf(wx_buf, "r%.16g", d); - fstWritex(xc, wx_buf, wx_len); - } - } - } - - if (fv) { - char vcd_id[16]; - int vcdid_len = fstVcdIDForFwrite(vcd_id + 1, idx + 1); - vcd_id[0] = ' '; - vcd_id[vcdid_len + 1] = '\n'; - fstWritex(xc, vcd_id, vcdid_len + 2); - } - - skiplen += len; - headptr[idx] += skiplen; - length_remaining[idx] -= skiplen; - - tc_head[i] = scatterptr[idx]; - scatterptr[idx] = 0; - - if (length_remaining[idx]) { - vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); - tdelta = vli >> 1; - - scatterptr[idx] = tc_head[i + tdelta]; - tc_head[i + tdelta] = idx + 1; - } - } - } - } - - block_err: - free(tc_head); - free(chain_cmem); - free(mem_for_traversal); - mem_for_traversal = NULL; - - secnum++; - if (secnum == xc->vc_section_count) - break; /* in case file is growing, keep with original block count */ - blkpos += seclen; - } - - if (mem_for_traversal) - free(mem_for_traversal); /* scan-build */ - free(length_remaining); - free(headptr); - free(scatterptr); - - if (chain_table) - free(chain_table); - if (chain_table_lengths) - free(chain_table_lengths); - - free(time_table); - -#ifndef FST_WRITEX_DISABLE - if (fv) { - fstWritex(xc, NULL, 0); - } -#endif - - return (1); -} - -/* rvat functions */ - -static char *fstExtractRvatDataFromFrame(struct fstReaderContext *xc, fstHandle facidx, char *buf) -{ - if (facidx >= xc->rvat_frame_maxhandle) { - return (NULL); - } - - if (xc->signal_lens[facidx] == 1) { - buf[0] = (char)xc->rvat_frame_data[xc->rvat_sig_offs[facidx]]; - buf[1] = 0; - } else { - if (xc->signal_typs[facidx] != FST_VT_VCD_REAL) { - memcpy(buf, xc->rvat_frame_data + xc->rvat_sig_offs[facidx], xc->signal_lens[facidx]); - buf[xc->signal_lens[facidx]] = 0; - } else { - double d; - unsigned char *clone_d = (unsigned char *)&d; - unsigned char *srcdata = xc->rvat_frame_data + xc->rvat_sig_offs[facidx]; - - if (xc->double_endian_match) { - memcpy(clone_d, srcdata, 8); - } else { - int j; - - for (j = 0; j < 8; j++) { - clone_d[j] = srcdata[7 - j]; - } - } - - sprintf((char *)buf, "%.16g", d); - } - } - - return (buf); -} - -char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf) -{ - struct fstReaderContext *xc = (struct fstReaderContext *)ctx; - fst_off_t blkpos = 0, prev_blkpos; - uint64_t beg_tim, end_tim, beg_tim2, end_tim2; - int sectype; - unsigned int secnum = 0; - uint64_t seclen; - uint64_t tsec_uclen = 0, tsec_clen = 0; - uint64_t tsec_nitems; - uint64_t frame_uclen, frame_clen; -#ifdef FST_DEBUG - uint64_t mem_required_for_traversal; -#endif - fst_off_t indx_pntr, indx_pos; - long chain_clen; - unsigned char *chain_cmem; - unsigned char *pnt; - fstHandle idx, pidx = 0, i; - uint64_t pval; - - if ((!xc) || (!facidx) || (facidx > xc->maxhandle) || (!buf) || (!xc->signal_lens[facidx - 1])) { - return (NULL); - } - - if (!xc->rvat_sig_offs) { - uint32_t cur_offs = 0; - - xc->rvat_sig_offs = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t)); - for (i = 0; i < xc->maxhandle; i++) { - xc->rvat_sig_offs[i] = cur_offs; - cur_offs += xc->signal_lens[i]; - } - } - - if (xc->rvat_data_valid) { - if ((xc->rvat_beg_tim <= tim) && (tim <= xc->rvat_end_tim)) { - goto process_value; - } - - fstReaderDeallocateRvatData(xc); - } - - xc->rvat_chain_pos_valid = 0; - - for (;;) { - fstReaderFseeko(xc, xc->f, (prev_blkpos = blkpos), SEEK_SET); - - sectype = fgetc(xc->f); - seclen = fstReaderUint64(xc->f); - - if ((sectype == EOF) || (sectype == FST_BL_SKIP) || (!seclen)) { - return (NULL); /* if this loop exits on break, it's successful */ - } - - blkpos++; - if ((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && - (sectype != FST_BL_VCDATA_DYN_ALIAS2)) { - blkpos += seclen; - continue; - } - - beg_tim = fstReaderUint64(xc->f); - end_tim = fstReaderUint64(xc->f); - - if ((beg_tim <= tim) && (tim <= end_tim)) { - if ((tim == end_tim) && (tim != xc->end_time)) { - fst_off_t cached_pos = ftello(xc->f); - fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); - - sectype = fgetc(xc->f); - seclen = fstReaderUint64(xc->f); - - beg_tim2 = fstReaderUint64(xc->f); - end_tim2 = fstReaderUint64(xc->f); - - if (((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && - (sectype != FST_BL_VCDATA_DYN_ALIAS2)) || - (!seclen) || (beg_tim2 != tim)) { - blkpos = prev_blkpos; - break; - } - beg_tim = beg_tim2; - end_tim = end_tim2; - fstReaderFseeko(xc, xc->f, cached_pos, SEEK_SET); - } - break; - } - - blkpos += seclen; - secnum++; - } - - xc->rvat_beg_tim = beg_tim; - xc->rvat_end_tim = end_tim; - -#ifdef FST_DEBUG - mem_required_for_traversal = -#endif - fstReaderUint64(xc->f); - -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "rvat sec: %u seclen: %d begtim: %d endtim: %d\n", secnum, (int)seclen, (int)beg_tim, - (int)end_tim); - fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal); -#endif - - /* process time block */ - { - unsigned char *ucdata; - unsigned char *cdata; - unsigned long destlen /* = tsec_uclen */; /* scan-build */ - unsigned long sourcelen /* = tsec_clen */; /* scan-build */ - int rc; - unsigned char *tpnt; - uint64_t tpval; - unsigned int ti; - - fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET); - tsec_uclen = fstReaderUint64(xc->f); - tsec_clen = fstReaderUint64(xc->f); - tsec_nitems = fstReaderUint64(xc->f); -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "time section unc: %d, com: %d (%d items)\n", (int)tsec_uclen, (int)tsec_clen, - (int)tsec_nitems); -#endif - ucdata = (unsigned char *)malloc(tsec_uclen); - destlen = tsec_uclen; - sourcelen = tsec_clen; - - fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR); - if (tsec_uclen != tsec_clen) { - cdata = (unsigned char *)malloc(tsec_clen); - fstFread(cdata, tsec_clen, 1, xc->f); - - rc = uncompress(ucdata, &destlen, cdata, sourcelen); - - if (rc != Z_OK) { - fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), tsec uncompress rc = %d, exiting.\n", - rc); - exit(255); - } - - free(cdata); - } else { - fstFread(ucdata, tsec_uclen, 1, xc->f); - } - - xc->rvat_time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t)); - tpnt = ucdata; - tpval = 0; - for (ti = 0; ti < tsec_nitems; ti++) { - int skiplen; - uint64_t val = fstGetVarint64(tpnt, &skiplen); - tpval = xc->rvat_time_table[ti] = tpval + val; - tpnt += skiplen; - } - - free(ucdata); - } - - fstReaderFseeko(xc, xc->f, blkpos + 32, SEEK_SET); - - frame_uclen = fstReaderVarint64(xc->f); - frame_clen = fstReaderVarint64(xc->f); - xc->rvat_frame_maxhandle = fstReaderVarint64(xc->f); - xc->rvat_frame_data = (unsigned char *)malloc(frame_uclen); - - if (frame_uclen == frame_clen) { - fstFread(xc->rvat_frame_data, frame_uclen, 1, xc->f); - } else { - unsigned char *mc = (unsigned char *)malloc(frame_clen); - int rc; - - unsigned long destlen = frame_uclen; - unsigned long sourcelen = frame_clen; - - fstFread(mc, sourcelen, 1, xc->f); - rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen); - if (rc != Z_OK) { - fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), frame decompress rc: %d, exiting.\n", rc); - exit(255); - } - free(mc); - } - - xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f); - xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */ - xc->rvat_packtype = fgetc(xc->f); - -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", (int)frame_uclen, - (int)frame_clen, (int)xc->rvat_frame_maxhandle); - fprintf(stderr, FST_APIMESS "vc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle); -#endif - - indx_pntr = blkpos + seclen - 24 - tsec_clen - 8; - fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET); - chain_clen = fstReaderUint64(xc->f); - indx_pos = indx_pntr - chain_clen; -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); -#endif - chain_cmem = (unsigned char *)malloc(chain_clen); - fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); - fstFread(chain_cmem, chain_clen, 1, xc->f); - - xc->rvat_chain_table = (fst_off_t *)calloc((xc->rvat_vc_maxhandle + 1), sizeof(fst_off_t)); - xc->rvat_chain_table_lengths = (uint32_t *)calloc((xc->rvat_vc_maxhandle + 1), sizeof(uint32_t)); - - pnt = chain_cmem; - idx = 0; - pval = 0; - - if (sectype == FST_BL_VCDATA_DYN_ALIAS2) { - uint32_t prev_alias = 0; - - do { - int skiplen; - - if (*pnt & 0x01) { - int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1; - if (shval > 0) { - pval = xc->rvat_chain_table[idx] = pval + shval; - if (idx) { - xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; - } - pidx = idx++; - } else if (shval < 0) { - xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ - xc->rvat_chain_table_lengths[idx] = prev_alias = - shval; /* because during this loop iter would give stale data! */ - idx++; - } else { - xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */ - xc->rvat_chain_table_lengths[idx] = - prev_alias; /* because during this loop iter would give stale data! */ - idx++; - } - } else { - uint64_t val = fstGetVarint32(pnt, &skiplen); - - fstHandle loopcnt = val >> 1; - for (i = 0; i < loopcnt; i++) { - xc->rvat_chain_table[idx++] = 0; - } - } - - pnt += skiplen; - } while (pnt != (chain_cmem + chain_clen)); - } else { - do { - int skiplen; - uint64_t val = fstGetVarint32(pnt, &skiplen); - - if (!val) { - pnt += skiplen; - val = fstGetVarint32(pnt, &skiplen); - xc->rvat_chain_table[idx] = 0; - xc->rvat_chain_table_lengths[idx] = -val; - idx++; - } else if (val & 1) { - pval = xc->rvat_chain_table[idx] = pval + (val >> 1); - if (idx) { - xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; - } - pidx = idx++; - } else { - fstHandle loopcnt = val >> 1; - for (i = 0; i < loopcnt; i++) { - xc->rvat_chain_table[idx++] = 0; - } - } - - pnt += skiplen; - } while (pnt != (chain_cmem + chain_clen)); - } - - free(chain_cmem); - xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start; - xc->rvat_chain_table_lengths[pidx] = xc->rvat_chain_table[idx] - xc->rvat_chain_table[pidx]; - - for (i = 0; i < idx; i++) { - int32_t v32 = xc->rvat_chain_table_lengths[i]; - if ((v32 < 0) && (!xc->rvat_chain_table[i])) { - v32 = -v32; - v32--; - if (((uint32_t)v32) < i) /* sanity check */ - { - xc->rvat_chain_table[i] = xc->rvat_chain_table[v32]; - xc->rvat_chain_table_lengths[i] = xc->rvat_chain_table_lengths[v32]; - } - } - } - -#ifdef FST_DEBUG - fprintf(stderr, FST_APIMESS "decompressed chain idx len: %" PRIu32 "\n", idx); -#endif - - xc->rvat_data_valid = 1; - -/* all data at this point is loaded or resident in fst cache, process and return appropriate value */ -process_value: - if (facidx > xc->rvat_vc_maxhandle) { - return (NULL); - } - - facidx--; /* scale down for array which starts at zero */ - - if (((tim == xc->rvat_beg_tim) && (!xc->rvat_chain_table[facidx])) || (!xc->rvat_chain_table[facidx])) { - return (fstExtractRvatDataFromFrame(xc, facidx, buf)); - } - - if (facidx != xc->rvat_chain_facidx) { - if (xc->rvat_chain_mem) { - free(xc->rvat_chain_mem); - xc->rvat_chain_mem = NULL; - - xc->rvat_chain_pos_valid = 0; - } - } - - if (!xc->rvat_chain_mem) { - uint32_t skiplen; - fstReaderFseeko(xc, xc->f, xc->rvat_vc_start + xc->rvat_chain_table[facidx], SEEK_SET); - xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen); - if (xc->rvat_chain_len) { - unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len); - unsigned char *mc = (unsigned char *)malloc(xc->rvat_chain_table_lengths[facidx]); - unsigned long destlen = xc->rvat_chain_len; - unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx]; - int rc = Z_OK; - - fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f); - - switch (xc->rvat_packtype) { - case '4': - rc = (destlen == - (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) - ? Z_OK - : Z_DATA_ERROR; - break; - case 'F': - fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */ - break; - default: - rc = uncompress(mu, &destlen, mc, sourcelen); - break; - } - - free(mc); - - if (rc != Z_OK) { - fprintf(stderr, - FST_APIMESS "fstReaderGetValueFromHandleAtTime(), rvat decompress clen: %d (rc=%d), exiting.\n", - (int)xc->rvat_chain_len, rc); - exit(255); - } - - /* data to process is for(j=0;jrvat_chain_mem = mu; - } else { - int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen; - unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len = destlen); - fstFread(mu, destlen, 1, xc->f); - /* data to process is for(j=0;jrvat_chain_mem = mu; - } - - xc->rvat_chain_facidx = facidx; - } - - /* process value chain here */ - - { - uint32_t tidx = 0, ptidx = 0; - uint32_t tdelta; - int skiplen; - unsigned int iprev = xc->rvat_chain_len; - uint32_t pvli = 0; - int pskip = 0; - - if ((xc->rvat_chain_pos_valid) && (tim >= xc->rvat_chain_pos_time)) { - i = xc->rvat_chain_pos_idx; - tidx = xc->rvat_chain_pos_tidx; - } else { - i = 0; - tidx = 0; - xc->rvat_chain_pos_time = xc->rvat_beg_tim; - } - - if (xc->signal_lens[facidx] == 1) { - while (i < xc->rvat_chain_len) { - uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen); - uint32_t shcnt = 2 << (vli & 1); - tdelta = vli >> shcnt; - - if (xc->rvat_time_table[tidx + tdelta] <= tim) { - iprev = i; - pvli = vli; - ptidx = tidx; - /* pskip = skiplen; */ /* scan-build */ - - tidx += tdelta; - i += skiplen; - } else { - break; - } - } - if (iprev != xc->rvat_chain_len) { - xc->rvat_chain_pos_tidx = ptidx; - xc->rvat_chain_pos_idx = iprev; - xc->rvat_chain_pos_time = tim; - xc->rvat_chain_pos_valid = 1; - - if (!(pvli & 1)) { - buf[0] = ((pvli >> 1) & 1) | '0'; - } else { - buf[0] = FST_RCV_STR[((pvli >> 1) & 7)]; - } - buf[1] = 0; - return (buf); - } else { - return (fstExtractRvatDataFromFrame(xc, facidx, buf)); - } - } else { - while (i < xc->rvat_chain_len) { - uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen); - tdelta = vli >> 1; - - if (xc->rvat_time_table[tidx + tdelta] <= tim) { - iprev = i; - pvli = vli; - ptidx = tidx; - pskip = skiplen; - - tidx += tdelta; - i += skiplen; - - if (!(pvli & 1)) { - i += ((xc->signal_lens[facidx] + 7) / 8); - } else { - i += xc->signal_lens[facidx]; - } - } else { - break; - } - } - - if (iprev != xc->rvat_chain_len) { - unsigned char *vdata = xc->rvat_chain_mem + iprev + pskip; - - xc->rvat_chain_pos_tidx = ptidx; - xc->rvat_chain_pos_idx = iprev; - xc->rvat_chain_pos_time = tim; - xc->rvat_chain_pos_valid = 1; - - if (xc->signal_typs[facidx] != FST_VT_VCD_REAL) { - if (!(pvli & 1)) { - int byte = 0; - int bit; - unsigned int j; - - for (j = 0; j < xc->signal_lens[facidx]; j++) { - unsigned char ch; - byte = j / 8; - bit = 7 - (j & 7); - ch = ((vdata[byte] >> bit) & 1) | '0'; - buf[j] = ch; - } - buf[j] = 0; - - return (buf); - } else { - memcpy(buf, vdata, xc->signal_lens[facidx]); - buf[xc->signal_lens[facidx]] = 0; - return (buf); - } - } else { - double d; - unsigned char *clone_d = (unsigned char *)&d; - unsigned char bufd[8]; - unsigned char *srcdata; - - if (!(pvli & 1)) /* very rare case, but possible */ - { - int bit; - int j; - - for (j = 0; j < 8; j++) { - unsigned char ch; - bit = 7 - (j & 7); - ch = ((vdata[0] >> bit) & 1) | '0'; - bufd[j] = ch; - } - - srcdata = bufd; - } else { - srcdata = vdata; - } - - if (xc->double_endian_match) { - memcpy(clone_d, srcdata, 8); - } else { - int j; - - for (j = 0; j < 8; j++) { - clone_d[j] = srcdata[7 - j]; - } - } - - sprintf(buf, "r%.16g", d); - return (buf); - } - } else { - return (fstExtractRvatDataFromFrame(xc, facidx, buf)); - } - } - } - - /* return(NULL); */ -} - -/**********************************************************************/ -#ifndef _WAVE_HAVE_JUDY - -/***********************/ -/*** ***/ -/*** jenkins hash ***/ -/*** ***/ -/***********************/ - -/* --------------------------------------------------------------------- -mix -- mix 3 32-bit values reversibly. -For every delta with one or two bits set, and the deltas of all three - high bits or all three low bits, whether the original value of a,b,c - is almost all zero or is uniformly distributed, -* If mix() is run forward or backward, at least 32 bits in a,b,c - have at least 1/4 probability of changing. -* If mix() is run forward, every bit of c will change between 1/3 and - 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) -mix() was built out of 36 single-cycle latency instructions in a - structure that could supported 2x parallelism, like so: - a -= b; - a -= c; x = (c>>13); - b -= c; a ^= x; - b -= a; x = (a<<8); - c -= a; b ^= x; - c -= b; x = (b>>13); - ... - Unfortunately, superscalar Pentiums and Sparcs can't take advantage - of that parallelism. They've also turned some of those single-cycle - latency instructions into multi-cycle latency instructions. Still, - this is the fastest good hash I could find. There were about 2^^68 - to choose from. I only looked at a billion or so. --------------------------------------------------------------------- -*/ -#define mix(a, b, c) \ - { \ - a -= b; \ - a -= c; \ - a ^= (c >> 13); \ - b -= c; \ - b -= a; \ - b ^= (a << 8); \ - c -= a; \ - c -= b; \ - c ^= (b >> 13); \ - a -= b; \ - a -= c; \ - a ^= (c >> 12); \ - b -= c; \ - b -= a; \ - b ^= (a << 16); \ - c -= a; \ - c -= b; \ - c ^= (b >> 5); \ - a -= b; \ - a -= c; \ - a ^= (c >> 3); \ - b -= c; \ - b -= a; \ - b ^= (a << 10); \ - c -= a; \ - c -= b; \ - c ^= (b >> 15); \ - } - -/* --------------------------------------------------------------------- -j_hash() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - len : the length of the key, counting by bytes - initval : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Every 1-bit and 2-bit delta achieves avalanche. -About 6*len+35 instructions. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (uint8_t **)k, do it like this: - for (i=0, h=0; i= 12) { - a += (k[0] + ((uint32_t)k[1] << 8) + ((uint32_t)k[2] << 16) + ((uint32_t)k[3] << 24)); - b += (k[4] + ((uint32_t)k[5] << 8) + ((uint32_t)k[6] << 16) + ((uint32_t)k[7] << 24)); - c += (k[8] + ((uint32_t)k[9] << 8) + ((uint32_t)k[10] << 16) + ((uint32_t)k[11] << 24)); - mix(a, b, c); - k += 12; - len -= 12; - } - - /*------------------------------------- handle the last 11 bytes */ - c += length; - switch (len) /* all the case statements fall through */ - { - case 11: - c += ((uint32_t)k[10] << 24); /* fallthrough */ - case 10: - c += ((uint32_t)k[9] << 16); /* fallthrough */ - case 9: - c += ((uint32_t)k[8] << 8); /* fallthrough */ - /* the first byte of c is reserved for the length */ - case 8: - b += ((uint32_t)k[7] << 24); /* fallthrough */ - case 7: - b += ((uint32_t)k[6] << 16); /* fallthrough */ - case 6: - b += ((uint32_t)k[5] << 8); /* fallthrough */ - case 5: - b += k[4]; /* fallthrough */ - case 4: - a += ((uint32_t)k[3] << 24); /* fallthrough */ - case 3: - a += ((uint32_t)k[2] << 16); /* fallthrough */ - case 2: - a += ((uint32_t)k[1] << 8); /* fallthrough */ - case 1: - a += k[0]; - /* case 0: nothing left to add */ - } - mix(a, b, c); - /*-------------------------------------------- report the result */ - return (c); -} - -/********************************************************************/ - -/***************************/ -/*** ***/ -/*** judy HS emulation ***/ -/*** ***/ -/***************************/ - -struct collchain_t -{ - struct collchain_t *next; - void *payload; - uint32_t fullhash, length; - unsigned char mem[1]; -}; - -void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask) -{ - struct collchain_t ***base = (struct collchain_t ***)base_i; - uint32_t hf, h; - struct collchain_t **ar; - struct collchain_t *chain, *pchain; - - if (!*base) { - *base = (struct collchain_t **)calloc(1, (hashmask + 1) * sizeof(void *)); - } - ar = *base; - - h = (hf = j_hash(mem, length, length)) & hashmask; - pchain = chain = ar[h]; - while (chain) { - if ((chain->fullhash == hf) && (chain->length == length) && !memcmp(chain->mem, mem, length)) { - if (pchain != chain) /* move hit to front */ - { - pchain->next = chain->next; - chain->next = ar[h]; - ar[h] = chain; - } - return (&(chain->payload)); - } - - pchain = chain; - chain = chain->next; - } - - chain = (struct collchain_t *)calloc(1, sizeof(struct collchain_t) + length - 1); - memcpy(chain->mem, mem, length); - chain->fullhash = hf; - chain->length = length; - chain->next = ar[h]; - ar[h] = chain; - return (&(chain->payload)); -} - -void JenkinsFree(void *base_i, uint32_t hashmask) -{ - struct collchain_t ***base = (struct collchain_t ***)base_i; - uint32_t h; - struct collchain_t **ar; - struct collchain_t *chain, *chain_next; - - if (base && *base) { - ar = *base; - for (h = 0; h <= hashmask; h++) { - chain = ar[h]; - while (chain) { - chain_next = chain->next; - free(chain); - chain = chain_next; - } - } - - free(*base); - *base = NULL; - } -} - -#endif - -/**********************************************************************/ - -/************************/ -/*** ***/ -/*** utility function ***/ -/*** ***/ -/************************/ - -int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len) -{ - const unsigned char *src = s; - int dlen = 0; - int i; - - for (i = 0; i < len; i++) { - switch (src[i]) { - case '\a': /* fallthrough */ - case '\b': /* fallthrough */ - case '\f': /* fallthrough */ - case '\n': /* fallthrough */ - case '\r': /* fallthrough */ - case '\t': /* fallthrough */ - case '\v': /* fallthrough */ - case '\'': /* fallthrough */ - case '\"': /* fallthrough */ - case '\\': /* fallthrough */ - case '\?': - dlen += 2; - break; - default: - if ((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */ - { - dlen++; - } else { - dlen += 4; - } - break; - } - } - - return (dlen); -} - -int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len) -{ - const unsigned char *src = s; - unsigned char *dst = d; - unsigned char val; - int i; - - for (i = 0; i < len; i++) { - switch (src[i]) { - case '\a': - *(dst++) = '\\'; - *(dst++) = 'a'; - break; - case '\b': - *(dst++) = '\\'; - *(dst++) = 'b'; - break; - case '\f': - *(dst++) = '\\'; - *(dst++) = 'f'; - break; - case '\n': - *(dst++) = '\\'; - *(dst++) = 'n'; - break; - case '\r': - *(dst++) = '\\'; - *(dst++) = 'r'; - break; - case '\t': - *(dst++) = '\\'; - *(dst++) = 't'; - break; - case '\v': - *(dst++) = '\\'; - *(dst++) = 'v'; - break; - case '\'': - *(dst++) = '\\'; - *(dst++) = '\''; - break; - case '\"': - *(dst++) = '\\'; - *(dst++) = '\"'; - break; - case '\\': - *(dst++) = '\\'; - *(dst++) = '\\'; - break; - case '\?': - *(dst++) = '\\'; - *(dst++) = '\?'; - break; - default: - if ((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */ - { - *(dst++) = src[i]; - } else { - val = src[i]; - *(dst++) = '\\'; - *(dst++) = (val / 64) + '0'; - val = val & 63; - *(dst++) = (val / 8) + '0'; - val = val & 7; - *(dst++) = (val) + '0'; - } - break; - } - } - - return (dst - d); -} - -/* - * this overwrites the original string if the destination pointer is NULL - */ -int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len) -{ - unsigned char *src = s; - unsigned char *dst = (!d) ? s : (s = d); - unsigned char val[3]; - int i; - - for (i = 0; i < len; i++) { - if (src[i] != '\\') { - *(dst++) = src[i]; - } else { - switch (src[++i]) { - case 'a': - *(dst++) = '\a'; - break; - case 'b': - *(dst++) = '\b'; - break; - case 'f': - *(dst++) = '\f'; - break; - case 'n': - *(dst++) = '\n'; - break; - case 'r': - *(dst++) = '\r'; - break; - case 't': - *(dst++) = '\t'; - break; - case 'v': - *(dst++) = '\v'; - break; - case '\'': - *(dst++) = '\''; - break; - case '\"': - *(dst++) = '\"'; - break; - case '\\': - *(dst++) = '\\'; - break; - case '\?': - *(dst++) = '\?'; - break; - - case 'x': - val[0] = toupper(src[++i]); - val[1] = toupper(src[++i]); - val[0] = ((val[0] >= 'A') && (val[0] <= 'F')) ? (val[0] - 'A' + 10) : (val[0] - '0'); - val[1] = ((val[1] >= 'A') && (val[1] <= 'F')) ? (val[1] - 'A' + 10) : (val[1] - '0'); - *(dst++) = val[0] * 16 + val[1]; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - val[0] = src[i] - '0'; - val[1] = src[++i] - '0'; - val[2] = src[++i] - '0'; - *(dst++) = val[0] * 64 + val[1] * 8 + val[2]; - break; - - default: - *(dst++) = src[i]; - break; - } - } - } - - return (dst - s); -} - -struct fstETab *fstUtilityExtractEnumTableFromString(const char *s) -{ - struct fstETab *et = NULL; - int num_spaces = 0; - int i; - int newlen; - - if (s) { - const char *csp = strchr(s, ' '); - int cnt = atoi(csp + 1); - - for (;;) { - csp = strchr(csp + 1, ' '); - if (csp) { - num_spaces++; - } else { - break; - } - } - - if (num_spaces == (2 * cnt)) { - char *sp, *sp2; - - et = (struct fstETab *)calloc(1, sizeof(struct fstETab)); - et->elem_count = cnt; - et->name = strdup(s); - et->literal_arr = (char **)calloc(cnt, sizeof(char *)); - et->val_arr = (char **)calloc(cnt, sizeof(char *)); - - sp = strchr(et->name, ' '); - *sp = 0; - - sp = strchr(sp + 1, ' '); - - for (i = 0; i < cnt; i++) { - sp2 = strchr(sp + 1, ' '); - *(char *)sp2 = 0; - et->literal_arr[i] = sp + 1; - sp = sp2; - - newlen = fstUtilityEscToBin(NULL, (unsigned char *)et->literal_arr[i], strlen(et->literal_arr[i])); - et->literal_arr[i][newlen] = 0; - } - - for (i = 0; i < cnt; i++) { - sp2 = strchr(sp + 1, ' '); - if (sp2) { - *sp2 = 0; - } - et->val_arr[i] = sp + 1; - sp = sp2; - - newlen = fstUtilityEscToBin(NULL, (unsigned char *)et->val_arr[i], strlen(et->val_arr[i])); - et->val_arr[i][newlen] = 0; - } - } - } - - return (et); -} - -void fstUtilityFreeEnumTable(struct fstETab *etab) -{ - if (etab) { - free(etab->literal_arr); - free(etab->val_arr); - free(etab->name); - free(etab); - } -} diff --git a/yosys/libs/fst/fstapi.h b/yosys/libs/fst/fstapi.h deleted file mode 100644 index a5e0971a16b..00000000000 --- a/yosys/libs/fst/fstapi.h +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (c) 2009-2018 Tony Bybell. - * - * 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. - * - * SPDX-License-Identifier: MIT - */ - -#ifndef FST_API_H -#define FST_API_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include -#if defined(_MSC_VER) -#include "libs/zlib/zlib.h" -#include - -#include - -#define ftruncate _chsize_s -#define unlink _unlink -#define fileno _fileno -#define lseek _lseeki64 - -#ifdef _WIN64 -#define ssize_t __int64 -#define SSIZE_MAX 9223372036854775807i64 -#else -#define ssize_t long -#define SSIZE_MAX 2147483647L -#endif - -#include "stdint.h" -#else -#include -#include -#endif -#include - -#define FST_RDLOAD "FSTLOAD | " - -typedef uint32_t fstHandle; -typedef uint32_t fstEnumHandle; - -enum fstWriterPackType -{ - FST_WR_PT_ZLIB = 0, - FST_WR_PT_FASTLZ = 1, - FST_WR_PT_LZ4 = 2 -}; - -enum fstFileType -{ - FST_FT_MIN = 0, - - FST_FT_VERILOG = 0, - FST_FT_VHDL = 1, - FST_FT_VERILOG_VHDL = 2, - - FST_FT_MAX = 2 -}; - -enum fstBlockType -{ - FST_BL_HDR = 0, - FST_BL_VCDATA = 1, - FST_BL_BLACKOUT = 2, - FST_BL_GEOM = 3, - FST_BL_HIER = 4, - FST_BL_VCDATA_DYN_ALIAS = 5, - FST_BL_HIER_LZ4 = 6, - FST_BL_HIER_LZ4DUO = 7, - FST_BL_VCDATA_DYN_ALIAS2 = 8, - - FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */ - FST_BL_SKIP = 255 /* used while block is being written */ -}; - -enum fstScopeType -{ - FST_ST_MIN = 0, - - FST_ST_VCD_MODULE = 0, - FST_ST_VCD_TASK = 1, - FST_ST_VCD_FUNCTION = 2, - FST_ST_VCD_BEGIN = 3, - FST_ST_VCD_FORK = 4, - FST_ST_VCD_GENERATE = 5, - FST_ST_VCD_STRUCT = 6, - FST_ST_VCD_UNION = 7, - FST_ST_VCD_CLASS = 8, - FST_ST_VCD_INTERFACE = 9, - FST_ST_VCD_PACKAGE = 10, - FST_ST_VCD_PROGRAM = 11, - - FST_ST_VHDL_ARCHITECTURE = 12, - FST_ST_VHDL_PROCEDURE = 13, - FST_ST_VHDL_FUNCTION = 14, - FST_ST_VHDL_RECORD = 15, - FST_ST_VHDL_PROCESS = 16, - FST_ST_VHDL_BLOCK = 17, - FST_ST_VHDL_FOR_GENERATE = 18, - FST_ST_VHDL_IF_GENERATE = 19, - FST_ST_VHDL_GENERATE = 20, - FST_ST_VHDL_PACKAGE = 21, - - FST_ST_MAX = 21, - - FST_ST_GEN_ATTRBEGIN = 252, - FST_ST_GEN_ATTREND = 253, - - FST_ST_VCD_SCOPE = 254, - FST_ST_VCD_UPSCOPE = 255 -}; - -enum fstVarType -{ - FST_VT_MIN = 0, /* start of vartypes */ - - FST_VT_VCD_EVENT = 0, - FST_VT_VCD_INTEGER = 1, - FST_VT_VCD_PARAMETER = 2, - FST_VT_VCD_REAL = 3, - FST_VT_VCD_REAL_PARAMETER = 4, - FST_VT_VCD_REG = 5, - FST_VT_VCD_SUPPLY0 = 6, - FST_VT_VCD_SUPPLY1 = 7, - FST_VT_VCD_TIME = 8, - FST_VT_VCD_TRI = 9, - FST_VT_VCD_TRIAND = 10, - FST_VT_VCD_TRIOR = 11, - FST_VT_VCD_TRIREG = 12, - FST_VT_VCD_TRI0 = 13, - FST_VT_VCD_TRI1 = 14, - FST_VT_VCD_WAND = 15, - FST_VT_VCD_WIRE = 16, - FST_VT_VCD_WOR = 17, - FST_VT_VCD_PORT = 18, - FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */ - FST_VT_VCD_REALTIME = 20, - - FST_VT_GEN_STRING = - 21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */ - - FST_VT_SV_BIT = 22, - FST_VT_SV_LOGIC = 23, - FST_VT_SV_INT = 24, /* declare as size = 32 */ - FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */ - FST_VT_SV_LONGINT = 26, /* declare as size = 64 */ - FST_VT_SV_BYTE = 27, /* declare as size = 8 */ - FST_VT_SV_ENUM = 28, /* declare as appropriate type range */ - FST_VT_SV_SHORTREAL = - 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */ - - FST_VT_MAX = 29 /* end of vartypes */ -}; - -enum fstVarDir -{ - FST_VD_MIN = 0, - - FST_VD_IMPLICIT = 0, - FST_VD_INPUT = 1, - FST_VD_OUTPUT = 2, - FST_VD_INOUT = 3, - FST_VD_BUFFER = 4, - FST_VD_LINKAGE = 5, - - FST_VD_MAX = 5 -}; - -enum fstHierType -{ - FST_HT_MIN = 0, - - FST_HT_SCOPE = 0, - FST_HT_UPSCOPE = 1, - FST_HT_VAR = 2, - FST_HT_ATTRBEGIN = 3, - FST_HT_ATTREND = 4, - - /* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when fstHier bridges other - formats */ - FST_HT_TREEBEGIN = 5, - FST_HT_TREEEND = 6, - - FST_HT_MAX = 6 -}; - -enum fstAttrType -{ - FST_AT_MIN = 0, - - FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */ - FST_AT_ARRAY = 1, - FST_AT_ENUM = 2, - FST_AT_PACK = 3, - - FST_AT_MAX = 3 -}; - -enum fstMiscType -{ - FST_MT_MIN = 0, - - FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */ - FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */ - FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */ - FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */ - FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */ - FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */ - FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */ - FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */ - FST_MT_UNKNOWN = 8, - - FST_MT_MAX = 8 -}; - -enum fstArrayType -{ - FST_AR_MIN = 0, - - FST_AR_NONE = 0, - FST_AR_UNPACKED = 1, - FST_AR_PACKED = 2, - FST_AR_SPARSE = 3, - - FST_AR_MAX = 3 -}; - -enum fstEnumValueType -{ - FST_EV_SV_INTEGER = 0, - FST_EV_SV_BIT = 1, - FST_EV_SV_LOGIC = 2, - FST_EV_SV_INT = 3, - FST_EV_SV_SHORTINT = 4, - FST_EV_SV_LONGINT = 5, - FST_EV_SV_BYTE = 6, - FST_EV_SV_UNSIGNED_INTEGER = 7, - FST_EV_SV_UNSIGNED_BIT = 8, - FST_EV_SV_UNSIGNED_LOGIC = 9, - FST_EV_SV_UNSIGNED_INT = 10, - FST_EV_SV_UNSIGNED_SHORTINT = 11, - FST_EV_SV_UNSIGNED_LONGINT = 12, - FST_EV_SV_UNSIGNED_BYTE = 13, - - FST_EV_REG = 14, - FST_EV_TIME = 15, - - FST_EV_MAX = 15 -}; - -enum fstPackType -{ - FST_PT_NONE = 0, - FST_PT_UNPACKED = 1, - FST_PT_PACKED = 2, - FST_PT_TAGGED_PACKED = 3, - - FST_PT_MAX = 3 -}; - -enum fstSupplementalVarType -{ - FST_SVT_MIN = 0, - - FST_SVT_NONE = 0, - - FST_SVT_VHDL_SIGNAL = 1, - FST_SVT_VHDL_VARIABLE = 2, - FST_SVT_VHDL_CONSTANT = 3, - FST_SVT_VHDL_FILE = 4, - FST_SVT_VHDL_MEMORY = 5, - - FST_SVT_MAX = 5 -}; - -enum fstSupplementalDataType -{ - FST_SDT_MIN = 0, - - FST_SDT_NONE = 0, - - FST_SDT_VHDL_BOOLEAN = 1, - FST_SDT_VHDL_BIT = 2, - FST_SDT_VHDL_BIT_VECTOR = 3, - FST_SDT_VHDL_STD_ULOGIC = 4, - FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5, - FST_SDT_VHDL_STD_LOGIC = 6, - FST_SDT_VHDL_STD_LOGIC_VECTOR = 7, - FST_SDT_VHDL_UNSIGNED = 8, - FST_SDT_VHDL_SIGNED = 9, - FST_SDT_VHDL_INTEGER = 10, - FST_SDT_VHDL_REAL = 11, - FST_SDT_VHDL_NATURAL = 12, - FST_SDT_VHDL_POSITIVE = 13, - FST_SDT_VHDL_TIME = 14, - FST_SDT_VHDL_CHARACTER = 15, - FST_SDT_VHDL_STRING = 16, - - FST_SDT_MAX = 16, - - FST_SDT_SVT_SHIFT_COUNT = - 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */ - FST_SDT_ABS_MAX = ((1 << (FST_SDT_SVT_SHIFT_COUNT)) - 1) -}; - -struct fstHier -{ - unsigned char htyp; - - union - { - /* if htyp == FST_HT_SCOPE */ - struct fstHierScope - { - unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */ - const char *name; - const char *component; - uint32_t name_length; /* strlen(u.scope.name) */ - uint32_t component_length; /* strlen(u.scope.component) */ - } scope; - - /* if htyp == FST_HT_VAR */ - struct fstHierVar - { - unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */ - unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */ - unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */ - unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */ - unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */ - const char *name; - uint32_t length; - fstHandle handle; - uint32_t name_length; /* strlen(u.var.name) */ - unsigned is_alias : 1; - } var; - - /* if htyp == FST_HT_ATTRBEGIN */ - struct fstHierAttr - { - unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */ - unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */ - const char *name; - uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */ - uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + - FST_MT_SOURCESTEM) */ - uint32_t name_length; /* strlen(u.attr.name) */ - } attr; - } u; -}; - -struct fstETab -{ - char *name; - uint32_t elem_count; - char **literal_arr; - char **val_arr; -}; - -/* - * writer functions - */ -void fstWriterClose(void *ctx); -void *fstWriterCreate(const char *nam, int use_compressed_hier); -fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, - const char **literal_arr, const char **val_arr); -/* used for Verilog/SV */ -fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam, - fstHandle aliasHandle); -/* future expansion for VHDL and other languages. The variable type, data type, etc map onto - the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */ -fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam, - fstHandle aliasHandle, const char *type, enum fstSupplementalVarType svt, - enum fstSupplementalDataType sdt); -void fstWriterEmitDumpActive(void *ctx, int enable); -void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle); -void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val); -void fstWriterEmitValueChange32(void *ctx, fstHandle handle, uint32_t bits, uint32_t val); -void fstWriterEmitValueChange64(void *ctx, fstHandle handle, uint32_t bits, uint64_t val); -void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle, uint32_t bits, const uint32_t *val); -void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle, uint32_t bits, const uint64_t *val); -void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len); -void fstWriterEmitTimeChange(void *ctx, uint64_t tim); -void fstWriterFlushContext(void *ctx); -int fstWriterGetDumpSizeLimitReached(void *ctx); -int fstWriterGetFseekFailed(void *ctx); -void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, const char *attrname, uint64_t arg); -void fstWriterSetAttrEnd(void *ctx); -void fstWriterSetComment(void *ctx, const char *comm); -void fstWriterSetDate(void *ctx, const char *dat); -void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes); -void fstWriterSetEnvVar(void *ctx, const char *envvar); -void fstWriterSetFileType(void *ctx, enum fstFileType filetype); -void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ); -void fstWriterSetParallelMode(void *ctx, int enable); -void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */ -void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, const char *scopename, const char *scopecomp); -void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); -void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); -void fstWriterSetTimescale(void *ctx, int ts); -void fstWriterSetTimescaleFromString(void *ctx, const char *s); -void fstWriterSetTimezero(void *ctx, int64_t tim); -void fstWriterSetUpscope(void *ctx); -void fstWriterSetValueList(void *ctx, const char *vl); -void fstWriterSetVersion(void *ctx, const char *vers); - -/* - * reader functions - */ -void fstReaderClose(void *ctx); -void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx); -void fstReaderClrFacProcessMaskAll(void *ctx); -uint64_t fstReaderGetAliasCount(void *ctx); -const char *fstReaderGetCurrentFlatScope(void *ctx); -void *fstReaderGetCurrentScopeUserInfo(void *ctx); -int fstReaderGetCurrentScopeLen(void *ctx); -const char *fstReaderGetDateString(void *ctx); -int fstReaderGetDoubleEndianMatchState(void *ctx); -uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx); -unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx); -uint64_t fstReaderGetEndTime(void *ctx); -int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx); -int fstReaderGetFileType(void *ctx); -int fstReaderGetFseekFailed(void *ctx); -fstHandle fstReaderGetMaxHandle(void *ctx); -uint64_t fstReaderGetMemoryUsedByWriter(void *ctx); -uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx); -uint64_t fstReaderGetScopeCount(void *ctx); -uint64_t fstReaderGetStartTime(void *ctx); -signed char fstReaderGetTimescale(void *ctx); -int64_t fstReaderGetTimezero(void *ctx); -uint64_t fstReaderGetValueChangeSectionCount(void *ctx); -char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf); -uint64_t fstReaderGetVarCount(void *ctx); -const char *fstReaderGetVersionString(void *ctx); -struct fstHier *fstReaderIterateHier(void *ctx); -int fstReaderIterateHierRewind(void *ctx); -int fstReaderIterBlocks(void *ctx, - void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, - const unsigned char *value), - void *user_callback_data_pointer, FILE *vcdhandle); -int fstReaderIterBlocks2(void *ctx, - void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, - fstHandle facidx, const unsigned char *value), - void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, - fstHandle facidx, const unsigned char *value, - uint32_t len), - void *user_callback_data_pointer, FILE *vcdhandle); -void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable); -void *fstReaderOpen(const char *nam); -void *fstReaderOpenForUtilitiesOnly(void); -const char *fstReaderPopScope(void *ctx); -int fstReaderProcessHier(void *ctx, FILE *vcdhandle); -const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info); -void fstReaderResetScope(void *ctx); -void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx); -void fstReaderSetFacProcessMaskAll(void *ctx); -void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time); -void fstReaderSetUnlimitedTimeRange(void *ctx); -void fstReaderSetVcdExtensions(void *ctx, int enable); - -/* - * utility functions - */ -int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */ -int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len); -int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len); -struct fstETab *fstUtilityExtractEnumTableFromString(const char *s); -void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/yosys/libs/fst/lz4.cc b/yosys/libs/fst/lz4.cc deleted file mode 100644 index 7e94f2492f4..00000000000 --- a/yosys/libs/fst/lz4.cc +++ /dev/null @@ -1,1615 +0,0 @@ -/* - LZ4 - Fast LZ compression algorithm - Copyright (C) 2011-2015, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - SPDX-License-Identifier: BSD-2-Clause - - You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 - - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c -*/ - -/************************************** - * Tuning parameters - **************************************/ -/* - * HEAPMODE : - * Select how default compression functions will allocate memory for their hash table, - * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()). - */ -#define HEAPMODE 0 - -/* - * ACCELERATION_DEFAULT : - * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 - */ -#define ACCELERATION_DEFAULT 1 - -/************************************** - * CPU Feature Detection - **************************************/ -/* - * LZ4_FORCE_SW_BITCOUNT - * Define this parameter if your target system or compiler does not support hardware bit count - */ -#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ -#define LZ4_FORCE_SW_BITCOUNT -#endif - -/************************************** - * Includes - **************************************/ -#include "lz4.h" - -/************************************** - * Compiler Options - **************************************/ -#ifdef _MSC_VER /* Visual Studio */ -#define FORCE_INLINE static __forceinline -#include -#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ -#else -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ -#if defined(__GNUC__) || defined(__clang__) -#define FORCE_INLINE static inline __attribute__((always_inline)) -#else -#define FORCE_INLINE static inline -#endif -#else -#define FORCE_INLINE static -#endif /* __STDC_VERSION__ */ -#endif /* _MSC_VER */ - -/* LZ4_GCC_VERSION is defined into lz4.h */ -#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) -#define expect(expr, value) (__builtin_expect((expr), (value))) -#else -#define expect(expr, value) (expr) -#endif - -#define likely(expr) expect((expr) != 0, 1) -#define unlikely(expr) expect((expr) != 0, 0) - -/************************************** - * Memory routines - **************************************/ -#include /* malloc, calloc, free */ -#define ALLOCATOR(n, s) calloc(n, s) -#define FREEMEM free -#include /* memset, memcpy */ -#define MEM_INIT memset - -/************************************** - * Basic Types - **************************************/ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ -#include -typedef uint8_t BYTE; -typedef uint16_t U16; -typedef uint32_t U32; -typedef int32_t S32; -typedef uint64_t U64; -#else -typedef unsigned char BYTE; -typedef unsigned short U16; -typedef unsigned int U32; -typedef signed int S32; -typedef unsigned long long U64; -#endif - -/************************************** - * Reading and writing into memory - **************************************/ -#define STEPSIZE sizeof(size_t) - -static unsigned LZ4_64bits(void) { return sizeof(void *) == 8; } - -static unsigned LZ4_isLittleEndian(void) -{ - const union - { - U32 i; - BYTE c[4]; - } one = {1}; /* don't use static : performance detrimental */ - return one.c[0]; -} - -static U16 LZ4_read16(const void *memPtr) -{ - U16 val16; - memcpy(&val16, memPtr, 2); - return val16; -} - -static U16 LZ4_readLE16(const void *memPtr) -{ - if (LZ4_isLittleEndian()) { - return LZ4_read16(memPtr); - } else { - const BYTE *p = (const BYTE *)memPtr; - return (U16)((U16)p[0] + (p[1] << 8)); - } -} - -static void LZ4_writeLE16(void *memPtr, U16 value) -{ - if (LZ4_isLittleEndian()) { - memcpy(memPtr, &value, 2); - } else { - BYTE *p = (BYTE *)memPtr; - p[0] = (BYTE)value; - p[1] = (BYTE)(value >> 8); - } -} - -static U32 LZ4_read32(const void *memPtr) -{ - U32 val32; - memcpy(&val32, memPtr, 4); - return val32; -} - -static U64 LZ4_read64(const void *memPtr) -{ - U64 val64; - memcpy(&val64, memPtr, 8); - return val64; -} - -static size_t LZ4_read_ARCH(const void *p) -{ - if (LZ4_64bits()) - return (size_t)LZ4_read64(p); - else - return (size_t)LZ4_read32(p); -} - -static void LZ4_copy4(void *dstPtr, const void *srcPtr) { memcpy(dstPtr, srcPtr, 4); } - -static void LZ4_copy8(void *dstPtr, const void *srcPtr) { memcpy(dstPtr, srcPtr, 8); } - -/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */ -static void LZ4_wildCopy(void *dstPtr, const void *srcPtr, void *dstEnd) -{ - BYTE *d = (BYTE *)dstPtr; - const BYTE *s = (const BYTE *)srcPtr; - BYTE *e = (BYTE *)dstEnd; - do { - LZ4_copy8(d, s); - d += 8; - s += 8; - } while (d < e); -} - -/************************************** - * Common Constants - **************************************/ -#define MINMATCH 4 - -#define COPYLENGTH 8 -#define LASTLITERALS 5 -#define MFLIMIT (COPYLENGTH + MINMATCH) -static const int LZ4_minLength = (MFLIMIT + 1); - -#define KB *(1 << 10) -#define MB *(1 << 20) -#define GB *(1U << 30) - -#define MAXD_LOG 16 -#ifdef MAX_DISTANCE -#undef MAX_DISTANCE -#endif -#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) - -#define ML_BITS 4 -#define ML_MASK ((1U << ML_BITS) - 1) -#define RUN_BITS (8 - ML_BITS) -#define RUN_MASK ((1U << RUN_BITS) - 1) - -/************************************** - * Common Utils - **************************************/ -#define LZ4_STATIC_ASSERT(c) \ - { \ - enum \ - { \ - LZ4_static_assert = 1 / (int)(!!(c)) \ - }; \ - } /* use only *after* variable declarations */ - -/************************************** - * Common functions - **************************************/ -static unsigned LZ4_NbCommonBytes(size_t val) -{ - if (LZ4_isLittleEndian()) { - if (LZ4_64bits()) { -#if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanForward64(&r, (U64)val); - return (int)(r >> 3); -#elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); -#else - static const int DeBruijnBytePos[64] = {0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, - 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, - 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7}; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -#endif - } else /* 32 bits */ - { -#if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward(&r, (U32)val); - return (int)(r >> 3); -#elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); -#else - static const int DeBruijnBytePos[32] = {0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, - 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1}; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -#endif - } - } else /* Big Endian CPU */ - { - if (LZ4_64bits()) { -#if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64(&r, val); - return (unsigned)(r >> 3); -#elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); -#else - unsigned r; - if (!(val >> 32)) { - r = 4; - } else { - r = 0; - val >>= 32; - } - if (!(val >> 16)) { - r += 2; - val >>= 8; - } else { - val >>= 24; - } - r += (!val); - return r; -#endif - } else /* 32 bits */ - { -#if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse(&r, (unsigned long)val); - return (unsigned)(r >> 3); -#elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); -#else - unsigned r; - if (!(val >> 16)) { - r = 2; - val >>= 8; - } else { - r = 0; - val >>= 24; - } - r += (!val); - return r; -#endif - } - } -} - -static unsigned LZ4_count(const BYTE *pIn, const BYTE *pMatch, const BYTE *pInLimit) -{ - const BYTE *const pStart = pIn; - - while (likely(pIn < pInLimit - (STEPSIZE - 1))) { - size_t diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); - if (!diff) { - pIn += STEPSIZE; - pMatch += STEPSIZE; - continue; - } - pIn += LZ4_NbCommonBytes(diff); - return (unsigned)(pIn - pStart); - } - - if (LZ4_64bits()) - if ((pIn < (pInLimit - 3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { - pIn += 4; - pMatch += 4; - } - if ((pIn < (pInLimit - 1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { - pIn += 2; - pMatch += 2; - } - if ((pIn < pInLimit) && (*pMatch == *pIn)) - pIn++; - return (unsigned)(pIn - pStart); -} - -#ifndef LZ4_COMMONDEFS_ONLY -/************************************** - * Local Constants - **************************************/ -#define LZ4_HASHLOG (LZ4_MEMORY_USAGE - 2) -#define HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) -#define HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ - -static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT - 1)); -static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run slower on incompressible data */ - -/************************************** - * Local Structures and types - **************************************/ -typedef struct -{ - U32 hashTable[HASH_SIZE_U32]; - U32 currentOffset; - U32 initCheck; - const BYTE *dictionary; - BYTE *bufferStart; /* obsolete, used for slideInputBuffer */ - U32 dictSize; -} LZ4_stream_t_internal; - -typedef enum -{ - notLimited = 0, - limitedOutput = 1 -} limitedOutput_directive; -typedef enum -{ - byPtr, - byU32, - byU16 -} tableType_t; - -typedef enum -{ - noDict = 0, - withPrefix64k, - usingExtDict -} dict_directive; -typedef enum -{ - noDictIssue = 0, - dictSmall -} dictIssue_directive; - -typedef enum -{ - endOnOutputSize = 0, - endOnInputSize = 1 -} endCondition_directive; -typedef enum -{ - full = 0, - partial = 1 -} earlyEnd_directive; - -/************************************** - * Local Utils - **************************************/ -int LZ4_versionNumber(void) { return LZ4_VERSION_NUMBER; } -int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } -int LZ4_sizeofState() { return LZ4_STREAMSIZE; } - -/******************************** - * Compression functions - ********************************/ - -static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType) -{ - if (tableType == byU16) - return (((sequence)*2654435761U) >> ((MINMATCH * 8) - (LZ4_HASHLOG + 1))); - else - return (((sequence)*2654435761U) >> ((MINMATCH * 8) - LZ4_HASHLOG)); -} - -static const U64 prime5bytes = 889523592379ULL; -static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType) -{ - const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG + 1 : LZ4_HASHLOG; - const U32 hashMask = (1 << hashLog) - 1; - return ((sequence * prime5bytes) >> (40 - hashLog)) & hashMask; -} - -static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType) -{ - if (LZ4_64bits()) - return LZ4_hashSequence64(sequence, tableType); - return LZ4_hashSequence((U32)sequence, tableType); -} - -static U32 LZ4_hashPosition(const void *p, tableType_t tableType) -{ - return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); -} - -static void LZ4_putPositionOnHash(const BYTE *p, U32 h, void *tableBase, tableType_t const tableType, - const BYTE *srcBase) -{ - switch (tableType) { - case byPtr: { - const BYTE **hashTable = (const BYTE **)tableBase; - hashTable[h] = p; - return; - } - case byU32: { - U32 *hashTable = (U32 *)tableBase; - hashTable[h] = (U32)(p - srcBase); - return; - } - case byU16: { - U16 *hashTable = (U16 *)tableBase; - hashTable[h] = (U16)(p - srcBase); - return; - } - } -} - -static void LZ4_putPosition(const BYTE *p, void *tableBase, tableType_t tableType, const BYTE *srcBase) -{ - U32 h = LZ4_hashPosition(p, tableType); - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); -} - -static const BYTE *LZ4_getPositionOnHash(U32 h, void *tableBase, tableType_t tableType, const BYTE *srcBase) -{ - if (tableType == byPtr) { - const BYTE **hashTable = (const BYTE **)tableBase; - return hashTable[h]; - } - if (tableType == byU32) { - U32 *hashTable = (U32 *)tableBase; - return hashTable[h] + srcBase; - } - { - U16 *hashTable = (U16 *)tableBase; - return hashTable[h] + srcBase; - } /* default, to ensure a return */ -} - -static const BYTE *LZ4_getPosition(const BYTE *p, void *tableBase, tableType_t tableType, const BYTE *srcBase) -{ - U32 h = LZ4_hashPosition(p, tableType); - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); -} - -FORCE_INLINE int LZ4_compress_generic(void *const ctx, const char *const source, char *const dest, const int inputSize, - const int maxOutputSize, const limitedOutput_directive outputLimited, - const tableType_t tableType, const dict_directive dict, - const dictIssue_directive dictIssue, const U32 acceleration) -{ - LZ4_stream_t_internal *const dictPtr = (LZ4_stream_t_internal *)ctx; - - const BYTE *ip = (const BYTE *)source; - const BYTE *base; - const BYTE *lowLimit; - const BYTE *const lowRefLimit = ip - dictPtr->dictSize; - const BYTE *const dictionary = dictPtr->dictionary; - const BYTE *const dictEnd = dictionary + dictPtr->dictSize; - const size_t dictDelta = dictEnd - (const BYTE *)source; - const BYTE *anchor = (const BYTE *)source; - const BYTE *const iend = ip + inputSize; - const BYTE *const mflimit = iend - MFLIMIT; - const BYTE *const matchlimit = iend - LASTLITERALS; - - BYTE *op = (BYTE *)dest; - BYTE *const olimit = op + maxOutputSize; - - U32 forwardH; - size_t refDelta = 0; - - /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) - return 0; /* Unsupported input size, too large (or negative) */ - switch (dict) { - case noDict: - default: - base = (const BYTE *)source; - lowLimit = (const BYTE *)source; - break; - case withPrefix64k: - base = (const BYTE *)source - dictPtr->currentOffset; - lowLimit = (const BYTE *)source - dictPtr->dictSize; - break; - case usingExtDict: - base = (const BYTE *)source - dictPtr->currentOffset; - lowLimit = (const BYTE *)source; - break; - } - if ((tableType == byU16) && (inputSize >= LZ4_64Klimit)) - return 0; /* Size too large (not within 64K limit) */ - if (inputSize < LZ4_minLength) - goto _last_literals; /* Input too small, no compression (all literals) */ - - /* First Byte */ - LZ4_putPosition(ip, ctx, tableType, base); - ip++; - forwardH = LZ4_hashPosition(ip, tableType); - - /* Main Loop */ - for (;;) { - const BYTE *match; - BYTE *token; - { - const BYTE *forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - - /* Find a match */ - do { - U32 h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); - - if (unlikely(forwardIp > mflimit)) - goto _last_literals; - - match = LZ4_getPositionOnHash(h, ctx, tableType, base); - if (dict == usingExtDict) { - if (match < (const BYTE *)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE *)source; - } - } - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, ctx, tableType, base); - - } while (((dictIssue == dictSmall) ? (match < lowRefLimit) : 0) || - ((tableType == byU16) ? 0 : (match + MAX_DISTANCE < ip)) || - (LZ4_read32(match + refDelta) != LZ4_read32(ip))); - } - - /* Catch up */ - while ((ip > anchor) && (match + refDelta > lowLimit) && (unlikely(ip[-1] == match[refDelta - 1]))) { - ip--; - match--; - } - - { - /* Encode Literal length */ - unsigned litLength = (unsigned)(ip - anchor); - token = op++; - if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength / 255) > olimit))) - return 0; /* Check output limit */ - if (litLength >= RUN_MASK) { - int len = (int)litLength - RUN_MASK; - *token = (RUN_MASK << ML_BITS); - for (; len >= 255; len -= 255) - *op++ = 255; - *op++ = (BYTE)len; - } else - *token = (BYTE)(litLength << ML_BITS); - - /* Copy Literals */ - LZ4_wildCopy(op, anchor, op + litLength); - op += litLength; - } - - _next_match: - /* Encode Offset */ - LZ4_writeLE16(op, (U16)(ip - match)); - op += 2; - - /* Encode MatchLength */ - { - unsigned matchLength; - - if ((dict == usingExtDict) && (lowLimit == dictionary)) { - const BYTE *limit; - match += refDelta; - limit = ip + (dictEnd - match); - if (limit > matchlimit) - limit = matchlimit; - matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, limit); - ip += MINMATCH + matchLength; - if (ip == limit) { - unsigned more = LZ4_count(ip, (const BYTE *)source, matchlimit); - matchLength += more; - ip += more; - } - } else { - matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); - ip += MINMATCH + matchLength; - } - - if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength >> 8) > olimit))) - return 0; /* Check output limit */ - if (matchLength >= ML_MASK) { - *token += ML_MASK; - matchLength -= ML_MASK; - for (; matchLength >= 510; matchLength -= 510) { - *op++ = 255; - *op++ = 255; - } - if (matchLength >= 255) { - matchLength -= 255; - *op++ = 255; - } - *op++ = (BYTE)matchLength; - } else - *token += (BYTE)(matchLength); - } - - anchor = ip; - - /* Test end of chunk */ - if (ip > mflimit) - break; - - /* Fill table */ - LZ4_putPosition(ip - 2, ctx, tableType, base); - - /* Test next position */ - match = LZ4_getPosition(ip, ctx, tableType, base); - if (dict == usingExtDict) { - if (match < (const BYTE *)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE *)source; - } - } - LZ4_putPosition(ip, ctx, tableType, base); - if (((dictIssue == dictSmall) ? (match >= lowRefLimit) : 1) && (match + MAX_DISTANCE >= ip) && - (LZ4_read32(match + refDelta) == LZ4_read32(ip))) { - token = op++; - *token = 0; - goto _next_match; - } - - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } - -_last_literals: - /* Encode Last Literals */ - { - const size_t lastRun = (size_t)(iend - anchor); - if ((outputLimited) && - ((op - (BYTE *)dest) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > (U32)maxOutputSize)) - return 0; /* Check output limit */ - if (lastRun >= RUN_MASK) { - size_t accumulator = lastRun - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for (; accumulator >= 255; accumulator -= 255) - *op++ = 255; - *op++ = (BYTE)accumulator; - } else { - *op++ = (BYTE)(lastRun << ML_BITS); - } - memcpy(op, anchor, lastRun); - op += lastRun; - } - - /* End */ - return (int)(((char *)op) - dest); -} - -int LZ4_compress_fast_extState(void *state, const char *source, char *dest, int inputSize, int maxOutputSize, - int acceleration) -{ - LZ4_resetStream((LZ4_stream_t *)state); - if (acceleration < 1) - acceleration = ACCELERATION_DEFAULT; - - if (maxOutputSize >= LZ4_compressBound(inputSize)) { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, - acceleration); - else - return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, - noDict, noDictIssue, acceleration); - } else { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, - noDictIssue, acceleration); - else - return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, - LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } -} - -int LZ4_compress_fast(const char *source, char *dest, int inputSize, int maxOutputSize, int acceleration) -{ -#if (HEAPMODE) - void *ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ -#else - LZ4_stream_t ctx; - void *ctxPtr = &ctx; -#endif - - int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); - -#if (HEAPMODE) - FREEMEM(ctxPtr); -#endif - return result; -} - -int LZ4_compress_default(const char *source, char *dest, int inputSize, int maxOutputSize) -{ - return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); -} - -/* hidden debug function */ -/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ -int LZ4_compress_fast_force(const char *source, char *dest, int inputSize, int maxOutputSize, int acceleration) -{ - LZ4_stream_t ctx; - - LZ4_resetStream(&ctx); - - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, - noDictIssue, acceleration); - else - return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, - LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); -} - -/******************************** - * destSize variant - ********************************/ - -static int LZ4_compress_destSize_generic(void *const ctx, const char *const src, char *const dst, int *const srcSizePtr, - const int targetDstSize, const tableType_t tableType) -{ - const BYTE *ip = (const BYTE *)src; - const BYTE *base = (const BYTE *)src; - const BYTE *lowLimit = (const BYTE *)src; - const BYTE *anchor = ip; - const BYTE *const iend = ip + *srcSizePtr; - const BYTE *const mflimit = iend - MFLIMIT; - const BYTE *const matchlimit = iend - LASTLITERALS; - - BYTE *op = (BYTE *)dst; - BYTE *const oend = op + targetDstSize; - BYTE *const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; - BYTE *const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); - BYTE *const oMaxSeq = oMaxLit - 1 /* token */; - - U32 forwardH; - - /* Init conditions */ - if (targetDstSize < 1) - return 0; /* Impossible to store anything */ - if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) - return 0; /* Unsupported input size, too large (or negative) */ - if ((tableType == byU16) && (*srcSizePtr >= LZ4_64Klimit)) - return 0; /* Size too large (not within 64K limit) */ - if (*srcSizePtr < LZ4_minLength) - goto _last_literals; /* Input too small, no compression (all literals) */ - - /* First Byte */ - *srcSizePtr = 0; - LZ4_putPosition(ip, ctx, tableType, base); - ip++; - forwardH = LZ4_hashPosition(ip, tableType); - - /* Main Loop */ - for (;;) { - const BYTE *match; - BYTE *token; - { - const BYTE *forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = 1 << LZ4_skipTrigger; - - /* Find a match */ - do { - U32 h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); - - if (unlikely(forwardIp > mflimit)) - goto _last_literals; - - match = LZ4_getPositionOnHash(h, ctx, tableType, base); - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, ctx, tableType, base); - - } while (((tableType == byU16) ? 0 : (match + MAX_DISTANCE < ip)) || (LZ4_read32(match) != LZ4_read32(ip))); - } - - /* Catch up */ - while ((ip > anchor) && (match > lowLimit) && (unlikely(ip[-1] == match[-1]))) { - ip--; - match--; - } - - { - /* Encode Literal length */ - unsigned litLength = (unsigned)(ip - anchor); - token = op++; - if (op + ((litLength + 240) / 255) + litLength > oMaxLit) { - /* Not enough space for a last match */ - op--; - goto _last_literals; - } - if (litLength >= RUN_MASK) { - unsigned len = litLength - RUN_MASK; - *token = (RUN_MASK << ML_BITS); - for (; len >= 255; len -= 255) - *op++ = 255; - *op++ = (BYTE)len; - } else - *token = (BYTE)(litLength << ML_BITS); - - /* Copy Literals */ - LZ4_wildCopy(op, anchor, op + litLength); - op += litLength; - } - - _next_match: - /* Encode Offset */ - LZ4_writeLE16(op, (U16)(ip - match)); - op += 2; - - /* Encode MatchLength */ - { - size_t matchLength; - - matchLength = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); - - if (op + ((matchLength + 240) / 255) > oMaxMatch) { - /* Match description too long : reduce it */ - matchLength = (15 - 1) + (oMaxMatch - op) * 255; - } - /*printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH);*/ - ip += MINMATCH + matchLength; - - if (matchLength >= ML_MASK) { - *token += ML_MASK; - matchLength -= ML_MASK; - while (matchLength >= 255) { - matchLength -= 255; - *op++ = 255; - } - *op++ = (BYTE)matchLength; - } else - *token += (BYTE)(matchLength); - } - - anchor = ip; - - /* Test end of block */ - if (ip > mflimit) - break; - if (op > oMaxSeq) - break; - - /* Fill table */ - LZ4_putPosition(ip - 2, ctx, tableType, base); - - /* Test next position */ - match = LZ4_getPosition(ip, ctx, tableType, base); - LZ4_putPosition(ip, ctx, tableType, base); - if ((match + MAX_DISTANCE >= ip) && (LZ4_read32(match) == LZ4_read32(ip))) { - token = op++; - *token = 0; - goto _next_match; - } - - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } - -_last_literals: - /* Encode Last Literals */ - { - size_t lastRunSize = (size_t)(iend - anchor); - if (op + 1 /* token */ + ((lastRunSize + 240) / 255) /* litLength */ + lastRunSize /* literals */ > oend) { - /* adapt lastRunSize to fill 'dst' */ - lastRunSize = (oend - op) - 1; - lastRunSize -= (lastRunSize + 240) / 255; - } - ip = anchor + lastRunSize; - - if (lastRunSize >= RUN_MASK) { - size_t accumulator = lastRunSize - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for (; accumulator >= 255; accumulator -= 255) - *op++ = 255; - *op++ = (BYTE)accumulator; - } else { - *op++ = (BYTE)(lastRunSize << ML_BITS); - } - memcpy(op, anchor, lastRunSize); - op += lastRunSize; - } - - /* End */ - *srcSizePtr = (int)(((const char *)ip) - src); - return (int)(((char *)op) - dst); -} - -static int LZ4_compress_destSize_extState(void *state, const char *src, char *dst, int *srcSizePtr, int targetDstSize) -{ - LZ4_resetStream((LZ4_stream_t *)state); - - if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */ - { - return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); - } else { - if (*srcSizePtr < LZ4_64Klimit) - return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16); - else - return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, - LZ4_64bits() ? byU32 : byPtr); - } -} - -int LZ4_compress_destSize(const char *src, char *dst, int *srcSizePtr, int targetDstSize) -{ -#if (HEAPMODE) - void *ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ -#else - LZ4_stream_t ctxBody; - void *ctx = &ctxBody; -#endif - - int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); - -#if (HEAPMODE) - FREEMEM(ctx); -#endif - return result; -} - -/******************************** - * Streaming functions - ********************************/ - -LZ4_stream_t *LZ4_createStream(void) -{ - LZ4_stream_t *lz4s = (LZ4_stream_t *)ALLOCATOR(8, LZ4_STREAMSIZE_U64); - LZ4_STATIC_ASSERT( - LZ4_STREAMSIZE >= - sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ - LZ4_resetStream(lz4s); - return lz4s; -} - -void LZ4_resetStream(LZ4_stream_t *LZ4_stream) { MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); } - -int LZ4_freeStream(LZ4_stream_t *LZ4_stream) -{ - FREEMEM(LZ4_stream); - return (0); -} - -#define HASH_UNIT sizeof(size_t) -int LZ4_loadDict(LZ4_stream_t *LZ4_dict, const char *dictionary, int dictSize) -{ - LZ4_stream_t_internal *dict = (LZ4_stream_t_internal *)LZ4_dict; - const BYTE *p = (const BYTE *)dictionary; - const BYTE *const dictEnd = p + dictSize; - const BYTE *base; - - if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ - LZ4_resetStream(LZ4_dict); - - if (dictSize < (int)HASH_UNIT) { - dict->dictionary = NULL; - dict->dictSize = 0; - return 0; - } - - if ((dictEnd - p) > 64 KB) - p = dictEnd - 64 KB; - dict->currentOffset += 64 KB; - base = p - dict->currentOffset; - dict->dictionary = p; - dict->dictSize = (U32)(dictEnd - p); - dict->currentOffset += dict->dictSize; - - while (p <= dictEnd - HASH_UNIT) { - LZ4_putPosition(p, dict->hashTable, byU32, base); - p += 3; - } - - return dict->dictSize; -} - -static void LZ4_renormDictT(LZ4_stream_t_internal *LZ4_dict, const BYTE *src) -{ - if ((LZ4_dict->currentOffset > 0x80000000) || - ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */ - { - /* rescale hash table */ - U32 delta = LZ4_dict->currentOffset - 64 KB; - const BYTE *dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; - int i; - for (i = 0; i < HASH_SIZE_U32; i++) { - if (LZ4_dict->hashTable[i] < delta) - LZ4_dict->hashTable[i] = 0; - else - LZ4_dict->hashTable[i] -= delta; - } - LZ4_dict->currentOffset = 64 KB; - if (LZ4_dict->dictSize > 64 KB) - LZ4_dict->dictSize = 64 KB; - LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; - } -} - -int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream, const char *source, char *dest, int inputSize, - int maxOutputSize, int acceleration) -{ - LZ4_stream_t_internal *streamPtr = (LZ4_stream_t_internal *)LZ4_stream; - const BYTE *const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - - const BYTE *smallest = (const BYTE *)source; - if (streamPtr->initCheck) - return 0; /* Uninitialized structure detected */ - if ((streamPtr->dictSize > 0) && (smallest > dictEnd)) - smallest = dictEnd; - LZ4_renormDictT(streamPtr, smallest); - if (acceleration < 1) - acceleration = ACCELERATION_DEFAULT; - - /* Check overlapping input/dictionary space */ - { - const BYTE *sourceEnd = (const BYTE *)source + inputSize; - if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { - streamPtr->dictSize = (U32)(dictEnd - sourceEnd); - if (streamPtr->dictSize > 64 KB) - streamPtr->dictSize = 64 KB; - if (streamPtr->dictSize < 4) - streamPtr->dictSize = 0; - streamPtr->dictionary = dictEnd - streamPtr->dictSize; - } - } - - /* prefix mode : source data follows dictionary */ - if (dictEnd == (const BYTE *)source) { - int result; - if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, - withPrefix64k, dictSmall, acceleration); - else - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, - withPrefix64k, noDictIssue, acceleration); - streamPtr->dictSize += (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; - return result; - } - - /* external dictionary mode */ - { - int result; - if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, - usingExtDict, dictSmall, acceleration); - else - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, - usingExtDict, noDictIssue, acceleration); - streamPtr->dictionary = (const BYTE *)source; - streamPtr->dictSize = (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; - return result; - } -} - -/* Hidden debug function, to force external dictionary mode */ -int LZ4_compress_forceExtDict(LZ4_stream_t *LZ4_dict, const char *source, char *dest, int inputSize) -{ - LZ4_stream_t_internal *streamPtr = (LZ4_stream_t_internal *)LZ4_dict; - int result; - const BYTE *const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - - const BYTE *smallest = dictEnd; - if (smallest > (const BYTE *)source) - smallest = (const BYTE *)source; - LZ4_renormDictT((LZ4_stream_t_internal *)LZ4_dict, smallest); - - result = - LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); - - streamPtr->dictionary = (const BYTE *)source; - streamPtr->dictSize = (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; - - return result; -} - -int LZ4_saveDict(LZ4_stream_t *LZ4_dict, char *safeBuffer, int dictSize) -{ - LZ4_stream_t_internal *dict = (LZ4_stream_t_internal *)LZ4_dict; - const BYTE *previousDictEnd = dict->dictionary + dict->dictSize; - - if ((U32)dictSize > 64 KB) - dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ - if ((U32)dictSize > dict->dictSize) - dictSize = dict->dictSize; - - memmove(safeBuffer, previousDictEnd - dictSize, dictSize); - - dict->dictionary = (const BYTE *)safeBuffer; - dict->dictSize = (U32)dictSize; - - return dictSize; -} - -/******************************* - * Decompression functions - *******************************/ -/* - * This generic decompression function cover all use cases. - * It shall be instantiated several times, using different sets of directives - * Note that it is essential this generic function is really inlined, - * in order to remove useless branches during compilation optimization. - */ -FORCE_INLINE int -LZ4_decompress_generic(const char *const source, char *const dest, int inputSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ - - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE *const lowPrefix, /* == dest if dict == noDict */ - const BYTE *const dictStart, /* only if dict==usingExtDict */ - const size_t dictSize /* note : = 0 if noDict */ -) -{ - /* Local Variables */ - const BYTE *ip = (const BYTE *)source; - const BYTE *const iend = ip + inputSize; - - BYTE *op = (BYTE *)dest; - BYTE *const oend = op + outputSize; - BYTE *cpy; - BYTE *oexit = op + targetOutputSize; - const BYTE *const lowLimit = lowPrefix - dictSize; - - const BYTE *const dictEnd = (const BYTE *)dictStart + dictSize; - const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; - const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; - - const int safeDecode = (endOnInput == endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); - - /* Special cases */ - if ((partialDecoding) && (oexit > oend - MFLIMIT)) - oexit = oend - MFLIMIT; /* targetOutputSize too high => decode everything */ - if ((endOnInput) && (unlikely(outputSize == 0))) - return ((inputSize == 1) && (*ip == 0)) ? 0 : -1; /* Empty output buffer */ - if ((!endOnInput) && (unlikely(outputSize == 0))) - return (*ip == 0 ? 1 : -1); - - /* Main Loop */ - while (1) { - unsigned token; - size_t length; - const BYTE *match; - - /* get literal length */ - token = *ip++; - if ((length = (token >> ML_BITS)) == RUN_MASK) { - unsigned s; - do { - s = *ip++; - length += s; - } while (likely((endOnInput) ? ip < iend - RUN_MASK : 1) && (s == 255)); - if ((safeDecode) && unlikely((size_t)(op + length) < (size_t)(op))) - goto _output_error; /* overflow detection */ - if ((safeDecode) && unlikely((size_t)(ip + length) < (size_t)(ip))) - goto _output_error; /* overflow detection */ - } - - /* copy literals */ - cpy = op + length; - if (((endOnInput) && - ((cpy > (partialDecoding ? oexit : oend - MFLIMIT)) || (ip + length > iend - (2 + 1 + LASTLITERALS)))) || - ((!endOnInput) && (cpy > oend - COPYLENGTH))) { - if (partialDecoding) { - if (cpy > oend) - goto _output_error; /* Error : write attempt beyond end of output buffer */ - if ((endOnInput) && (ip + length > iend)) - goto _output_error; /* Error : read attempt beyond end of input buffer */ - } else { - if ((!endOnInput) && (cpy != oend)) - goto _output_error; /* Error : block decoding must stop exactly there */ - if ((endOnInput) && ((ip + length != iend) || (cpy > oend))) - goto _output_error; /* Error : input must be consumed */ - } - memcpy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; - op = cpy; - - /* get offset */ - match = cpy - LZ4_readLE16(ip); - ip += 2; - if ((checkOffset) && (unlikely(match < lowLimit))) - goto _output_error; /* Error : offset outside destination buffer */ - - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) { - unsigned s; - do { - if ((endOnInput) && (ip > iend - LASTLITERALS)) - goto _output_error; - s = *ip++; - length += s; - } while (s == 255); - if ((safeDecode) && unlikely((size_t)(op + length) < (size_t)op)) - goto _output_error; /* overflow detection */ - } - length += MINMATCH; - - /* check external dictionary */ - if ((dict == usingExtDict) && (match < lowPrefix)) { - if (unlikely(op + length > oend - LASTLITERALS)) - goto _output_error; /* doesn't respect parsing restriction */ - - if (length <= (size_t)(lowPrefix - match)) { - /* match can be copied as a single segment from external dictionary */ - match = dictEnd - (lowPrefix - match); - memmove(op, match, length); - op += length; - } else { - /* match encompass external dictionary and current segment */ - size_t copySize = (size_t)(lowPrefix - match); - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - copySize = length - copySize; - if (copySize > (size_t)(op - lowPrefix)) /* overlap within current segment */ - { - BYTE *const endOfMatch = op + copySize; - const BYTE *copyFrom = lowPrefix; - while (op < endOfMatch) - *op++ = *copyFrom++; - } else { - memcpy(op, lowPrefix, copySize); - op += copySize; - } - } - continue; - } - - /* copy repeated sequence */ - cpy = op + length; - if (unlikely((op - match) < 8)) { - const size_t dec64 = dec64table[op - match]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[op - match]; - LZ4_copy4(op + 4, match); - op += 8; - match -= dec64; - } else { - LZ4_copy8(op, match); - op += 8; - match += 8; - } - - if (unlikely(cpy > oend - 12)) { - if (cpy > oend - LASTLITERALS) - goto _output_error; /* Error : last LASTLITERALS bytes must be literals */ - if (op < oend - 8) { - LZ4_wildCopy(op, match, oend - 8); - match += (oend - 8) - op; - op = oend - 8; - } - while (op < cpy) - *op++ = *match++; - } else - LZ4_wildCopy(op, match, cpy); - op = cpy; /* correction */ - } - - /* end of decoding */ - if (endOnInput) - return (int)(((char *)op) - dest); /* Nb of output bytes decoded */ - else - return (int)(((const char *)ip) - source); /* Nb of input bytes read */ - - /* Overflow error detected */ -_output_error: - return (int)(-(((const char *)ip) - source)) - 1; -} - -int LZ4_decompress_safe(const char *source, char *dest, int compressedSize, int maxDecompressedSize) -{ - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, - (BYTE *)dest, NULL, 0); -} - -int LZ4_decompress_safe_partial(const char *source, char *dest, int compressedSize, int targetOutputSize, - int maxDecompressedSize) -{ - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, - targetOutputSize, noDict, (BYTE *)dest, NULL, 0); -} - -int LZ4_decompress_fast(const char *source, char *dest, int originalSize) -{ - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, - (BYTE *)(dest - 64 KB), NULL, 64 KB); -} - -/* streaming decompression functions */ - -typedef struct -{ - const BYTE *externalDict; - size_t extDictSize; - const BYTE *prefixEnd; - size_t prefixSize; -} LZ4_streamDecode_t_internal; - -/* - * If you prefer dynamic allocation methods, - * LZ4_createStreamDecode() - * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure. - */ -LZ4_streamDecode_t *LZ4_createStreamDecode(void) -{ - LZ4_streamDecode_t *lz4s = (LZ4_streamDecode_t *)ALLOCATOR(1, sizeof(LZ4_streamDecode_t)); - return lz4s; -} - -int LZ4_freeStreamDecode(LZ4_streamDecode_t *LZ4_stream) -{ - FREEMEM(LZ4_stream); - return 0; -} - -/* - * LZ4_setStreamDecode - * Use this function to instruct where to find the dictionary - * This function is not necessary if previous data is still available where it was decoded. - * Loading a size of 0 is allowed (same effect as no dictionary). - * Return : 1 if OK, 0 if error - */ -int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, const char *dictionary, int dictSize) -{ - LZ4_streamDecode_t_internal *lz4sd = (LZ4_streamDecode_t_internal *)LZ4_streamDecode; - lz4sd->prefixSize = (size_t)dictSize; - lz4sd->prefixEnd = (const BYTE *)dictionary + dictSize; - lz4sd->externalDict = NULL; - lz4sd->extDictSize = 0; - return 1; -} - -/* -*_continue() : - These decoding functions allow decompression of multiple blocks in "streaming" mode. - Previously decoded blocks must still be available at the memory position where they were decoded. - If it's not possible, save the relevant part of decoded data into a safe buffer, - and indicate where it stands using LZ4_setStreamDecode() -*/ -int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *source, char *dest, - int compressedSize, int maxOutputSize) -{ - LZ4_streamDecode_t_internal *lz4sd = (LZ4_streamDecode_t_internal *)LZ4_streamDecode; - int result; - - if (lz4sd->prefixEnd == (BYTE *)dest) { - result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, - usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, - lz4sd->extDictSize); - if (result <= 0) - return result; - lz4sd->prefixSize += result; - lz4sd->prefixEnd += result; - } else { - lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, - usingExtDict, (BYTE *)dest, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) - return result; - lz4sd->prefixSize = result; - lz4sd->prefixEnd = (BYTE *)dest + result; - } - - return result; -} - -int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *source, char *dest, int originalSize) -{ - LZ4_streamDecode_t_internal *lz4sd = (LZ4_streamDecode_t_internal *)LZ4_streamDecode; - int result; - - if (lz4sd->prefixEnd == (BYTE *)dest) { - result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, - lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) - return result; - lz4sd->prefixSize += originalSize; - lz4sd->prefixEnd += originalSize; - } else { - lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = (BYTE *)dest - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, - (BYTE *)dest, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) - return result; - lz4sd->prefixSize = originalSize; - lz4sd->prefixEnd = (BYTE *)dest + originalSize; - } - - return result; -} - -/* -Advanced decoding functions : -*_usingDict() : - These decoding functions work the same as "_continue" ones, - the dictionary must be explicitly provided within parameters -*/ - -FORCE_INLINE int LZ4_decompress_usingDict_generic(const char *source, char *dest, int compressedSize, int maxOutputSize, - int safe, const char *dictStart, int dictSize) -{ - if (dictSize == 0) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE *)dest, - NULL, 0); - if (dictStart + dictSize == dest) { - if (dictSize >= (int)(64 KB - 1)) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, - (BYTE *)dest - 64 KB, NULL, 0); - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, - (BYTE *)dest - dictSize, NULL, 0); - } - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, - (BYTE *)dest, (const BYTE *)dictStart, dictSize); -} - -int LZ4_decompress_safe_usingDict(const char *source, char *dest, int compressedSize, int maxOutputSize, - const char *dictStart, int dictSize) -{ - return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); -} - -int LZ4_decompress_fast_usingDict(const char *source, char *dest, int originalSize, const char *dictStart, int dictSize) -{ - return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); -} - -/* debug function */ -int LZ4_decompress_safe_forceExtDict(const char *source, char *dest, int compressedSize, int maxOutputSize, - const char *dictStart, int dictSize) -{ - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, - (BYTE *)dest, (const BYTE *)dictStart, dictSize); -} - -/*************************************************** - * Obsolete Functions - ***************************************************/ -/* obsolete compression functions */ -int LZ4_compress_limitedOutput(const char *source, char *dest, int inputSize, int maxOutputSize) -{ - return LZ4_compress_default(source, dest, inputSize, maxOutputSize); -} -int LZ4_compress(const char *source, char *dest, int inputSize) -{ - return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); -} -int LZ4_compress_limitedOutput_withState(void *state, const char *src, char *dst, int srcSize, int dstSize) -{ - return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); -} -int LZ4_compress_withState(void *state, const char *src, char *dst, int srcSize) -{ - return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); -} -int LZ4_compress_limitedOutput_continue(LZ4_stream_t *LZ4_stream, const char *src, char *dst, int srcSize, - int maxDstSize) -{ - return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); -} -int LZ4_compress_continue(LZ4_stream_t *LZ4_stream, const char *source, char *dest, int inputSize) -{ - return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); -} - -/* -These function names are deprecated and should no longer be used. -They are only provided here for compatibility with older user programs. -- LZ4_uncompress is totally equivalent to LZ4_decompress_fast -- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe -*/ -int LZ4_uncompress(const char *source, char *dest, int outputSize) -{ - return LZ4_decompress_fast(source, dest, outputSize); -} -int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize) -{ - return LZ4_decompress_safe(source, dest, isize, maxOutputSize); -} - -/* Obsolete Streaming functions */ - -int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } - -static void LZ4_init(LZ4_stream_t_internal *lz4ds, BYTE *base) -{ - MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE); - lz4ds->bufferStart = base; -} - -int LZ4_resetStreamState(void *state, char *inputBuffer) -{ - if ((((size_t)state) & 3) != 0) - return 1; /* Error : pointer is not aligned on 4-bytes boundary */ - LZ4_init((LZ4_stream_t_internal *)state, (BYTE *)inputBuffer); - return 0; -} - -void *LZ4_create(char *inputBuffer) -{ - void *lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64); - LZ4_init((LZ4_stream_t_internal *)lz4ds, (BYTE *)inputBuffer); - return lz4ds; -} - -char *LZ4_slideInputBuffer(void *LZ4_Data) -{ - LZ4_stream_t_internal *ctx = (LZ4_stream_t_internal *)LZ4_Data; - int dictSize = LZ4_saveDict((LZ4_stream_t *)LZ4_Data, (char *)ctx->bufferStart, 64 KB); - return (char *)(ctx->bufferStart + dictSize); -} - -/* Obsolete streaming decompression functions */ - -int LZ4_decompress_safe_withPrefix64k(const char *source, char *dest, int compressedSize, int maxOutputSize) -{ - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, - (BYTE *)dest - 64 KB, NULL, 64 KB); -} - -int LZ4_decompress_fast_withPrefix64k(const char *source, char *dest, int originalSize) -{ - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, - (BYTE *)dest - 64 KB, NULL, 64 KB); -} - -#endif /* LZ4_COMMONDEFS_ONLY */ diff --git a/yosys/libs/fst/lz4.h b/yosys/libs/fst/lz4.h deleted file mode 100644 index 929cf02cac7..00000000000 --- a/yosys/libs/fst/lz4.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - LZ4 - Fast LZ compression algorithm - Header File - Copyright (C) 2011-2015, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - SPDX-License-Identifier: BSD-2-Clause - - You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 - - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c -*/ -#pragma once - -#if defined(__cplusplus) -extern "C" { -#endif - -/* - * lz4.h provides block compression functions, and gives full buffer control to programmer. - * If you need to generate inter-operable compressed data (respecting LZ4 frame specification), - * and can let the library handle its own memory, please use lz4frame.h instead. - */ - -/************************************** - * Version - **************************************/ -#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ -#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ -#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR * 100 * 100 + LZ4_VERSION_MINOR * 100 + LZ4_VERSION_RELEASE) -int LZ4_versionNumber(void); - -/************************************** - * Tuning parameter - **************************************/ -/* - * LZ4_MEMORY_USAGE : - * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) - * Increasing memory usage improves compression ratio - * Reduced memory usage can improve speed, due to cache effect - * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache - */ -#define LZ4_MEMORY_USAGE 14 - -/************************************** - * Simple Functions - **************************************/ - -int LZ4_compress_default(const char *source, char *dest, int sourceSize, int maxDestSize); -int LZ4_decompress_safe(const char *source, char *dest, int compressedSize, int maxDecompressedSize); - -/* -LZ4_compress_default() : - Compresses 'sourceSize' bytes from buffer 'source' - into already allocated 'dest' buffer of size 'maxDestSize'. - Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). - It also runs faster, so it's a recommended setting. - If the function cannot compress 'source' into a more limited 'dest' budget, - compression stops *immediately*, and the function result is zero. - As a consequence, 'dest' content is not valid. - This function never writes outside 'dest' buffer, nor read outside 'source' buffer. - sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE - maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) - return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) - or 0 if compression fails - -LZ4_decompress_safe() : - compressedSize : is the precise full size of the compressed block. - maxDecompressedSize : is the size of destination buffer, which must be already allocated. - return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) - If destination buffer is not large enough, decoding will stop and output an error code (<0). - If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function is protected against buffer overflow exploits, including malicious data packets. - It never writes outside output buffer, nor reads outside input buffer. -*/ - -/************************************** - * Advanced Functions - **************************************/ -#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ -#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize) / 255) + 16) - -/* -LZ4_compressBound() : - Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) - This function is primarily useful for memory allocation purposes (destination buffer size). - Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). - Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) - inputSize : max supported value is LZ4_MAX_INPUT_SIZE - return : maximum output size in a "worst case" scenario - or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) -*/ -int LZ4_compressBound(int inputSize); - -/* -LZ4_compress_fast() : - Same as LZ4_compress_default(), but allows to select an "acceleration" factor. - The larger the acceleration value, the faster the algorithm, but also the lesser the compression. - It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. - An acceleration value of "1" is the same as regular LZ4_compress_default() - Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. -*/ -int LZ4_compress_fast(const char *source, char *dest, int sourceSize, int maxDestSize, int acceleration); - -/* -LZ4_compress_fast_extState() : - Same compression function, just using an externally allocated memory space to store compression state. - Use LZ4_sizeofState() to know how much memory must be allocated, - and allocate it on 8-bytes boundaries (using malloc() typically). - Then, provide it as 'void* state' to compression function. -*/ -int LZ4_sizeofState(void); -int LZ4_compress_fast_extState(void *state, const char *source, char *dest, int inputSize, int maxDestSize, - int acceleration); - -/* -LZ4_compress_destSize() : - Reverse the logic, by compressing as much data as possible from 'source' buffer - into already allocated buffer 'dest' of size 'targetDestSize'. - This function either compresses the entire 'source' content into 'dest' if it's large enough, - or fill 'dest' buffer completely with as much data as possible from 'source'. - *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. - New value is necessarily <= old value. - return : Nb bytes written into 'dest' (necessarily <= targetDestSize) - or 0 if compression fails -*/ -int LZ4_compress_destSize(const char *source, char *dest, int *sourceSizePtr, int targetDestSize); - -/* -LZ4_decompress_fast() : - originalSize : is the original and therefore uncompressed size - return : the number of bytes read from the source buffer (in other words, the compressed size) - If the source stream is detected malformed, the function will stop decoding and return a negative result. - Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. - note : This function fully respect memory boundaries for properly formed compressed data. - It is a bit faster than LZ4_decompress_safe(). - However, it does not provide any protection against intentionally modified data stream (malicious input). - Use this function in trusted environment only (data to decode comes from a trusted source). -*/ -int LZ4_decompress_fast(const char *source, char *dest, int originalSize); - -/* -LZ4_decompress_safe_partial() : - This function decompress a compressed block of size 'compressedSize' at position 'source' - into destination buffer 'dest' of size 'maxDecompressedSize'. - The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, - reducing decompression time. - return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) - Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. - Always control how many bytes were decoded. - If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function never writes outside of output buffer, and never reads outside of input buffer. It is -therefore protected against malicious data packets -*/ -int LZ4_decompress_safe_partial(const char *source, char *dest, int compressedSize, int targetOutputSize, - int maxDecompressedSize); - -/*********************************************** - * Streaming Compression Functions - ***********************************************/ -#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE - 3)) + 4) -#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long)) -/* - * LZ4_stream_t - * information structure to track an LZ4 stream. - * important : init this structure content before first use ! - * note : only allocated directly the structure if you are statically linking LZ4 - * If you are using liblz4 as a DLL, please use below construction methods instead. - */ -typedef struct -{ - long long table[LZ4_STREAMSIZE_U64]; -} LZ4_stream_t; - -/* - * LZ4_resetStream - * Use this function to init an allocated LZ4_stream_t structure - */ -void LZ4_resetStream(LZ4_stream_t *streamPtr); - -/* - * LZ4_createStream will allocate and initialize an LZ4_stream_t structure - * LZ4_freeStream releases its memory. - * In the context of a DLL (liblz4), please use these methods rather than the static struct. - * They are more future proof, in case of a change of LZ4_stream_t size. - */ -LZ4_stream_t *LZ4_createStream(void); -int LZ4_freeStream(LZ4_stream_t *streamPtr); - -/* - * LZ4_loadDict - * Use this function to load a static dictionary into LZ4_stream. - * Any previous data will be forgotten, only 'dictionary' will remain in memory. - * Loading a size of 0 is allowed. - * Return : dictionary size, in bytes (necessarily <= 64 KB) - */ -int LZ4_loadDict(LZ4_stream_t *streamPtr, const char *dictionary, int dictSize); - -/* - * LZ4_compress_fast_continue - * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression - * ratio. Important : Previous data blocks are assumed to still be present and unmodified ! 'dst' buffer must be already - * allocated. If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. If - * not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero. - */ -int LZ4_compress_fast_continue(LZ4_stream_t *streamPtr, const char *src, char *dst, int srcSize, int maxDstSize, - int acceleration); - -/* - * LZ4_saveDict - * If previously compressed data block is not guaranteed to remain available at its memory location - * save it into a safer place (char* safeBuffer) - * Note : you don't need to call LZ4_loadDict() afterwards, - * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue() - * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error - */ -int LZ4_saveDict(LZ4_stream_t *streamPtr, char *safeBuffer, int dictSize); - -/************************************************ - * Streaming Decompression Functions - ************************************************/ - -#define LZ4_STREAMDECODESIZE_U64 4 -#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) -typedef struct -{ - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; -} LZ4_streamDecode_t; -/* - * LZ4_streamDecode_t - * information structure to track an LZ4 stream. - * init this structure content using LZ4_setStreamDecode or memset() before first use ! - * - * In the context of a DLL (liblz4) please prefer usage of construction methods below. - * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future. - * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure - * LZ4_freeStreamDecode releases its memory. - */ -LZ4_streamDecode_t *LZ4_createStreamDecode(void); -int LZ4_freeStreamDecode(LZ4_streamDecode_t *LZ4_stream); - -/* - * LZ4_setStreamDecode - * Use this function to instruct where to find the dictionary. - * Setting a size of 0 is allowed (same effect as reset). - * Return : 1 if OK, 0 if error - */ -int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, const char *dictionary, int dictSize); - -/* -*_continue() : - These decoding functions allow decompression of multiple blocks in "streaming" mode. - Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) - In the case of a ring buffers, decoding buffer must be either : - - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) - In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). - - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. - maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. - In which case, encoding and decoding buffers do not need to be synchronized, - and encoding ring buffer can have any size, including small ones ( < 64 KB). - - _At least_ 64 KB + 8 bytes + maxBlockSize. - In which case, encoding and decoding buffers do not need to be synchronized, - and encoding ring buffer can have any size, including larger than decoding buffer. - Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, - and indicate where it is saved using LZ4_setStreamDecode() -*/ -int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *source, char *dest, - int compressedSize, int maxDecompressedSize); -int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *source, char *dest, - int originalSize); - -/* -Advanced decoding functions : -*_usingDict() : - These decoding functions work the same as - a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue() - They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure. -*/ -int LZ4_decompress_safe_usingDict(const char *source, char *dest, int compressedSize, int maxDecompressedSize, - const char *dictStart, int dictSize); -int LZ4_decompress_fast_usingDict(const char *source, char *dest, int originalSize, const char *dictStart, - int dictSize); - -/************************************** - * Obsolete Functions - **************************************/ -/* Deprecate Warnings */ -/* Should these warnings messages be a problem, - it is generally possible to disable them, - with -Wno-deprecated-declarations for gcc - or _CRT_SECURE_NO_WARNINGS in Visual for example. - You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */ -#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK -#define LZ4_DEPRECATE_WARNING_DEFBLOCK -#define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#if (LZ4_GCC_VERSION >= 405) || defined(__clang__) -#define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) -#elif (LZ4_GCC_VERSION >= 301) -#define LZ4_DEPRECATED(message) __attribute__((deprecated)) -#elif defined(_MSC_VER) -#define LZ4_DEPRECATED(message) __declspec(deprecated(message)) -#else -#pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") -#define LZ4_DEPRECATED(message) -#endif -#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */ - -/* Obsolete compression functions */ -/* These functions are planned to start generate warnings by r131 approximately */ -int LZ4_compress(const char *source, char *dest, int sourceSize); -int LZ4_compress_limitedOutput(const char *source, char *dest, int sourceSize, int maxOutputSize); -int LZ4_compress_withState(void *state, const char *source, char *dest, int inputSize); -int LZ4_compress_limitedOutput_withState(void *state, const char *source, char *dest, int inputSize, int maxOutputSize); -int LZ4_compress_continue(LZ4_stream_t *LZ4_streamPtr, const char *source, char *dest, int inputSize); -int LZ4_compress_limitedOutput_continue(LZ4_stream_t *LZ4_streamPtr, const char *source, char *dest, int inputSize, - int maxOutputSize); - -/* Obsolete decompression functions */ -/* These function names are completely deprecated and must no longer be used. - They are only provided here for compatibility with older programs. - - LZ4_uncompress is the same as LZ4_decompress_fast - - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe - These function prototypes are now disabled; uncomment them only if you really need them. - It is highly recommended to stop using these prototypes and migrate to maintained ones */ -/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */ -/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */ - -/* Obsolete streaming functions; use new streaming interface whenever possible */ -LZ4_DEPRECATED("use LZ4_createStream() instead") void *LZ4_create(char *inputBuffer); -LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void); -LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void *state, char *inputBuffer); -LZ4_DEPRECATED("use LZ4_saveDict() instead") char *LZ4_slideInputBuffer(void *state); - -/* Obsolete streaming decoding functions */ -LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") -int LZ4_decompress_safe_withPrefix64k(const char *src, char *dst, int compressedSize, int maxDstSize); -LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") -int LZ4_decompress_fast_withPrefix64k(const char *src, char *dst, int originalSize); - -#if defined(__cplusplus) -} -#endif diff --git a/yosys/libs/json11/json11.cpp b/yosys/libs/json11/json11.cpp deleted file mode 100644 index 189e63881ac..00000000000 --- a/yosys/libs/json11/json11.cpp +++ /dev/null @@ -1,788 +0,0 @@ -/* Copyright (c) 2013 Dropbox, Inc. - * - * 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 "json11.hpp" -#include -#include -#include -#include -#include - -namespace json11 { - -static const int max_depth = 200; - -using std::string; -using std::vector; -using std::map; -using std::make_shared; -using std::initializer_list; -using std::move; - -/* Helper for representing null - just a do-nothing struct, plus comparison - * operators so the helpers in JsonValue work. We can't use nullptr_t because - * it may not be orderable. - */ -struct NullStruct { - bool operator==(NullStruct) const { return true; } - bool operator<(NullStruct) const { return false; } -}; - -/* * * * * * * * * * * * * * * * * * * * - * Serialization - */ - -static void dump(NullStruct, string &out) { - out += "null"; -} - -static void dump(double value, string &out) { - if (std::isfinite(value)) { - char buf[32]; - snprintf(buf, sizeof buf, "%.17g", value); - out += buf; - } else { - out += "null"; - } -} - -static void dump(int value, string &out) { - char buf[32]; - snprintf(buf, sizeof buf, "%d", value); - out += buf; -} - -static void dump(bool value, string &out) { - out += value ? "true" : "false"; -} - -static void dump(const string &value, string &out) { - out += '"'; - for (size_t i = 0; i < value.length(); i++) { - const char ch = value[i]; - if (ch == '\\') { - out += "\\\\"; - } else if (ch == '"') { - out += "\\\""; - } else if (ch == '\b') { - out += "\\b"; - } else if (ch == '\f') { - out += "\\f"; - } else if (ch == '\n') { - out += "\\n"; - } else if (ch == '\r') { - out += "\\r"; - } else if (ch == '\t') { - out += "\\t"; - } else if (static_cast(ch) <= 0x1f) { - char buf[8]; - snprintf(buf, sizeof buf, "\\u%04x", ch); - out += buf; - } else if (static_cast(ch) == 0xe2 && static_cast(value[i+1]) == 0x80 - && static_cast(value[i+2]) == 0xa8) { - out += "\\u2028"; - i += 2; - } else if (static_cast(ch) == 0xe2 && static_cast(value[i+1]) == 0x80 - && static_cast(value[i+2]) == 0xa9) { - out += "\\u2029"; - i += 2; - } else { - out += ch; - } - } - out += '"'; -} - -static void dump(const Json::array &values, string &out) { - bool first = true; - out += "["; - for (const auto &value : values) { - if (!first) - out += ", "; - value.dump(out); - first = false; - } - out += "]"; -} - -static void dump(const Json::object &values, string &out) { - bool first = true; - out += "{"; - for (const auto &kv : values) { - if (!first) - out += ", "; - dump(kv.first, out); - out += ": "; - kv.second.dump(out); - first = false; - } - out += "}"; -} - -void Json::dump(string &out) const { - m_ptr->dump(out); -} - -/* * * * * * * * * * * * * * * * * * * * - * Value wrappers - */ - -template -class Value : public JsonValue { -protected: - - // Constructors - explicit Value(const T &value) : m_value(value) {} - explicit Value(T &&value) : m_value(std::move(value)) {} - - // Get type tag - Json::Type type() const override { - return tag; - } - - // Comparisons - bool equals(const JsonValue * other) const override { - return m_value == static_cast *>(other)->m_value; - } - bool less(const JsonValue * other) const override { - return m_value < static_cast *>(other)->m_value; - } - - const T m_value; - void dump(string &out) const override { json11::dump(m_value, out); } -}; - -class JsonDouble final : public Value { - double number_value() const override { return m_value; } - int int_value() const override { return static_cast(m_value); } - bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } - bool less(const JsonValue * other) const override { return m_value < other->number_value(); } -public: - explicit JsonDouble(double value) : Value(value) {} -}; - -class JsonInt final : public Value { - double number_value() const override { return m_value; } - int int_value() const override { return m_value; } - bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } - bool less(const JsonValue * other) const override { return m_value < other->number_value(); } -public: - explicit JsonInt(int value) : Value(value) {} -}; - -class JsonBoolean final : public Value { - bool bool_value() const override { return m_value; } -public: - explicit JsonBoolean(bool value) : Value(value) {} -}; - -class JsonString final : public Value { - const string &string_value() const override { return m_value; } -public: - explicit JsonString(const string &value) : Value(value) {} - explicit JsonString(string &&value) : Value(std::move(value)) {} -}; - -class JsonArray final : public Value { - const Json::array &array_items() const override { return m_value; } - const Json & operator[](size_t i) const override; -public: - explicit JsonArray(const Json::array &value) : Value(value) {} - explicit JsonArray(Json::array &&value) : Value(std::move(value)) {} -}; - -class JsonObject final : public Value { - const Json::object &object_items() const override { return m_value; } - const Json & operator[](const string &key) const override; -public: - explicit JsonObject(const Json::object &value) : Value(value) {} - explicit JsonObject(Json::object &&value) : Value(std::move(value)) {} -}; - -class JsonNull final : public Value { -public: - JsonNull() : Value({}) {} -}; - -/* * * * * * * * * * * * * * * * * * * * - * Static globals - static-init-safe - */ -struct Statics { - const std::shared_ptr null = make_shared(); - const std::shared_ptr t = make_shared(true); - const std::shared_ptr f = make_shared(false); - const string empty_string; - const vector empty_vector; - const map empty_map; - Statics() {} -}; - -static const Statics & statics() { - static const Statics s {}; - return s; -} - -static const Json & static_null() { - // This has to be separate, not in Statics, because Json() accesses statics().null. - static const Json json_null; - return json_null; -} - -/* * * * * * * * * * * * * * * * * * * * - * Constructors - */ - -Json::Json() noexcept : m_ptr(statics().null) {} -Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {} -Json::Json(double value) : m_ptr(make_shared(value)) {} -Json::Json(int value) : m_ptr(make_shared(value)) {} -Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {} -Json::Json(const string &value) : m_ptr(make_shared(value)) {} -Json::Json(string &&value) : m_ptr(make_shared(std::move(value))) {} -Json::Json(const char * value) : m_ptr(make_shared(value)) {} -Json::Json(const Json::array &values) : m_ptr(make_shared(values)) {} -Json::Json(Json::array &&values) : m_ptr(make_shared(std::move(values))) {} -Json::Json(const Json::object &values) : m_ptr(make_shared(values)) {} -Json::Json(Json::object &&values) : m_ptr(make_shared(std::move(values))) {} - -/* * * * * * * * * * * * * * * * * * * * - * Accessors - */ - -Json::Type Json::type() const { return m_ptr->type(); } -double Json::number_value() const { return m_ptr->number_value(); } -int Json::int_value() const { return m_ptr->int_value(); } -bool Json::bool_value() const { return m_ptr->bool_value(); } -const string & Json::string_value() const { return m_ptr->string_value(); } -const vector & Json::array_items() const { return m_ptr->array_items(); } -const map & Json::object_items() const { return m_ptr->object_items(); } -const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; } -const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; } - -double JsonValue::number_value() const { return 0; } -int JsonValue::int_value() const { return 0; } -bool JsonValue::bool_value() const { return false; } -const string & JsonValue::string_value() const { return statics().empty_string; } -const vector & JsonValue::array_items() const { return statics().empty_vector; } -const map & JsonValue::object_items() const { return statics().empty_map; } -const Json & JsonValue::operator[] (size_t) const { return static_null(); } -const Json & JsonValue::operator[] (const string &) const { return static_null(); } - -const Json & JsonObject::operator[] (const string &key) const { - auto iter = m_value.find(key); - return (iter == m_value.end()) ? static_null() : iter->second; -} -const Json & JsonArray::operator[] (size_t i) const { - if (i >= m_value.size()) return static_null(); - else return m_value[i]; -} - -/* * * * * * * * * * * * * * * * * * * * - * Comparison - */ - -bool Json::operator== (const Json &other) const { - if (m_ptr == other.m_ptr) - return true; - if (m_ptr->type() != other.m_ptr->type()) - return false; - - return m_ptr->equals(other.m_ptr.get()); -} - -bool Json::operator< (const Json &other) const { - if (m_ptr == other.m_ptr) - return false; - if (m_ptr->type() != other.m_ptr->type()) - return m_ptr->type() < other.m_ptr->type(); - - return m_ptr->less(other.m_ptr.get()); -} - -/* * * * * * * * * * * * * * * * * * * * - * Parsing - */ - -/* esc(c) - * - * Format char c suitable for printing in an error message. - */ -static inline string esc(char c) { - char buf[12]; - if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { - snprintf(buf, sizeof buf, "'%c' (%d)", c, c); - } else { - snprintf(buf, sizeof buf, "(%d)", c); - } - return string(buf); -} - -static inline bool in_range(long x, long lower, long upper) { - return (x >= lower && x <= upper); -} - -namespace { -/* JsonParser - * - * Object that tracks all state of an in-progress parse. - */ -struct JsonParser final { - - /* State - */ - const string &str; - size_t i; - string &err; - bool failed; - const JsonParse strategy; - - /* fail(msg, err_ret = Json()) - * - * Mark this parse as failed. - */ - Json fail(string &&msg) { - return fail(std::move(msg), Json()); - } - - template - T fail(string &&msg, const T err_ret) { - if (!failed) - err = std::move(msg); - failed = true; - return err_ret; - } - - /* consume_whitespace() - * - * Advance until the current character is non-whitespace. - */ - void consume_whitespace() { - while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t') - i++; - } - - /* consume_comment() - * - * Advance comments (c-style inline and multiline). - */ - bool consume_comment() { - bool comment_found = false; - if (str[i] == '/') { - i++; - if (i == str.size()) - return fail("unexpected end of input after start of comment", false); - if (str[i] == '/') { // inline comment - i++; - // advance until next line, or end of input - while (i < str.size() && str[i] != '\n') { - i++; - } - comment_found = true; - } - else if (str[i] == '*') { // multiline comment - i++; - if (i > str.size()-2) - return fail("unexpected end of input inside multi-line comment", false); - // advance until closing tokens - while (!(str[i] == '*' && str[i+1] == '/')) { - i++; - if (i > str.size()-2) - return fail( - "unexpected end of input inside multi-line comment", false); - } - i += 2; - comment_found = true; - } - else - return fail("malformed comment", false); - } - return comment_found; - } - - /* consume_garbage() - * - * Advance until the current character is non-whitespace and non-comment. - */ - void consume_garbage() { - consume_whitespace(); - if(strategy == JsonParse::COMMENTS) { - bool comment_found = false; - do { - comment_found = consume_comment(); - if (failed) return; - consume_whitespace(); - } - while(comment_found); - } - } - - /* get_next_token() - * - * Return the next non-whitespace character. If the end of the input is reached, - * flag an error and return 0. - */ - char get_next_token() { - consume_garbage(); - if (failed) return static_cast(0); - if (i == str.size()) - return fail("unexpected end of input", static_cast(0)); - - return str[i++]; - } - - /* encode_utf8(pt, out) - * - * Encode pt as UTF-8 and add it to out. - */ - void encode_utf8(long pt, string & out) { - if (pt < 0) - return; - - if (pt < 0x80) { - out += static_cast(pt); - } else if (pt < 0x800) { - out += static_cast((pt >> 6) | 0xC0); - out += static_cast((pt & 0x3F) | 0x80); - } else if (pt < 0x10000) { - out += static_cast((pt >> 12) | 0xE0); - out += static_cast(((pt >> 6) & 0x3F) | 0x80); - out += static_cast((pt & 0x3F) | 0x80); - } else { - out += static_cast((pt >> 18) | 0xF0); - out += static_cast(((pt >> 12) & 0x3F) | 0x80); - out += static_cast(((pt >> 6) & 0x3F) | 0x80); - out += static_cast((pt & 0x3F) | 0x80); - } - } - - /* parse_string() - * - * Parse a string, starting at the current position. - */ - string parse_string() { - string out; - long last_escaped_codepoint = -1; - while (true) { - if (i == str.size()) - return fail("unexpected end of input in string", ""); - - char ch = str[i++]; - - if (ch == '"') { - encode_utf8(last_escaped_codepoint, out); - return out; - } - - if (in_range(ch, 0, 0x1f)) - return fail("unescaped " + esc(ch) + " in string", ""); - - // The usual case: non-escaped characters - if (ch != '\\') { - encode_utf8(last_escaped_codepoint, out); - last_escaped_codepoint = -1; - out += ch; - continue; - } - - // Handle escapes - if (i == str.size()) - return fail("unexpected end of input in string", ""); - - ch = str[i++]; - - if (ch == 'u') { - // Extract 4-byte escape sequence - string esc = str.substr(i, 4); - // Explicitly check length of the substring. The following loop - // relies on std::string returning the terminating NUL when - // accessing str[length]. Checking here reduces brittleness. - if (esc.length() < 4) { - return fail("bad \\u escape: " + esc, ""); - } - for (size_t j = 0; j < 4; j++) { - if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') - && !in_range(esc[j], '0', '9')) - return fail("bad \\u escape: " + esc, ""); - } - - long codepoint = strtol(esc.data(), nullptr, 16); - - // JSON specifies that characters outside the BMP shall be encoded as a pair - // of 4-hex-digit \u escapes encoding their surrogate pair components. Check - // whether we're in the middle of such a beast: the previous codepoint was an - // escaped lead (high) surrogate, and this is a trail (low) surrogate. - if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) - && in_range(codepoint, 0xDC00, 0xDFFF)) { - // Reassemble the two surrogate pairs into one astral-plane character, per - // the UTF-16 algorithm. - encode_utf8((((last_escaped_codepoint - 0xD800) << 10) - | (codepoint - 0xDC00)) + 0x10000, out); - last_escaped_codepoint = -1; - } else { - encode_utf8(last_escaped_codepoint, out); - last_escaped_codepoint = codepoint; - } - - i += 4; - continue; - } - - encode_utf8(last_escaped_codepoint, out); - last_escaped_codepoint = -1; - - if (ch == 'b') { - out += '\b'; - } else if (ch == 'f') { - out += '\f'; - } else if (ch == 'n') { - out += '\n'; - } else if (ch == 'r') { - out += '\r'; - } else if (ch == 't') { - out += '\t'; - } else if (ch == '"' || ch == '\\' || ch == '/') { - out += ch; - } else { - return fail("invalid escape character " + esc(ch), ""); - } - } - } - - /* parse_number() - * - * Parse a double. - */ - Json parse_number() { - size_t start_pos = i; - - if (str[i] == '-') - i++; - - // Integer part - if (str[i] == '0') { - i++; - if (in_range(str[i], '0', '9')) - return fail("leading 0s not permitted in numbers"); - } else if (in_range(str[i], '1', '9')) { - i++; - while (in_range(str[i], '0', '9')) - i++; - } else { - return fail("invalid " + esc(str[i]) + " in number"); - } - - if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' - && (i - start_pos) <= static_cast(std::numeric_limits::digits10)) { - return std::atoi(str.c_str() + start_pos); - } - - // Decimal part - if (str[i] == '.') { - i++; - if (!in_range(str[i], '0', '9')) - return fail("at least one digit required in fractional part"); - - while (in_range(str[i], '0', '9')) - i++; - } - - // Exponent part - if (str[i] == 'e' || str[i] == 'E') { - i++; - - if (str[i] == '+' || str[i] == '-') - i++; - - if (!in_range(str[i], '0', '9')) - return fail("at least one digit required in exponent"); - - while (in_range(str[i], '0', '9')) - i++; - } - - return std::strtod(str.c_str() + start_pos, nullptr); - } - - /* expect(str, res) - * - * Expect that 'str' starts at the character that was just read. If it does, advance - * the input and return res. If not, flag an error. - */ - Json expect(const string &expected, Json res) { - assert(i != 0); - i--; - if (str.compare(i, expected.length(), expected) == 0) { - i += expected.length(); - return res; - } else { - return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length())); - } - } - - /* parse_json() - * - * Parse a JSON object. - */ - Json parse_json(int depth) { - if (depth > max_depth) { - return fail("exceeded maximum nesting depth"); - } - - char ch = get_next_token(); - if (failed) - return Json(); - - if (ch == '-' || (ch >= '0' && ch <= '9')) { - i--; - return parse_number(); - } - - if (ch == 't') - return expect("true", true); - - if (ch == 'f') - return expect("false", false); - - if (ch == 'n') - return expect("null", Json()); - - if (ch == '"') - return parse_string(); - - if (ch == '{') { - map data; - ch = get_next_token(); - if (ch == '}') - return data; - - while (1) { - if (ch != '"') - return fail("expected '\"' in object, got " + esc(ch)); - - string key = parse_string(); - if (failed) - return Json(); - - ch = get_next_token(); - if (ch != ':') - return fail("expected ':' in object, got " + esc(ch)); - - data[std::move(key)] = parse_json(depth + 1); - if (failed) - return Json(); - - ch = get_next_token(); - if (ch == '}') - break; - if (ch != ',') - return fail("expected ',' in object, got " + esc(ch)); - - ch = get_next_token(); - } - return data; - } - - if (ch == '[') { - vector data; - ch = get_next_token(); - if (ch == ']') - return data; - - while (1) { - i--; - data.push_back(parse_json(depth + 1)); - if (failed) - return Json(); - - ch = get_next_token(); - if (ch == ']') - break; - if (ch != ',') - return fail("expected ',' in list, got " + esc(ch)); - - ch = get_next_token(); - (void)ch; - } - return data; - } - - return fail("expected value, got " + esc(ch)); - } -}; -}//namespace { - -Json Json::parse(const string &in, string &err, JsonParse strategy) { - JsonParser parser { in, 0, err, false, strategy }; - Json result = parser.parse_json(0); - - // Check for any trailing garbage - parser.consume_garbage(); - if (parser.failed) - return Json(); - if (parser.i != in.size()) - return parser.fail("unexpected trailing " + esc(in[parser.i])); - - return result; -} - -// Documented in json11.hpp -vector Json::parse_multi(const string &in, - std::string::size_type &parser_stop_pos, - string &err, - JsonParse strategy) { - JsonParser parser { in, 0, err, false, strategy }; - parser_stop_pos = 0; - vector json_vec; - while (parser.i != in.size() && !parser.failed) { - json_vec.push_back(parser.parse_json(0)); - if (parser.failed) - break; - - // Check for another object - parser.consume_garbage(); - if (parser.failed) - break; - parser_stop_pos = parser.i; - } - return json_vec; -} - -/* * * * * * * * * * * * * * * * * * * * - * Shape-checking - */ - -bool Json::has_shape(const shape & types, string & err) const { - if (!is_object()) { - err = "expected JSON object, got " + dump(); - return false; - } - - for (auto & item : types) { - if ((*this)[item.first].type() != item.second) { - err = "bad type for " + item.first + " in " + dump(); - return false; - } - } - - return true; -} - -} // namespace json11 diff --git a/yosys/libs/json11/json11.hpp b/yosys/libs/json11/json11.hpp deleted file mode 100644 index 0c47d050932..00000000000 --- a/yosys/libs/json11/json11.hpp +++ /dev/null @@ -1,232 +0,0 @@ -/* json11 - * - * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization. - * - * The core object provided by the library is json11::Json. A Json object represents any JSON - * value: null, bool, number (int or double), string (std::string), array (std::vector), or - * object (std::map). - * - * Json objects act like values: they can be assigned, copied, moved, compared for equality or - * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and - * Json::parse (static) to parse a std::string as a Json object. - * - * Internally, the various types of Json object are represented by the JsonValue class - * hierarchy. - * - * A note on numbers - JSON specifies the syntax of number formatting but not its semantics, - * so some JSON implementations distinguish between integers and floating-point numbers, while - * some don't. In json11, we choose the latter. Because some JSON implementations (namely - * Javascript itself) treat all numbers as the same type, distinguishing the two leads - * to JSON that will be *silently* changed by a round-trip through those implementations. - * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also - * provides integer helpers. - * - * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the - * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64 - * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch - * will be exact for +/- 275 years.) - */ - -/* Copyright (c) 2013 Dropbox, Inc. - * - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#ifdef _MSC_VER - #if _MSC_VER <= 1800 // VS 2013 - #ifndef noexcept - #define noexcept throw() - #endif - - #ifndef snprintf - #define snprintf _snprintf_s - #endif - #endif -#endif - -namespace json11 { - -enum JsonParse { - STANDARD, COMMENTS -}; - -class JsonValue; - -class Json final { -public: - // Types - enum Type { - NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT - }; - - // Array and object typedefs - typedef std::vector array; - typedef std::map object; - - // Constructors for the various types of JSON value. - Json() noexcept; // NUL - Json(std::nullptr_t) noexcept; // NUL - Json(double value); // NUMBER - Json(int value); // NUMBER - Json(bool value); // BOOL - Json(const std::string &value); // STRING - Json(std::string &&value); // STRING - Json(const char * value); // STRING - Json(const array &values); // ARRAY - Json(array &&values); // ARRAY - Json(const object &values); // OBJECT - Json(object &&values); // OBJECT - - // Implicit constructor: anything with a to_json() function. - template - Json(const T & t) : Json(t.to_json()) {} - - // Implicit constructor: map-like objects (std::map, std::unordered_map, etc) - template ().begin()->first)>::value - && std::is_constructible().begin()->second)>::value, - int>::type = 0> - Json(const M & m) : Json(object(m.begin(), m.end())) {} - - // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc) - template ().begin())>::value, - int>::type = 0> - Json(const V & v) : Json(array(v.begin(), v.end())) {} - - // This prevents Json(some_pointer) from accidentally producing a bool. Use - // Json(bool(some_pointer)) if that behavior is desired. - Json(void *) = delete; - - // Accessors - Type type() const; - - bool is_null() const { return type() == NUL; } - bool is_number() const { return type() == NUMBER; } - bool is_bool() const { return type() == BOOL; } - bool is_string() const { return type() == STRING; } - bool is_array() const { return type() == ARRAY; } - bool is_object() const { return type() == OBJECT; } - - // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not - // distinguish between integer and non-integer numbers - number_value() and int_value() - // can both be applied to a NUMBER-typed object. - double number_value() const; - int int_value() const; - - // Return the enclosed value if this is a boolean, false otherwise. - bool bool_value() const; - // Return the enclosed string if this is a string, "" otherwise. - const std::string &string_value() const; - // Return the enclosed std::vector if this is an array, or an empty vector otherwise. - const array &array_items() const; - // Return the enclosed std::map if this is an object, or an empty map otherwise. - const object &object_items() const; - - // Return a reference to arr[i] if this is an array, Json() otherwise. - const Json & operator[](size_t i) const; - // Return a reference to obj[key] if this is an object, Json() otherwise. - const Json & operator[](const std::string &key) const; - - // Serialize. - void dump(std::string &out) const; - std::string dump() const { - std::string out; - dump(out); - return out; - } - - // Parse. If parse fails, return Json() and assign an error message to err. - static Json parse(const std::string & in, - std::string & err, - JsonParse strategy = JsonParse::STANDARD); - static Json parse(const char * in, - std::string & err, - JsonParse strategy = JsonParse::STANDARD) { - if (in) { - return parse(std::string(in), err, strategy); - } else { - err = "null input"; - return nullptr; - } - } - // Parse multiple objects, concatenated or separated by whitespace - static std::vector parse_multi( - const std::string & in, - std::string::size_type & parser_stop_pos, - std::string & err, - JsonParse strategy = JsonParse::STANDARD); - - static inline std::vector parse_multi( - const std::string & in, - std::string & err, - JsonParse strategy = JsonParse::STANDARD) { - std::string::size_type parser_stop_pos; - return parse_multi(in, parser_stop_pos, err, strategy); - } - - bool operator== (const Json &rhs) const; - bool operator< (const Json &rhs) const; - bool operator!= (const Json &rhs) const { return !(*this == rhs); } - bool operator<= (const Json &rhs) const { return !(rhs < *this); } - bool operator> (const Json &rhs) const { return (rhs < *this); } - bool operator>= (const Json &rhs) const { return !(*this < rhs); } - - /* has_shape(types, err) - * - * Return true if this is a JSON object and, for each item in types, has a field of - * the given type. If not, return false and set err to a descriptive message. - */ - typedef std::initializer_list> shape; - bool has_shape(const shape & types, std::string & err) const; - -private: - std::shared_ptr m_ptr; -}; - -// Internal class hierarchy - JsonValue objects are not exposed to users of this API. -class JsonValue { -protected: - friend class Json; - friend class JsonInt; - friend class JsonDouble; - virtual Json::Type type() const = 0; - virtual bool equals(const JsonValue * other) const = 0; - virtual bool less(const JsonValue * other) const = 0; - virtual void dump(std::string &out) const = 0; - virtual double number_value() const; - virtual int int_value() const; - virtual bool bool_value() const; - virtual const std::string &string_value() const; - virtual const Json::array &array_items() const; - virtual const Json &operator[](size_t i) const; - virtual const Json::object &object_items() const; - virtual const Json &operator[](const std::string &key) const; - virtual ~JsonValue() {} -}; - -} // namespace json11 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 e21683f9811..00000000000 --- 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 6c754b1ed6a..00000000000 --- 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 068356b732c..00000000000 --- 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 175f483bffe..00000000000 --- 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_PATCH_wasm.patch b/yosys/libs/minisat/00_PATCH_wasm.patch deleted file mode 100644 index 38493004797..00000000000 --- a/yosys/libs/minisat/00_PATCH_wasm.patch +++ /dev/null @@ -1,46 +0,0 @@ ---- System.cc -+++ System.cc -@@ -101,7 +101,7 @@ double Minisat::memUsedPeak(bool) { return 0; } - #endif - - --#if !defined(_MSC_VER) && !defined(__MINGW32__) -+#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__wasm) - void Minisat::limitMemory(uint64_t max_mem_mb) - { - // FIXME: OpenBSD does not support RLIMIT_AS. Not sure how well RLIMIT_DATA works instead. -@@ -133,7 +133,7 @@ void Minisat::limitMemory(uint64_t /*max_mem_mb*/) - #endif - - --#if !defined(_MSC_VER) && !defined(__MINGW32__) -+#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__wasm) - void Minisat::limitTime(uint32_t max_cpu_time) - { - if (max_cpu_time != 0){ -@@ -156,9 +156,13 @@ void Minisat::limitTime(uint32_t /*max_cpu_time*/) - - void Minisat::sigTerm(void handler(int)) - { -+#if defined(__wasm) -+ (void)handler; -+#else - signal(SIGINT, handler); - signal(SIGTERM,handler); - #ifdef SIGXCPU - signal(SIGXCPU,handler); - #endif -+#endif - } ---- System.cc -+++ System.cc -@@ -24,7 +24,9 @@ - OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - **************************************************************************************************/ - -+#if !defined(__wasm) - #include -+#endif - #include - - #include "System.h" diff --git a/yosys/libs/minisat/00_UPDATE.sh b/yosys/libs/minisat/00_UPDATE.sh deleted file mode 100755 index 51107e4506a..00000000000 --- 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 -patch -p0 < 00_PATCH_wasm.patch diff --git a/yosys/libs/minisat/Alg.h b/yosys/libs/minisat/Alg.h deleted file mode 100644 index ddb972e772b..00000000000 --- 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 6591dcd555d..00000000000 --- 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 61b9d3ca0af..00000000000 --- 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 057a3cdf247..00000000000 --- 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 9a66315d194..00000000000 --- 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 c4881628497..00000000000 --- 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 22816ff39b1..00000000000 --- 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 a6f8320006a..00000000000 --- 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 5c45dd6ac45..00000000000 --- 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 d602769cf21..00000000000 --- 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 04911c70a51..00000000000 --- 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 5ba50cd2bfd..00000000000 --- 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 ccb94c6ce15..00000000000 --- 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 7348a905dbc..00000000000 --- 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 76d5aca1f01..00000000000 --- 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 f6d4fb5ae98..00000000000 --- 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 44570b0e15d..00000000000 --- 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 a7df57858f7..00000000000 --- 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 cc96486d8c0..00000000000 --- 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 807e46c694b..00000000000 --- a/yosys/libs/minisat/System.cc +++ /dev/null @@ -1,170 +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. -**************************************************************************************************/ - -#if !defined(__wasm) -#include -#endif -#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__) && !defined(__wasm) -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__) && !defined(__wasm) -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)) -{ -#if defined(__wasm) - (void)handler; -#else - signal(SIGINT, handler); - signal(SIGTERM,handler); -#ifdef SIGXCPU - signal(SIGXCPU,handler); -#endif -#endif -} diff --git a/yosys/libs/minisat/System.h b/yosys/libs/minisat/System.h deleted file mode 100644 index cd9d020c736..00000000000 --- 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 6e398801f58..00000000000 --- 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 1da176028d3..00000000000 --- 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 51bbd85c88d..00000000000 --- 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 b1346b548f3..00000000000 --- 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 constexpr unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */ - static constexpr unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */ - static constexpr 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 9f1eb4e8f1c..00000000000 --- 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 f81085b5bc3..00000000000 --- 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 de85cdfea7e..00000000000 --- 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 Claire Xenia 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 149dc6aa0e6..00000000000 --- 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 c4b37a4defc..00000000000 --- 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 f38da3fcc57..00000000000 --- a/yosys/libs/subcircuit/subcircuit.cc +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * SubCircuit -- An implementation of the Ullmann Subgraph Isomorphism - * algorithm for coarse grain logic networks - * - * Copyright (C) 2013 Claire Xenia 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 constexpr 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 f2a28ecd26d..00000000000 --- 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 Claire Xenia 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 e33e26985b5..00000000000 --- 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 71938c1c181..00000000000 --- 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 7ba272ea19a..00000000000 --- 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 b4e05e35e8d..00000000000 --- 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 f1cb4cfd54d..00000000000 --- 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 110f65b1900..00000000000 --- 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/PRESENTATION_ExAdv.tex b/yosys/manual/PRESENTATION_ExAdv.tex deleted file mode 100644 index 6a426ff2b1f..00000000000 --- 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{https://yosyshq.net/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_ExAdv/.gitignore b/yosys/manual/PRESENTATION_ExAdv/.gitignore deleted file mode 100644 index cf658897d52..00000000000 --- 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 993a9d9e10c..00000000000 --- 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 13ecf0bae69..00000000000 --- 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 b53271faac6..00000000000 --- 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 c08f1106a25..00000000000 --- 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 6358a47c972..00000000000 --- 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 8d106a28c9d..00000000000 --- 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 8391fb383db..00000000000 --- 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 3630102faf0..00000000000 --- 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 42f5bae958e..00000000000 --- 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 e369672251d..00000000000 --- 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 683d9d84750..00000000000 --- 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 f3e8af4f046..00000000000 --- 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 9dfaef13126..00000000000 --- 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 f23f6c02ac9..00000000000 --- 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 06372f5af0d..00000000000 --- 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 4a3c2a06240..00000000000 --- 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 4b975f414c2..00000000000 --- 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 c5dac49eb9b..00000000000 --- 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 e888a7a7c26..00000000000 --- 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 620a06d9e53..00000000000 --- 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 48203e31992..00000000000 --- 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 0750a130794..00000000000 --- 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 8c37b1dba43..00000000000 --- 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 bcdd32cbf81..00000000000 --- 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 b9234603494..00000000000 --- 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 1b0bb7eeb67..00000000000 --- 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 9832c104b3d..00000000000 --- 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 ce1771544f6..00000000000 --- 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 b4dbd9e07cd..00000000000 --- 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 eb715f83d71..00000000000 --- 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 0c07e7e877c..00000000000 --- 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 3f5113e3cf4..00000000000 --- 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{https://yosyshq.net/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_ExOth/.gitignore b/yosys/manual/PRESENTATION_ExOth/.gitignore deleted file mode 100644 index cf658897d52..00000000000 --- 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 4864d8d5203..00000000000 --- 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 fe9008adbe9..00000000000 --- 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 0be833f16ec..00000000000 --- 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 19663ac7733..00000000000 --- 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 8db0a88a5fb..00000000000 --- 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 d4c1fa2bbc8..00000000000 --- 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 2ef14c56e5f..00000000000 --- 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 d7cfdc6f2fc..00000000000 --- 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{https://yosyshq.net/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_ExSyn/.gitignore b/yosys/manual/PRESENTATION_ExSyn/.gitignore deleted file mode 100644 index cf658897d52..00000000000 --- 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 c34eae3ffcf..00000000000 --- 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 3bc6863538d..00000000000 --- 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 bb0b3780ff3..00000000000 --- 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 bf6b34788d0..00000000000 --- 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 44409479895..00000000000 --- 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 0a3f9acd71c..00000000000 --- 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 2ffd8223ab5..00000000000 --- 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 dbe86ed187e..00000000000 --- 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 9da6fda5493..00000000000 --- 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 5d3c1ea49fc..00000000000 --- 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 34ed123bee4..00000000000 --- 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 762fc1a8993..00000000000 --- 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 fc92a636ed4..00000000000 --- 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 134161bb80a..00000000000 --- 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 282f06ddecc..00000000000 --- 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 2ed44763953..00000000000 --- 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 f5ddae29f20..00000000000 --- 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 6128631955b..00000000000 --- 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 c22a2fd5f06..00000000000 --- 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 8e440f6cec8..00000000000 --- 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 823b18d6e1f..00000000000 --- 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 a89c965e443..00000000000 --- 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 3e7e6ddae57..00000000000 --- 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 c53ca91a8b4..00000000000 --- 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 8ef9de2226d..00000000000 --- 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 4fd86e85483..00000000000 --- 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 1c3b79fa034..00000000000 --- 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] {RTLIL 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/YosysHQ/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{https://yosyshq.net/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 RTLIL 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_rtlil # read modules from RTLIL 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_rtlil # write design to RTLIL 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 C. 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{https://yosyshq.net/yosys/} - -\bigskip -\item Manual, Command Reference, Application Notes: \\ -\smallskip\hskip1cm\url{https://yosyshq.net/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/YosysHQ/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{https://yosyshq.net/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_Intro/.gitignore b/yosys/manual/PRESENTATION_Intro/.gitignore deleted file mode 100644 index d0c4618ac70..00000000000 --- 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 abc354e4691..00000000000 --- 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 36b878e3132..00000000000 --- 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 cc4e7cd3199..00000000000 --- 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 a0204d7e15e..00000000000 --- 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 802f58718bd..00000000000 --- 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 b0390cb9977..00000000000 --- a/yosys/manual/PRESENTATION_Prog.tex +++ /dev/null @@ -1,596 +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] {RTLIL 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 the 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 -$divfloor $modfloor $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{https://yosyshq.net/yosys/} -\end{center} -\end{frame} - diff --git a/yosys/manual/PRESENTATION_Prog/.gitignore b/yosys/manual/PRESENTATION_Prog/.gitignore deleted file mode 100644 index ccdd6bd5c68..00000000000 --- 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 2ac8e5bed9f..00000000000 --- a/yosys/manual/PRESENTATION_Prog/Makefile +++ /dev/null @@ -1,21 +0,0 @@ - -all: test0.log test1.log test2.log - -CXXFLAGS=$(shell ../../yosys-config --cxxflags) -DATDIR=$(shell ../../yosys-config --datdir) - -my_cmd.so: my_cmd.cc - ../../yosys-config --exec --cxx $(subst $(DATDIR),../../share,$(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 'hierarchy -top test; 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 ca0a115a0a7..00000000000 --- 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 9cb4b8e38b1..00000000000 --- 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) 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) 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) 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 18dcf5eb78e..00000000000 --- 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/clean.sh b/yosys/manual/clean.sh deleted file mode 100755 index addc34ed183..00000000000 --- 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/presentation.sh b/yosys/manual/presentation.sh deleted file mode 100755 index ca8a6c93c10..00000000000 --- a/yosys/manual/presentation.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash - -fast_mode=false - -set -- $(getopt fu "$@") -while [ $# -gt 0 ]; do - case "$1" in - -f) - fast_mode=true - ;; - --) - shift - break - ;; - -*) - echo "$0: error - unrecognized option $1" 1>&2 - exit 1 - ;; - *) - break - esac - shift -done - -PDFTEX_OPT="-shell-escape -halt-on-error" - -set -ex - -if ! $fast_mode; then - ! md5sum *.aux *.snm *.nav *.toc > autoloop.old - make -C PRESENTATION_Intro - make -C PRESENTATION_ExSyn - make -C PRESENTATION_ExAdv - make -C PRESENTATION_ExOth - make -C PRESENTATION_Prog -fi - -set -ex - -pdflatex $PDFTEX_OPT presentation.tex - -if ! $fast_mode; then - while - md5sum *.aux *.snm *.nav *.toc > autoloop.new - ! cmp autoloop.old autoloop.new - do - cp autoloop.new autoloop.old - pdflatex $PDFTEX_OPT presentation.tex - done - - rm -f autoloop.old - rm -f autoloop.new -fi - diff --git a/yosys/manual/presentation.tex b/yosys/manual/presentation.tex deleted file mode 100644 index 7aba33c8b31..00000000000 --- a/yosys/manual/presentation.tex +++ /dev/null @@ -1,162 +0,0 @@ -\documentclass{beamer} -\hypersetup{bookmarksdepth=5} - -\usepackage[T1]{fontenc} % required for luximono! -\usepackage{lmodern} -\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"). - -% formats the text according the set language -\usepackage[english]{babel} -\usepackage{amsmath} -\usepackage{multirow} -\usepackage{booktabs} -\usepackage{listings} -\usepackage{setspace} -\usepackage{skull} -\usepackage{units} - -\usepackage{tikz} -\usetikzlibrary{calc} -\usetikzlibrary{arrows} -\usetikzlibrary{scopes} -\usetikzlibrary{through} -\usetikzlibrary{shapes.geometric} - -\lstset{basicstyle=\ttfamily} - -\def\B#1{{\tt\textbackslash{}#1}} -\def\C#1{\lstinline[language=C++]{#1}} -\def\V#1{\lstinline[language=Verilog]{#1}} - -\lstdefinelanguage{liberty}{ - morecomment=[s]{/*}{*/}, - morekeywords={library,cell,area,pin,direction,function,clocked_on,next_state,clock,ff}, - morestring=[b]", -} - -\lstdefinelanguage{rtlil}{ - morecomment=[l]{\#}, - morekeywords={module,attribute,parameter,wire,memory,auto,width,offset,size,input,output,inout,cell,connect,switch,case,assign,sync,low,high,posedge,negedge,edge,always,update,process,end}, - morestring=[b]", -} - -\lstdefinelanguage{ys}{ - morecomment=[l]{\#}, -} - -\lstset{ - commentstyle=\color{YosysGreen}, -} - -\newenvironment{boxalertenv}{\begin{altenv}% -{\usebeamertemplate{alerted text begin}\usebeamercolor[fg]{alerted text}\usebeamerfont{alerted text}\setlength{\fboxsep}{1pt}\colorbox{bg}} -{\usebeamertemplate{alerted text end}}{\color{.}}{}}{\end{altenv}} - -\newcommand<>{\boxalert}[1]{{% -\begin{boxalertenv}#2{#1}\end{boxalertenv}% -}} - -\newcommand{\subsectionpagesuffix}{ -\vfill\begin{centering} -{\usebeamerfont{subsection name}\usebeamercolor[fg]{subsection name}of \sectionname~\insertsectionnumber} -\vskip1em\par -\setbeamercolor{graybox}{bg=gray} -\begin{beamercolorbox}[sep=8pt,center]{graybox} -\usebeamerfont{subsection title}\insertsection\par -\end{beamercolorbox} -\end{centering}} - -\title{Yosys Open SYnthesis Suite} -\author{Claire Xenia Wolf} -\institute{https://yosyshq.net/yosys/} - -\usetheme{Madrid} -\usecolortheme{seagull} -\beamertemplatenavigationsymbolsempty - -\definecolor{YosysGreen}{RGB}{85,136,102} -\definecolor{MyBlue}{RGB}{85,130,180} - -\setbeamercolor{title}{fg=black,bg=YosysGreen!70} -\setbeamercolor{titlelike}{fg=black,bg=YosysGreen!70} -\setbeamercolor{frametitle}{fg=black,bg=YosysGreen!70} -\setbeamercolor{block title}{fg=black,bg=YosysGreen!70} -\setbeamercolor{item projected}{fg=black,bg=YosysGreen} - -\begin{document} - -\begin{frame} -\titlepage -\end{frame} - -\setcounter{section}{-3} - -\section{Abstract} -\begin{frame}{Abstract} -Yosys is the first full-featured open source software for Verilog HDL -synthesis. It supports most of Verilog-2005 and is well tested with -real-world designs from the ASIC and FPGA world. - -\bigskip -Learn how to use Yosys to create your own custom synthesis flows and -discover why open source HDL synthesis is important for researchers, -hobbyists, educators and engineers alike. - -\bigskip -This presentation covers basic concepts of Yosys, writing synthesis scripts -for a wide range of applications, creating Yosys scripts for various -non-synthesis applications (such as formal equivalence checking) and -writing extensions to Yosys using the C++ API. -\end{frame} - -\section{About me} -\begin{frame}{About me} -Hi! I'm Claire Xenia Wolf. - -\bigskip -I like writing open source software. For example: -\begin{itemize} -\item Yosys -\item OpenSCAD (now maintained by Marius Kintel) -\item SPL (a not very popular scripting language) -\item EmbedVM (a very simple compiler+vm for 8 bit micros) -\item Lib(X)SVF (a library to play SVF/XSVF files over JTAG) -\item ROCK Linux (discontinued since 2010) -\end{itemize} -\end{frame} - -\section{Outline} -\begin{frame}{Outline} -Yosys is an Open Source Verilog synthesis tool, and more. - -\bigskip -Outline of this presentation: -\begin{itemize} -\item Introduction to the field and Yosys -\item Yosys by example: synthesis -\item Yosys by example: advanced synthesis -\item Yosys by example: beyond synthesis -\item Writing Yosys extensions in C++ -\end{itemize} -\end{frame} - -\include{PRESENTATION_Intro} -\include{PRESENTATION_ExSyn} -\include{PRESENTATION_ExAdv} -\include{PRESENTATION_ExOth} -\include{PRESENTATION_Prog} - -\end{document} diff --git a/yosys/misc/__init__.py b/yosys/misc/__init__.py deleted file mode 100644 index 330fd6d8634..00000000000 --- a/yosys/misc/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -import os -import sys -sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL) - -__all__ = ["libyosys"] diff --git a/yosys/misc/create_vcxsrc.sh b/yosys/misc/create_vcxsrc.sh deleted file mode 100644 index 8b39d59e30e..00000000000 --- a/yosys/misc/create_vcxsrc.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -set -ex -vcxsrc="$1-$2" -yosysver="$2" -gitsha="$3" - -rm -rf YosysVS-Tpl-v2.zip YosysVS -wget https://yosyshq.net/yosys/nogit/YosysVS-Tpl-v2.zip -wget https://www.zlib.net/fossils/zlib-1.2.11.tar.gz - -unzip YosysVS-Tpl-v2.zip -rm -f YosysVS-Tpl-v2.zip -tar xvfz zlib-1.2.11.tar.gz - -mv YosysVS "$vcxsrc" -mkdir -p "$vcxsrc"/yosys -mkdir -p "$vcxsrc"/yosys/libs/zlib -mv zlib-1.2.11/* "$vcxsrc"/yosys/libs/zlib/. -rm -rf zlib-1.2.11 -pushd "$vcxsrc"/yosys -ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' >> ../../srcfiles.txt -popd -{ - n=$(grep -B999 '' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l) - head -n$n "$vcxsrc"/YosysVS/YosysVS.vcxproj - egrep '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,,' - egrep -v '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,,' - echo '' - tail -n +$((n+1)) "$vcxsrc"/YosysVS/YosysVS.vcxproj -} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new - -mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj - -mkdir -p "$vcxsrc"/yosys -tar -cf - -T srcfiles.txt | tar -xf - -C "$vcxsrc"/yosys -cp -r share "$vcxsrc"/ - -echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys" \ - "$yosysver (git sha1 $gitsha, Visual Studio)\"; }" > "$vcxsrc"/yosys/kernel/version.cc - -cat > "$vcxsrc"/readme-git.txt << EOT -Want to use a git working copy for the yosys source code? -Open "Git Bash" in this directory and run: - - mv yosys yosys.bak - git clone https://github.com/YosysHQ/yosys.git yosys - cd yosys - git checkout -B master $(git rev-parse HEAD | cut -c1-10) - unzip ../genfiles.zip -EOT - -cat > "$vcxsrc"/readme-abc.txt << EOT -Yosys is using "ABC" for gate-level optimizations and technology -mapping. Download yosys-win32-mxebin-$yosysver.zip and copy the -following files from it into this directory: - - pthreadVC2.dll - yosys-abc.exe -EOT - -sed -i 's/$/\r/; s/\r\r*/\r/g;' "$vcxsrc"/YosysVS/YosysVS.vcxproj "$vcxsrc"/readme-git.txt "$vcxsrc"/readme-abc.txt - diff --git a/yosys/misc/jny.schema.json b/yosys/misc/jny.schema.json deleted file mode 100644 index 0fff8ee57d8..00000000000 --- a/yosys/misc/jny.schema.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json", - "title": "Yosys JSON Netlist metadata", - "description": "Yosys JSON Netlist", - "type": "object", - "properties": { - "generator": { - "type": "string", - "description": "JNY File Generator" - }, - "version": { - "type": "string", - "description": "JNY Version" - }, - "invocation": { - "type": "string", - "description": "Invocation line that generated the JNY metadata" - }, - "features": { - "type": "array", - "description": "What information is contained in the JNY file", - "items": { - "type": "string" - } - }, - "modules": { - "type": "array", - "items": { "$ref": "#/$defs/module" } - } - }, - "required": [ - "generator", - "version", - "invocation", - "features" - ], - "$defs": { - "module": { - "type": "object", - "description": "Module definition", - "properties": { - "name": { - "type": "string", - "description": "Module Name" - }, - "cell_sorts": { - "type": "array", - "description": "", - "items": { "$ref": "#/$defs/cell_sort" } - }, - "connections": { - "type": "array", - "description": "Cell connections", - "items": { "$ref": "#/$defs/connection" } - }, - "attributes": { - "type": "object", - "description": "Attributes attached to the module" - }, - "parameters": { - "type": "object", - "description": "Parameters attached to the module" - } - }, - "required": [ - "name", - "cell_sorts" - ] - }, - "cell_sort": { - "type": "object", - "description": "Describes a type of cell", - "properties": { - "type": { - "type": "string", - "description": "Type of cell" - }, - "ports": { - "type": "array", - "description": "Cell ports", - "items": { "$ref": "#/$defs/port" } - } - , - "cells": { - "type": "array", - "description": "Cells of cell_sort", - "items": { "$ref": "#/$defs/cell" } - } - }, - "required": [ - "type", - "ports", - "cells" - ] - }, - "connection": { - "type": "object", - "description": "A connection within a module or cell", - "properties": { - "name": { - "type": "string", - "description": "Connection name" - }, - "signals": { - "type": "array", - "description": "Signals that compose the connection", - "items": { "$ref": "#/$defs/signal" } - } - }, - "required": [ - "name", - "signals" - ] - }, - "port": { - "type": "object", - "description": "Cell port description", - "properties": { - "name": { - "type": "string", - "description": "Port name" - }, - "direction": { - "type": "string", - "description": "Port direction", - "enum": ["i", "o", "io", ""] - }, - "range": { - "type": "array", - "description": "Port width [MSB, LSB]", - "items": { - "type": "number" - }, - "minContains": 1, - "maxContains": 2 - } - }, - "required": [ - "name", - "direction", - "range" - ] - }, - "cell": { - "type": "object", - "description": "Module cell definition", - "properties": { - "name": { - "type": "string", - "description": "Cell name" - }, - "connections": { - "type": "array", - "description": "Cell connections", - "items": { "$ref": "#/$defs/connection" } - }, - "attributes": { - "type": "object", - "description": "Attributes attached to the cell" - }, - "parameters": { - "type": "object", - "description": "Parameters attached to the cell" - } - }, - "required": [ - "name" - ] - }, - "signal": { - "type": "object", - "description": "A signal definition", - "parameters": { - "width": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["wire", "chunk"] - }, - "const": { - "type": "boolean" - } - }, - "required": [ - "width", - "type", - "const" - ] - } - } -} diff --git a/yosys/misc/launcher.c b/yosys/misc/launcher.c deleted file mode 100644 index 49d6414e718..00000000000 --- a/yosys/misc/launcher.c +++ /dev/null @@ -1,359 +0,0 @@ -/* This file comes from the PyPA Setuptools repository, commit 16e452a: -https://github.com/pypa/setuptools -Modifications include this comment and inline inclusion of the LICENSE text. */ - -/* Copyright (C) 2016 Jason R Coombs - -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. */ - -/* Setuptools Script Launcher for Windows - - This is a stub executable for Windows that functions somewhat like - Effbot's "exemaker", in that it runs a script with the same name but - a .py extension, using information from a #! line. It differs in that - it spawns the actual Python executable, rather than attempting to - hook into the Python DLL. This means that the script will run with - sys.executable set to the Python executable, where exemaker ends up with - sys.executable pointing to itself. (Which means it won't work if you try - to run another Python process using sys.executable.) - - To build/rebuild with mingw32, do this in the setuptools project directory: - - gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c - gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c - - To build for Windows RT, install both Visual Studio Express for Windows 8 - and for Windows Desktop (both freeware), create "win32" application using - "Windows Desktop" version, create new "ARM" target via - "Configuration Manager" menu and modify ".vcxproj" file by adding - "true" tag - as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM" - properties. - - It links to msvcrt.dll, but this shouldn't be a problem since it doesn't - actually run Python in the same process. Note that using 'exec' instead - of 'spawn' doesn't work, because on Windows this leads to the Python - executable running in the *background*, attached to the same console - window, meaning you get a command prompt back *before* Python even finishes - starting. So, we have to use spawnv() and wait for Python to exit before - continuing. :( -*/ - -#include -#include -#include -#include -#include -#include -#include - -int child_pid=0; - -int fail(const char *format, const char *data) { - /* Print error message to stderr and return 2 */ - fprintf(stderr, format, data); - return 2; -} - -char *quoted(char *data) { - int i, ln = strlen(data), nb; - - /* We allocate twice as much space as needed to deal with worse-case - of having to escape everything. */ - char *result = (char *)calloc(ln*2+3, sizeof(char)); - char *presult = result; - - *presult++ = '"'; - for (nb=0, i=0; i < ln; i++) - { - if (data[i] == '\\') - nb += 1; - else if (data[i] == '"') - { - for (; nb > 0; nb--) - *presult++ = '\\'; - *presult++ = '\\'; - } - else - nb = 0; - *presult++ = data[i]; - } - - for (; nb > 0; nb--) /* Deal w trailing slashes */ - *presult++ = '\\'; - - *presult++ = '"'; - *presult++ = 0; - return result; -} - - - - - - - - - - -char *loadable_exe(char *exename) { - /* HINSTANCE hPython; DLL handle for python executable */ - char *result; - - /* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (!hPython) return NULL; */ - - /* Return the absolute filename for spawnv */ - result = (char *)calloc(MAX_PATH, sizeof(char)); - strncpy(result, exename, MAX_PATH); - /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH); - - FreeLibrary(hPython); */ - return result; -} - - -char *find_exe(char *exename, char *script) { - char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT]; - char path[_MAX_PATH], c, *result; - - /* convert slashes to backslashes for uniform search below */ - result = exename; - while (c = *result++) if (c=='/') result[-1] = '\\'; - - _splitpath(exename, drive, dir, fname, ext); - if (drive[0] || dir[0]=='\\') { - return loadable_exe(exename); /* absolute path, use directly */ - } - /* Use the script's parent directory, which should be the Python home - (This should only be used for bdist_wininst-installed scripts, because - easy_install-ed scripts use the absolute path to python[w].exe - */ - _splitpath(script, drive, dir, fname, ext); - result = dir + strlen(dir) -1; - if (*result == '\\') result--; - while (*result != '\\' && result>=dir) *result-- = 0; - _makepath(path, drive, dir, exename, NULL); - return loadable_exe(path); -} - - -char **parse_argv(char *cmdline, int *argc) -{ - /* Parse a command line in-place using MS C rules */ - - char **result = (char **)calloc(strlen(cmdline), sizeof(char *)); - char *output = cmdline; - char c; - int nb = 0; - int iq = 0; - *argc = 0; - - result[0] = output; - while (isspace(*cmdline)) cmdline++; /* skip leading spaces */ - - do { - c = *cmdline++; - if (!c || (isspace(c) && !iq)) { - while (nb) {*output++ = '\\'; nb--; } - *output++ = 0; - result[++*argc] = output; - if (!c) return result; - while (isspace(*cmdline)) cmdline++; /* skip leading spaces */ - if (!*cmdline) return result; /* avoid empty arg if trailing ws */ - continue; - } - if (c == '\\') - ++nb; /* count \'s */ - else { - if (c == '"') { - if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */ - nb = nb >> 1; /* cut \'s in half */ - } - while (nb) {*output++ = '\\'; nb--; } - if (c) *output++ = c; - } - } while (1); -} - -void pass_control_to_child(DWORD control_type) { - /* - * distribute-issue207 - * passes the control event to child process (Python) - */ - if (!child_pid) { - return; - } - GenerateConsoleCtrlEvent(child_pid,0); -} - -BOOL control_handler(DWORD control_type) { - /* - * distribute-issue207 - * control event handler callback function - */ - switch (control_type) { - case CTRL_C_EVENT: - pass_control_to_child(0); - break; - } - return TRUE; -} - -int create_and_wait_for_subprocess(char* command) { - /* - * distribute-issue207 - * launches child process (Python) - */ - DWORD return_value = 0; - LPSTR commandline = command; - STARTUPINFOA s_info; - PROCESS_INFORMATION p_info; - ZeroMemory(&p_info, sizeof(p_info)); - ZeroMemory(&s_info, sizeof(s_info)); - s_info.cb = sizeof(STARTUPINFO); - // set-up control handler callback funciotn - SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE); - if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) { - fprintf(stderr, "failed to create process.\n"); - return 0; - } - child_pid = p_info.dwProcessId; - // wait for Python to exit - WaitForSingleObject(p_info.hProcess, INFINITE); - if (!GetExitCodeProcess(p_info.hProcess, &return_value)) { - fprintf(stderr, "failed to get exit code from process.\n"); - return 0; - } - return return_value; -} - -char* join_executable_and_args(char *executable, char **args, int argc) -{ - /* - * distribute-issue207 - * CreateProcess needs a long string of the executable and command-line arguments, - * so we need to convert it from the args that was built - */ - int len,counter; - char* cmdline; - - len=strlen(executable)+2; - for (counter=1; counterscript && *end != '.') - *end-- = '\0'; - *end-- = '\0'; - strcat(script, (GUI ? "-script.pyw" : "-script.py")); - - /* figure out the target python executable */ - - scriptf = open(script, O_RDONLY); - if (scriptf == -1) { - return fail("Cannot open %s\n", script); - } - end = python + read(scriptf, python, sizeof(python)); - close(scriptf); - - ptr = python-1; - while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;} - - *ptr-- = '\0'; - - if (strncmp(python, "#!", 2)) { - /* default to python.exe if no #! header */ - strcpy(python, "#!python.exe"); - } - - parsedargs = parse_argv(python+2, &parsedargc); - - /* Using spawnv() can fail strangely if you e.g. find the Cygwin - Python, so we'll make sure Windows can find and load it */ - - ptr = find_exe(parsedargs[0], script); - if (!ptr) { - return fail("Cannot find Python executable %s\n", parsedargs[0]); - } - - /* printf("Python executable: %s\n", ptr); */ - - /* Argument array needs to be - parsedargc + argc, plus 1 for null sentinel */ - - newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *)); - newargsp = newargs; - - *newargsp++ = quoted(ptr); - for (i = 1; i -# -# 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. -# -# Author Benedikt Tutzer -# - -import copy - -#Map c++ operator Syntax to Python functions -wrappable_operators = { - "<" : "__lt__", - "==": "__eq__", - "!=": "__ne__", - "+" : "__add__", - "-" : "__sub__", - "*" : "__mul__", - "/" : "__div__", - "()": "__call__" - } - -#Restrict certain strings from being function names in Python -keyword_aliases = { - "in" : "in_", - "False" : "False_", - "None" : "None_", - "True" : "True_", - "and" : "and_", - "as" : "as_", - "assert" : "assert_", - "break" : "break_", - "class" : "class_", - "continue" : "continue_", - "def" : "def_", - "del" : "del_", - "elif" : "elif_", - "else" : "else_", - "except" : "except_", - "for" : "for_", - "from" : "from_", - "global" : "global_", - "if" : "if_", - "import" : "import_", - "in" : "in_", - "is" : "is_", - "lambda" : "lambda_", - "nonlocal" : "nonlocal_", - "not" : "not_", - "or" : "or_", - "pass" : "pass_", - "raise" : "raise_", - "return" : "return_", - "try" : "try_", - "while" : "while_", - "with" : "with_", - "yield" : "yield_" - } - -#These can be used without any explicit conversion -primitive_types = ["void", "bool", "int", "double", "size_t", "std::string", - "string", "State", "char_p"] - -from enum import Enum - -#Ways to link between Python- and C++ Objects -class link_types(Enum): - global_list = 1 #Manage a global list of objects in C++, the Python - #object contains a key to find the corresponding C++ - #object and a Pointer to the object to verify it is - #still the same, making collisions unlikely to happen - ref_copy = 2 #The Python object contains a copy of the C++ object. - #The C++ object is deleted when the Python object gets - #deleted - pointer = 3 #The Python Object contains a pointer to it's C++ - #counterpart - derive = 4 #The Python-Wrapper is derived from the C++ object. - -class attr_types(Enum): - star = "*" - amp = "&" - ampamp = "&&" - default = "" - -#For source-files -class Source: - name = "" - classes = [] - - def __init__(self, name, classes): - self.name = name - self.classes = classes - -#Splits a list by the given delimiter, without splitting strings inside -#pointy-brackets (< and >) -def split_list(str_def, delim): - str_def = str_def.strip() - if len(str_def) == 0: - return [] - if str_def.count(delim) == 0: - return [str_def] - if str_def.count("<") == 0: - return str_def.split(delim) - if str_def.find("<") < str_def.find(" "): - closing = find_closing(str_def[str_def.find("<")+1:], "<", ">") + str_def.find("<") - comma = str_def[closing:].find(delim) - if comma == -1: - return [str_def] - comma = closing + comma - else: - comma = str_def.find(delim) - rest = split_list(str_def[comma+1:], delim) - ret = [str_def[:comma]] - if rest != None and len(rest) != 0: - ret.extend(rest) - return ret - -#Represents a Type -class WType: - name = "" - cont = None - attr_type = attr_types.default - - def __init__(self, name = "", cont = None, attr_type = attr_types.default): - self.name = name - self.cont = cont - self.attr_type = attr_type - - #Python type-string - def gen_text(self): - text = self.name - if self.name in enum_names: - text = enum_by_name(self.name).namespace + "::" + self.name - if self.cont != None: - return known_containers[self.name].typename - return text - - #C++ type-string - def gen_text_cpp(self): - postfix = "" - if self.attr_type == attr_types.star: - postfix = "*" - if self.name in primitive_types: - return self.name + postfix - if self.name in enum_names: - return enum_by_name(self.name).namespace + "::" + self.name + postfix - if self.name in classnames: - return class_by_name(self.name).namespace + "::" + self.name + postfix - text = self.name - if self.cont != None: - text += "<" - for a in self.cont.args: - text += a.gen_text_cpp() + ", " - text = text[:-2] - text += ">" - return text - - @staticmethod - def from_string(str_def, containing_file, line_number): - str_def = str_def.strip() - if len(str_def) == 0: - return None - str_def = str_def.replace("RTLIL::SigSig", "std::pair").replace("SigSig", "std::pair") - t = WType() - t.name = "" - t.cont = None - t.attr_type = attr_types.default - if str_def.find("<") != -1:# and str_def.find("<") < str_def.find(" "): - candidate = WContainer.from_string(str_def, containing_file, line_number) - if candidate == None: - return None - t.name = str_def[:str_def.find("<")] - - if t.name.count("*") + t.name.count("&") > 1: - return None - - if t.name.count("*") == 1 or str_def[0] == '*' or str_def[-1] == '*': - t.attr_type = attr_types.star - t.name = t.name.replace("*","") - elif t.name.count("&&") == 1: - t.attr_type = attr_types.ampamp - t.name = t.name.replace("&&","") - elif t.name.count("&") == 1 or str_def[0] == '&' or str_def[-1] == '&': - t.attr_type = attr_types.amp - t.name = t.name.replace("&","") - - t.cont = candidate - if(t.name not in known_containers): - return None - return t - - prefix = "" - - if str.startswith(str_def, "unsigned "): - prefix = "unsigned " - str_def = str_def[9:] - while str.startswith(str_def, "long "): - prefix= "long " + prefix - str_def = str_def[5:] - while str.startswith(str_def, "short "): - prefix = "short " + prefix - str_def = str_def[6:] - - str_def = str_def.split("::")[-1] - - if str_def.count("*") + str_def.count("&") >= 2: - return None - - if str_def.count("*") == 1: - t.attr_type = attr_types.star - str_def = str_def.replace("*","") - elif str_def.count("&&") == 1: - t.attr_type = attr_types.ampamp - str_def = str_def.replace("&&","") - elif str_def.count("&") == 1: - t.attr_type = attr_types.amp - str_def = str_def.replace("&","") - - if len(str_def) > 0 and str_def.split("::")[-1] not in primitive_types and str_def.split("::")[-1] not in classnames and str_def.split("::")[-1] not in enum_names: - return None - - if str_def.count(" ") == 0: - t.name = (prefix + str_def).replace("char_p", "char *") - t.cont = None - return t - return None - -#Represents a container-type -class WContainer: - name = "" - args = [] - - def from_string(str_def, containing_file, line_number): - if str_def == None or len(str_def) < 4: - return None - cont = WContainer() - cont.name = str_def[:str_def.find("<")] - str_def = str_def[str_def.find("<")+1:find_closing(str_def, "<", ">")] - cont.args = [] - for arg in split_list(str_def, ","): - candidate = WType.from_string(arg.strip(), containing_file, line_number) - if candidate == None: - return None - if candidate.name == "void": - return None - cont.args.append(candidate) - return cont - -#Translators between Python and C++ containers -#Base Type -class Translator: - tmp_cntr = 0 - typename = "DefaultType" - orig_name = "DefaultCpp" - - @classmethod - def gen_type(c, types): - return "\nImplement a function that outputs the c++ type of this container here\n" - - @classmethod - def translate(c, varname, types, prefix): - return "\nImplement a function translating a python container to a c++ container here\n" - - @classmethod - def translate_cpp(c, varname, types, prefix, ref): - return "\nImplement a function translating a c++ container to a python container here\n" - -#Translates list-types (vector, pool, set), that only differ in their name and -#the name of the insertion function -class PythonListTranslator(Translator): - typename = "boost::python::list" - insert_name = "Default" - - #generate the c++ type string - @classmethod - def gen_type(c, types): - text = c.orig_name + "<" - if types[0].name in primitive_types: - text += types[0].name - elif types[0].name in known_containers: - text += known_containers[types[0].name].gen_type(types[0].cont.args) - else: - text += class_by_name(types[0].name).namespace + "::" + types[0].name - if types[0].attr_type == attr_types.star: - text += "*" - text += ">" - return text - - #Generate C++ code to translate from a boost::python::list - @classmethod - def translate(c, varname, types, prefix): - text = prefix + c.gen_type(types) + " " + varname + "___tmp;" - cntr_name = "cntr_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "); " + cntr_name + "++)" - text += prefix + "{" - tmp_name = "tmp_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - if types[0].name in known_containers: - text += prefix + "\t" + known_containers[types[0].name].typename + " " + tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "[" + cntr_name + "]);" - text += known_containers[types[0].name].translate(tmp_name, types[0].cont.args, prefix+"\t") - tmp_name = tmp_name + "___tmp" - text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + ");" - elif types[0].name in classnames: - text += prefix + "\t" + types[0].name + "* " + tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "[" + cntr_name + "]);" - if types[0].attr_type == attr_types.star: - text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + "->get_cpp_obj());" - else: - text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(*" + tmp_name + "->get_cpp_obj());" - else: - text += prefix + "\t" + types[0].name + " " + tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "[" + cntr_name + "]);" - text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + ");" - text += prefix + "}" - return text - - #Generate C++ code to translate to a boost::python::list - @classmethod - def translate_cpp(c, varname, types, prefix, ref): - text = prefix + c.typename + " " + varname + "___tmp;" - tmp_name = "tmp_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - if ref: - text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" - else: - text += prefix + "for(auto " + tmp_name + " : " + varname + ")" - text += prefix + "{" - if types[0].name in classnames: - if types[0].attr_type == attr_types.star: - text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));" - else: - text += prefix + "\t" + varname + "___tmp.append(*" + types[0].name + "::get_py_obj(&" + tmp_name + "));" - elif types[0].name in known_containers: - text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[0].attr_type == attr_types.star) - text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + "___tmp);" - else: - text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");" - text += prefix + "}" - return text - -class IDictTranslator(PythonListTranslator): - typename = "boost::python::list" - orig_name = "idict" - insert_name = "" - -#Sub-type for std::set -class SetTranslator(PythonListTranslator): - insert_name = ".insert" - orig_name = "std::set" - -#Sub-type for std::vector -class VectorTranslator(PythonListTranslator): - insert_name = ".push_back" - orig_name = "std::vector" - -#Sub-type for pool -class PoolTranslator(PythonListTranslator): - insert_name = ".insert" - orig_name = "pool" - -#Translates dict-types (dict, std::map), that only differ in their name and -#the name of the insertion function -class PythonDictTranslator(Translator): - typename = "boost::python::dict" - insert_name = "Default" - - @classmethod - def gen_type(c, types): - text = c.orig_name + "<" - if types[0].name in primitive_types: - text += types[0].name - elif types[0].name in known_containers: - text += known_containers[types[0].name].gen_type(types[0].cont.args) - else: - text += class_by_name(types[0].name).namespace + "::" + types[0].name - if types[0].attr_type == attr_types.star: - text += "*" - text += ", " - if types[1].name in primitive_types: - text += types[1].name - elif types[1].name in known_containers: - text += known_containers[types[1].name].gen_type(types[1].cont.args) - else: - text += class_by_name(types[1].name).namespace + "::" + types[1].name - if types[1].attr_type == attr_types.star: - text += "*" - text += ">" - return text - - #Generate c++ code to translate from a boost::python::dict - @classmethod - def translate(c, varname, types, prefix): - text = prefix + c.gen_type(types) + " " + varname + "___tmp;" - text += prefix + "boost::python::list " + varname + "_keylist = " + varname + ".keys();" - cntr_name = "cntr_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "_keylist); " + cntr_name + "++)" - text += prefix + "{" - key_tmp_name = "key_tmp_" + str(Translator.tmp_cntr) - val_tmp_name = "val_tmp_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - - if types[0].name in known_containers: - text += prefix + "\t" + known_containers[types[0].name].typename + " " + key_tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "_keylist[ " + cntr_name + " ]);" - text += known_containers[types[0].name].translate(key_tmp_name, types[0].cont.args, prefix+"\t") - key_tmp_name = key_tmp_name + "___tmp" - elif types[0].name in classnames: - text += prefix + "\t" + types[0].name + "* " + key_tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "_keylist[ " + cntr_name + " ]);" - else: - text += prefix + "\t" + types[0].name + " " + key_tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "_keylist[ " + cntr_name + " ]);" - - if types[1].name in known_containers: - text += prefix + "\t" + known_containers[types[1].name].typename + " " + val_tmp_name + " = boost::python::extract<" + known_containers[types[1].name].typename + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" - text += known_containers[types[1].name].translate(val_tmp_name, types[1].cont.args, prefix+"\t") - val_tmp_name = val_tmp_name + "___tmp" - elif types[1].name in classnames: - text += prefix + "\t" + types[1].name + "* " + val_tmp_name + " = boost::python::extract<" + types[1].name + "*>(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" - else: - text += prefix + "\t" + types[1].name + " " + val_tmp_name + " = boost::python::extract<" + types[1].name + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" - - text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(std::pair<" + types[0].gen_text_cpp() + ", " + types[1].gen_text_cpp() + ">(" - - if types[0].name not in classnames: - text += key_tmp_name - else: - if types[0].attr_type != attr_types.star: - text += "*" - text += key_tmp_name + "->get_cpp_obj()" - - text += ", " - if types[1].name not in classnames: - text += val_tmp_name - else: - if types[1].attr_type != attr_types.star: - text += "*" - text += val_tmp_name + "->get_cpp_obj()" - text += "));\n" + prefix + "}" - return text - - #Generate c++ code to translate to a boost::python::dict - @classmethod - def translate_cpp(c, varname, types, prefix, ref): - text = prefix + c.typename + " " + varname + "___tmp;" - tmp_name = "tmp_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - if ref: - text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" - else: - text += prefix + "for(auto " + tmp_name + " : " + varname + ")" - text += prefix + "{" - if types[1].name in known_containers: - text += prefix + "\tauto " + tmp_name + "_second = " + tmp_name + ".second;" - text += known_containers[types[1].name].translate_cpp(tmp_name + "_second", types[1].cont.args, prefix + "\t", types[1].attr_type == attr_types.star) - - if types[0].name in classnames: - text += prefix + "\t" + varname + "___tmp[" + types[0].name + "::get_py_obj(" + tmp_name + ".first)] = " - elif types[0].name not in known_containers: - text += prefix + "\t" + varname + "___tmp[" + tmp_name + ".first] = " - - if types[1].name in classnames: - if types[1].attr_type == attr_types.star: - text += types[1].name + "::get_py_obj(" + tmp_name + ".second);" - else: - text += "*" + types[1].name + "::get_py_obj(&" + tmp_name + ".second);" - elif types[1].name in known_containers: - text += tmp_name + "_second___tmp;" - else: - text += tmp_name + ".second;" - text += prefix + "}" - return text - -#Sub-type for dict -class DictTranslator(PythonDictTranslator): - insert_name = "insert" - orig_name = "dict" - -#Sub_type for std::map -class MapTranslator(PythonDictTranslator): - insert_name = "insert" - orig_name = "std::map" - -#Translator for std::pair. Derived from PythonDictTranslator because the -#gen_type function is the same (because both have two template parameters) -class TupleTranslator(PythonDictTranslator): - typename = "boost::python::tuple" - orig_name = "std::pair" - - #Generate c++ code to translate from a boost::python::tuple - @classmethod - def translate(c, varname, types, prefix): - text = prefix + types[0].name + " " + varname + "___tmp_0 = boost::python::extract<" + types[0].name + ">(" + varname + "[0]);" - text += prefix + types[1].name + " " + varname + "___tmp_1 = boost::python::extract<" + types[1].name + ">(" + varname + "[1]);" - text += prefix + TupleTranslator.gen_type(types) + " " + varname + "___tmp(" - if types[0].name.split(" ")[-1] in primitive_types: - text += varname + "___tmp_0, " - else: - text += varname + "___tmp_0.get_cpp_obj(), " - if types[1].name.split(" ")[-1] in primitive_types: - text += varname + "___tmp_1);" - else: - text += varname + "___tmp_1.get_cpp_obj());" - return text - - #Generate c++ code to translate to a boost::python::tuple - @classmethod - def translate_cpp(c, varname, types, prefix, ref): - # if the tuple is a pair of SigSpecs (aka SigSig), then we need - # to call get_py_obj() on each item in the tuple - if types[0].name in classnames: - first_var = types[0].name + "::get_py_obj(" + varname + ".first)" - else: - first_var = varname + ".first" - if types[1].name in classnames: - second_var = types[1].name + "::get_py_obj(" + varname + ".second)" - else: - second_var = varname + ".second" - text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + first_var + ", " + second_var + ");" - return text - -#Associate the Translators with their c++ type -known_containers = { - "std::set" : SetTranslator, - "std::vector" : VectorTranslator, - "pool" : PoolTranslator, - "idict" : IDictTranslator, - "dict" : DictTranslator, - "std::pair" : TupleTranslator, - "std::map" : MapTranslator -} - -class Attribute: - wtype = None - varname = None - is_const = False - default_value = None - pos = None - pos_counter = 0 - - def __init__(self, wtype, varname, is_const = False, default_value = None): - self.wtype = wtype - self.varname = varname - self.is_const = is_const - self.default_value = None - self.container = None - - @staticmethod - def from_string(str_def, containing_file, line_number): - if len(str_def) < 3: - return None - orig = str_def - arg = Attribute(None, None) - prefix = "" - arg.wtype = None - arg.varname = None - arg.is_const = False - arg.default_value = None - arg.container = None - if str.startswith(str_def, "const "): - arg.is_const = True - str_def = str_def[6:] - if str.startswith(str_def, "unsigned "): - prefix = "unsigned " - str_def = str_def[9:] - while str.startswith(str_def, "long "): - prefix= "long " + prefix - str_def = str_def[5:] - while str.startswith(str_def, "short "): - prefix = "short " + prefix - str_def = str_def[6:] - - if str_def.find("<") != -1 and str_def.find("<") < str_def.find(" "): - closing = find_closing(str_def[str_def.find("<"):], "<", ">") + str_def.find("<") + 1 - arg.wtype = WType.from_string(str_def[:closing].strip(), containing_file, line_number) - str_def = str_def[closing+1:] - else: - if str_def.count(" ") > 0: - arg.wtype = WType.from_string(prefix + str_def[:str_def.find(" ")].strip(), containing_file, line_number) - str_def = str_def[str_def.find(" ")+1:] - else: - arg.wtype = WType.from_string(prefix + str_def.strip(), containing_file, line_number) - str_def = "" - arg.varname = "" - - if arg.wtype == None: - return None - if str_def.count("=") == 0: - arg.varname = str_def.strip() - if arg.varname.find(" ") > 0: - return None - else: - arg.varname = str_def[:str_def.find("=")].strip() - if arg.varname.find(" ") > 0: - return None - str_def = str_def[str_def.find("=")+1:].strip() - arg.default_value = str_def[arg.varname.find("=")+1:].strip() - if len(arg.varname) == 0: - arg.varname = None - return arg - if arg.varname[0] == '*': - arg.wtype.attr_type = attr_types.star - arg.varname = arg.varname[1:] - elif arg.varname[0] == '&': - if arg.wtype.attr_type != attr_types.default: - return None - if arg.varname[1] == '&': - arg.wtype.attr_type = attr_types.ampamp - arg.varname = arg.varname[2:] - else: - arg.wtype.attr_type = attr_types.amp - arg.varname = arg.varname[1:] - return arg - - #Generates the varname. If the attribute has no name in the header file, - #a name is generated - def gen_varname(self): - if self.varname != None: - return self.varname - if self.wtype.name == "void": - return "" - if self.pos == None: - self.pos = Attribute.pos_counter - Attribute.pos_counter = Attribute.pos_counter + 1 - return "gen_varname_" + str(self.pos) - - #Generates the text for the function headers with wrapper types - def gen_listitem(self): - prefix = "" - if self.is_const: - prefix = "const " - if self.wtype.name in classnames: - return prefix + self.wtype.name + "* " + self.gen_varname() - if self.wtype.name in known_containers: - return prefix + known_containers[self.wtype.name].typename + " " + self.gen_varname() - return prefix + self.wtype.name + " " + self.gen_varname() - - #Generates the test for the function headers with c++ types - def gen_listitem_cpp(self): - prefix = "" - if self.is_const: - prefix = "const " - infix = "" - if self.wtype.attr_type == attr_types.star: - infix = "*" - elif self.wtype.attr_type == attr_types.amp: - infix = "&" - elif self.wtype.attr_type == attr_types.ampamp: - infix = "&&" - if self.wtype.name in known_containers: - return prefix + known_containers[self.wtype.name].gen_type(self.wtype.cont.args) + " " + infix + self.gen_varname() - if self.wtype.name in classnames: - return prefix + class_by_name(self.wtype.name).namespace + "::" + self.wtype.name + " " + infix + self.gen_varname() - return prefix + self.wtype.name + " " + infix + self.gen_varname() - - #Generates the listitem withtout the varname, so the signature can be - #compared - def gen_listitem_hash(self): - prefix = "" - if self.is_const: - prefix = "const " - if self.wtype.name in classnames: - return prefix + self.wtype.name + "* " - if self.wtype.name in known_containers: - return known_containers[self.wtype.name].typename - return prefix + self.wtype.name - - #Generate Translation code for the attribute - def gen_translation(self): - if self.wtype.name in known_containers: - return known_containers[self.wtype.name].translate(self.gen_varname(), self.wtype.cont.args, "\n\t\t") - return "" - - #Generate Translation code from c++ for the attribute - def gen_translation_cpp(self): - if self.wtype.name in known_containers: - return known_containers[self.wtype.name].translate_cpp(self.gen_varname(), self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) - return "" - - #Generate Text for the call - def gen_call(self): - ret = self.gen_varname() - if self.wtype.name in known_containers: - if self.wtype.attr_type == attr_types.star: - return "&" + ret + "___tmp" - return ret + "___tmp" - if self.wtype.name in classnames: - if self.wtype.attr_type != attr_types.star: - ret = "*" + ret - return ret + "->get_cpp_obj()" - if self.wtype.name == "char *" and self.gen_varname() in ["format", "fmt"]: - return "\"%s\", " + self.gen_varname() - if self.wtype.attr_type == attr_types.star: - return "&" + ret - return ret - - def gen_call_cpp(self): - ret = self.gen_varname() - if self.wtype.name.split(" ")[-1] in primitive_types or self.wtype.name in enum_names: - if self.wtype.attr_type == attr_types.star: - return "&" + ret - return ret - if self.wtype.name not in classnames: - if self.wtype.attr_type == attr_types.star: - return "&" + ret + "___tmp" - return ret + "___tmp" - if self.wtype.attr_type != attr_types.star: - ret = "*" + ret - return self.wtype.name + "::get_py_obj(" + self.gen_varname() + ")" - - #Generate cleanup code - def gen_cleanup(self): - if self.wtype.name in primitive_types or self.wtype.name in classnames or self.wtype.name in enum_names or not self.wtype.attr_type == attr_types.star or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): - return "" - return "\n\t\tdelete " + self.gen_varname() + "___tmp;" - -class WClass: - name = None - namespace = None - link_type = None - base_class = None - id_ = None - string_id = None - hash_id = None - needs_clone = False - found_funs = [] - found_vars = [] - found_constrs = [] - - def __init__(self, name, link_type, id_, string_id = None, hash_id = None, needs_clone = False): - self.name = name - self.namespace = None - self.base_class = None - self.link_type = link_type - self.id_ = id_ - self.string_id = string_id - self.hash_id = hash_id - self.needs_clone = needs_clone - self.found_funs = [] - self.found_vars = [] - self.found_constrs = [] - - def printable_constrs(self): - ret = 0 - for con in self.found_constrs: - if not con.protected: - ret += 1 - return ret - - def gen_decl(self, filename): - long_name = self.namespace + "::" + self.name - - text = "\n\t// WRAPPED from " + filename - text += "\n\tstruct " + self.name - if self.link_type == link_types.derive: - text += " : public " + self.namespace + "::" + self.name - text += "\n\t{\n" - - if self.link_type != link_types.derive: - - text += "\t\t" + long_name + "* ref_obj;\n" - - if self.link_type == link_types.ref_copy or self.link_type == link_types.pointer: - text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn ref_obj;\n\t\t}\n" - elif self.link_type == link_types.global_list: - text += "\t\t" + self.id_.wtype.name + " " + self.id_.varname + ";\n" - text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{" - text += "\n\t\t\t" + long_name + "* ret = " + long_name + "::get_all_" + self.name.lower() + "s()->at(this->" + self.id_.varname + ");" - text += "\n\t\t\tif(ret != NULL && ret == this->ref_obj)" - text += "\n\t\t\t\treturn ret;" - text += "\n\t\t\tthrow std::runtime_error(\"" + self.name + "'s c++ object does not exist anymore.\");" - text += "\n\t\t\treturn NULL;" - text += "\n\t\t}\n" - - #if self.link_type != link_types.pointer: - text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" - text += "\n\t\t\tif(ref == nullptr){" - text += "\n\t\t\t\tthrow std::runtime_error(\"" + self.name + " does not exist.\");" - text += "\n\t\t\t}" - text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" - if self.link_type == link_types.pointer: - text += "\n\t\t\tret->ref_obj = ref;" - if self.link_type == link_types.ref_copy: - if self.needs_clone: - text += "\n\t\t\tret->ref_obj = ref->clone();" - else: - text += "\n\t\t\tret->ref_obj = new "+long_name+"(*ref);" - if self.link_type == link_types.global_list: - text += "\n\t\t\tret->ref_obj = ref;" - text += "\n\t\t\tret->" + self.id_.varname + " = ret->ref_obj->" + self.id_.varname + ";" - text += "\n\t\t\treturn ret;" - text += "\n\t\t}\n" - - if self.link_type == link_types.ref_copy: - text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + " ref)\n\t\t{" - text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" - if self.needs_clone: - text += "\n\t\t\tret->ref_obj = ref.clone();" - else: - text += "\n\t\t\tret->ref_obj = new "+long_name+"(ref);" - text += "\n\t\t\treturn ret;" - text += "\n\t\t}\n" - - for con in self.found_constrs: - text += con.gen_decl() - if self.base_class is not None: - text += "\n\t\tvirtual ~" + self.name + "() { };" - for var in self.found_vars: - text += var.gen_decl() - for fun in self.found_funs: - text += fun.gen_decl() - - - if self.link_type == link_types.derive: - duplicates = {} - for fun in self.found_funs: - if fun.name in duplicates: - fun.gen_alias() - duplicates[fun.name].gen_alias() - else: - duplicates[fun.name] = fun - - text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn (" + self.namespace + "::" + self.name +"*)this;\n\t\t}\n" - text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" - text += "\n\t\t\treturn (" + self.name + "*)ref;" - text += "\n\t\t}\n" - - for con in self.found_constrs: - text += con.gen_decl_derive() - for var in self.found_vars: - text += var.gen_decl() - for fun in self.found_funs: - text += fun.gen_decl_virtual() - - if self.hash_id != None: - text += "\n\t\tunsigned int get_hash_py()" - text += "\n\t\t{" - text += "\n\t\t\treturn get_cpp_obj()->" + self.hash_id + ";" - text += "\n\t\t}" - - text += "\n\t};\n" - - if self.link_type == link_types.derive: - text += "\n\tstruct " + self.name + "Wrap : " + self.name + ", boost::python::wrapper<" + self.name + ">" - text += "\n\t{" - - for con in self.found_constrs: - text += con.gen_decl_wrapperclass() - for fun in self.found_funs: - text += fun.gen_default_impl() - - text += "\n\t};" - - text += "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self.name + " &ref)" - text += "\n\t{" - text += "\n\t\tostr << \"" + self.name - if self.string_id != None: - text +=" \\\"\"" - text += " << ref.get_cpp_obj()->" + self.string_id - text += " << \"\\\"\"" - else: - text += " at \" << ref.get_cpp_obj()" - text += ";" - text += "\n\t\treturn ostr;" - text += "\n\t}" - text += "\n" - - return text - - def gen_funs(self, filename): - text = "" - if self.link_type != link_types.derive: - for con in self.found_constrs: - text += con.gen_def() - for var in self.found_vars: - text += var.gen_def() - for fun in self.found_funs: - text += fun.gen_def() - else: - for var in self.found_vars: - text += var.gen_def() - for fun in self.found_funs: - text += fun.gen_def_virtual() - return text - - def gen_boost_py_body(self): - text = "" - if self.printable_constrs() == 0 or not self.contains_default_constr(): - text += ", no_init" - text += ")" - text += "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))" - text += "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))" - for con in self.found_constrs: - text += con.gen_boost_py() - for var in self.found_vars: - text += var.gen_boost_py() - static_funs = [] - for fun in self.found_funs: - text += fun.gen_boost_py() - if fun.is_static and fun.alias not in static_funs: - static_funs.append(fun.alias) - for fun in static_funs: - text += "\n\t\t\t.staticmethod(\"" + fun + "\")" - - if self.hash_id != None: - text += "\n\t\t\t.def(\"__hash__\", &" + self.name + "::get_hash_py)" - text += "\n\t\t\t;\n" - return text - - def gen_boost_py(self): - body = self.gen_boost_py_body() - base_info = "" - if self.base_class is not None: - base_info = ", bases<" + (self.base_class.name) + ">" - - if self.link_type == link_types.derive: - text = "\n\t\tclass_<" + self.name + base_info + ">(\"Cpp" + self.name + "\"" - text += body - text += "\n\t\tclass_<" + self.name - text += "Wrap, boost::noncopyable" - text += ">(\"" + self.name + "\"" - text += body - else: - text = "\n\t\tclass_<" + self.name + base_info + ">(\"" + self.name + "\"" - text += body - return text - - - def contains_default_constr(self): - for c in self.found_constrs: - if len(c.args) == 0: - return True - return False - -#CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE - -sources = [ - Source("kernel/celltypes",[ - WClass("CellType", link_types.pointer, None, None, "type.hash()", True), - WClass("CellTypes", link_types.pointer, None, None, None, True) - ] - ), - Source("kernel/consteval",[ - WClass("ConstEval", link_types.pointer, None, None, None, True) - ] - ), - Source("kernel/log",[]), - Source("kernel/register",[ - WClass("Pass", link_types.derive, None, None, None, True), - ] - ), - Source("kernel/rtlil",[ - WClass("IdString", link_types.ref_copy, None, "str()", "hash()"), - WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"), - WClass("AttrObject", link_types.ref_copy, None, None, None), - WClass("Selection", link_types.ref_copy, None, None, None), - WClass("Monitor", link_types.derive, None, None, None), - WClass("CaseRule",link_types.ref_copy, None, None, None, True), - WClass("SwitchRule",link_types.ref_copy, None, None, None, True), - WClass("SyncRule", link_types.ref_copy, None, None, None, True), - WClass("Process", link_types.ref_copy, None, "name.c_str()", "name.hash()"), - WClass("SigChunk", link_types.ref_copy, None, None, None), - WClass("SigBit", link_types.ref_copy, None, None, "hash()"), - WClass("SigSpec", link_types.ref_copy, None, None, "hash()"), - WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), - WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), - WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), - WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), - WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()") - ] - ), - #Source("kernel/satgen",[ - # ] - # ), - #Source("libs/ezsat/ezsat",[ - # ] - # ), - #Source("libs/ezsat/ezminisat",[ - # ] - # ), - Source("kernel/sigtools",[ - WClass("SigMap", link_types.pointer, None, None, None, True) - ] - ), - Source("kernel/yosys",[ - ] - ), - Source("kernel/cost",[]) - ] - -blacklist_methods = ["YOSYS_NAMESPACE::Pass::run_register", "YOSYS_NAMESPACE::Module::Pow"] - -enum_names = ["State","SyncType","ConstFlags"] - -enums = [] #Do not edit -glbls = [] - -unowned_functions = [] - -classnames = [] -for source in sources: - for wclass in source.classes: - classnames.append(wclass.name) - -def class_by_name(name): - for source in sources: - for wclass in source.classes: - if wclass.name == name: - return wclass - return None - -def enum_by_name(name): - for e in enums: - if e.name == name: - return e - return None - -def find_closing(text, open_tok, close_tok): - if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok): - return text.find(close_tok) - return text.find(close_tok) + find_closing(text[text.find(close_tok)+1:], open_tok, close_tok) + 1 - -def unpretty_string(s): - s = s.strip() - while s.find(" ") != -1: - s = s.replace(" "," ") - while s.find("\t") != -1: - s = s.replace("\t"," ") - s = s.replace(" (","(") - return s - -class WEnum: - name = None - namespace = None - values = [] - - def from_string(str_def, namespace, line_number): - str_def = str_def.strip() - if not str.startswith(str_def, "enum "): - return None - if str_def.count(";") != 1: - return None - str_def = str_def[5:] - enum = WEnum() - split = str_def.split(":") - if(len(split) != 2): - return None - enum.name = split[0].strip() - if enum.name not in enum_names: - return None - str_def = split[1] - if str_def.count("{") != str_def.count("}") != 1: - return None - if len(str_def) < str_def.find("}")+2 or str_def[str_def.find("}")+1] != ';': - return None - str_def = str_def.split("{")[-1].split("}")[0] - enum.values = [] - for val in str_def.split(','): - enum.values.append(val.strip().split('=')[0].strip()) - enum.namespace = namespace - return enum - - def gen_boost_py(self): - text = "\n\t\tenum_<" + self.namespace + "::" + self.name + ">(\"" + self.name + "\")\n" - for value in self.values: - text += "\t\t\t.value(\"" + value + "\"," + self.namespace + "::" + value + ")\n" - text += "\t\t\t;\n" - return text - - def __str__(self): - ret = "Enum " + self.namespace + "::" + self.name + "(\n" - for val in self.values: - ret = ret + "\t" + val + "\n" - return ret + ")" - - def __repr__(self): - return __str__(self) - -class WConstructor: - orig_text = None - args = [] - containing_file = None - member_of = None - duplicate = False - protected = False - - def __init__(self, containing_file, class_): - self.orig_text = "Auto generated default constructor" - self.args = [] - self.containing_file = containing_file - self.member_of = class_ - self.protected = False - - def from_string(str_def, containing_file, class_, line_number, protected = False): - if class_ == None: - return None - if str_def.count("delete;") > 0: - return None - con = WConstructor(containing_file, class_) - con.orig_text = str_def - con.args = [] - con.duplicate = False - con.protected = protected - if str.startswith(str_def, "inline "): - str_def = str_def[7:] - if not str.startswith(str_def, class_.name + "("): - return None - str_def = str_def[len(class_.name)+1:] - found = find_closing(str_def, "(", ")") - if found == -1: - return None - str_def = str_def[0:found].strip() - if len(str_def) == 0: - return con - for arg in split_list(str_def, ","): - parsed = Attribute.from_string(arg.strip(), containing_file, line_number) - if parsed == None: - return None - con.args.append(parsed) - return con - - def gen_decl(self): - if self.duplicate or self.protected: - return "" - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\t" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ");\n" - return text - - def gen_decl_derive(self): - if self.duplicate or self.protected: - return "" - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\t" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ")" - if len(self.args) == 0: - return text + "{}" - text += " : " - text += self.member_of.namespace + "::" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_call() + ", " - if len(self.args) > 0: - text = text[:-2] - text += "){}\n" - return text - - def gen_decl_wrapperclass(self): - if self.duplicate or self.protected: - return "" - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\t" + self.member_of.name + "Wrap(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ")" - if len(self.args) == 0: - return text + "{}" - text += " : " - text += self.member_of.name + "(" - for arg in self.args: - text += arg.gen_call() + ", " - if len(self.args) > 0: - text = text[:-2] - text += "){}\n" - return text - - def gen_decl_hash_py(self): - text = self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem_hash() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ");" - return text - - def gen_def(self): - if self.duplicate or self.protected: - return "" - text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t" + self.member_of.name + "::" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text +=")\n\t{" - for arg in self.args: - text += arg.gen_translation() - if self.member_of.link_type != link_types.derive: - text += "\n\t\tthis->ref_obj = new " + self.member_of.namespace + "::" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_call() + ", " - if len(self.args) > 0: - text = text[:-2] - if self.member_of.link_type != link_types.derive: - text += ");" - if self.member_of.link_type == link_types.global_list: - text += "\n\t\tthis->" + self.member_of.id_.varname + " = this->ref_obj->" + self.member_of.id_.varname + ";" - for arg in self.args: - text += arg.gen_cleanup() - text += "\n\t}\n" - return text - - def gen_boost_py(self): - if self.duplicate or self.protected or len(self.args) == 0: - return "" - text = "\n\t\t\t.def(init" - text += "<" - for a in self.args: - text += a.gen_listitem_hash() + ", " - text = text[0:-2] + ">())" - return text - -class WFunction: - orig_text = None - is_static = False - is_inline = False - is_virtual = False - ret_attr_type = attr_types.default - is_operator = False - ret_type = None - name = None - alias = None - args = [] - containing_file = None - member_of = None - duplicate = False - namespace = "" - - def from_string(str_def, containing_file, class_, line_number, namespace): - if str_def.count("delete;") > 0: - return None - func = WFunction() - func.is_static = False - func.is_inline = False - func.is_virtual = False - func.ret_attr_type = attr_types.default - func.is_operator = False - func.member_of = None - func.orig_text = str_def - func.args = [] - func.containing_file = containing_file - func.member_of = class_ - func.duplicate = False - func.namespace = namespace - str_def = str_def.replace("operator ","operator") - if str.startswith(str_def, "static "): - func.is_static = True - str_def = str_def[7:] - else: - func.is_static = False - if str.startswith(str_def, "inline "): - func.is_inline = True - str_def = str_def[7:] - else: - func.is_inline = False - if str.startswith(str_def, "virtual "): - func.is_virtual = True - str_def = str_def[8:] - else: - func.is_virtual = False - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - func.ret_type = WType.from_string(prefix + parts[0], containing_file, line_number) - - if func.ret_type == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - found = str_def.find("(") - if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")): - return None - func.name = str_def[:found] - str_def = str_def[found:] - if func.name.find("operator") != -1 and str.startswith(str_def, "()("): - func.name += "()" - str_def = str_def[2:] - str_def = str_def[1:] - if func.name.find("operator") != -1: - func.is_operator = True - if func.name.find("*") == 0: - func.name = func.name.replace("*", "") - func.ret_type.attr_type = attr_types.star - if func.name.find("&&") == 0: - func.name = func.name.replace("&&", "") - func.ret_type.attr_type = attr_types.ampamp - if func.name.find("&") == 0: - func.name = func.name.replace("&", "") - func.ret_type.attr_type = attr_types.amp - - found = find_closing(str_def, "(", ")") - if found == -1: - return None - str_def = str_def[0:found] - if func.name in blacklist_methods: - return None - if func.namespace != None and func.namespace != "": - if (func.namespace + "::" + func.name) in blacklist_methods: - return None - if func.member_of != None: - if (func.namespace + "::" + func.member_of.name + "::" + func.name) in blacklist_methods: - return None - if func.is_operator and func.name.replace(" ","").replace("operator","").split("::")[-1] not in wrappable_operators: - return None - - testname = func.name - if func.is_operator: - testname = testname[:testname.find("operator")] - if testname.count(")") != 0 or testname.count("(") != 0 or testname.count("~") != 0 or testname.count(";") != 0 or testname.count(">") != 0 or testname.count("<") != 0 or testname.count("throw") != 0: - return None - - func.alias = func.name - if func.name in keyword_aliases: - func.alias = keyword_aliases[func.name] - str_def = str_def[:found].strip() - if(len(str_def) == 0): - return func - for arg in split_list(str_def, ","): - if arg.strip() == "...": - continue - parsed = Attribute.from_string(arg.strip(), containing_file, line_number) - if parsed == None: - return None - func.args.append(parsed) - return func - - def gen_alias(self): - self.alias = self.name - for arg in self.args: - self.alias += "__" + arg.wtype.gen_text_cpp().replace("::", "_").replace("<","_").replace(">","_").replace(" ","").replace("*","").replace(",","") - - def gen_decl(self): - if self.duplicate: - return "" - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\t" - if self.is_static: - text += "static " - text += self.ret_type.gen_text() + " " + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += ");\n" - return text - - def gen_decl_virtual(self): - if self.duplicate: - return "" - if not self.is_virtual: - return self.gen_decl() - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\tvirtual " - if self.is_static: - text += "static " - text += self.ret_type.gen_text() + " py_" + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += ")" - if len(self.args) == 0: - text += "{}" - else: - text += "\n\t\t{" - for arg in self.args: - text += "\n\t\t\t(void)" + arg.gen_varname() + ";" - text += "\n\t\t}\n" - text += "\n\t\tvirtual " - if self.is_static: - text += "static " - text += self.ret_type.gen_text() + " " + self.name + "(" - for arg in self.args: - text += arg.gen_listitem_cpp() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += ") override;\n" - return text - - def gen_decl_hash_py(self): - text = self.ret_type.gen_text() + " " + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem_hash() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ");" - return text - - def gen_def(self): - if self.duplicate: - return "" - text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t" + self.ret_type.gen_text() + " " - if self.member_of != None: - text += self.member_of.name + "::" - text += self.alias + "(" - for arg in self.args: - text += arg.gen_listitem() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text +=")\n\t{" - for arg in self.args: - text += arg.gen_translation() - text += "\n\t\t" - if self.ret_type.name != "void": - if self.ret_type.name in known_containers: - text += self.ret_type.gen_text_cpp() - else: - text += self.ret_type.gen_text() - if self.ret_type.name in classnames or (self.ret_type.name in known_containers and self.ret_type.attr_type == attr_types.star): - text += "*" - text += " ret_ = " - if self.ret_type.name in classnames: - text += self.ret_type.name + "::get_py_obj(" - if self.member_of == None: - text += "::" + self.namespace + "::" + self.alias + "(" - elif self.is_static: - text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "(" - else: - text += "this->get_cpp_obj()->" + self.name + "(" - for arg in self.args: - text += arg.gen_call() + ", " - if len(self.args) > 0: - text = text[:-2] - if self.ret_type.name in classnames: - text += ")" - text += ");" - for arg in self.args: - text += arg.gen_cleanup() - if self.ret_type.name != "void": - if self.ret_type.name in classnames: - text += "\n\t\treturn *ret_;" - elif self.ret_type.name in known_containers: - text += known_containers[self.ret_type.name].translate_cpp("ret_", self.ret_type.cont.args, "\n\t\t", self.ret_type.attr_type == attr_types.star) - text += "\n\t\treturn ret____tmp;" - else: - text += "\n\t\treturn ret_;" - text += "\n\t}\n" - return text - - def gen_def_virtual(self): - if self.duplicate: - return "" - if not self.is_virtual: - return self.gen_def() - text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t" - if self.is_static: - text += "static " - text += self.ret_type.gen_text() + " " + self.member_of.name + "::" + self.name + "(" - for arg in self.args: - text += arg.gen_listitem_cpp() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += ")\n\t{" - for arg in self.args: - text += arg.gen_translation_cpp() - text += "\n\t\t" - if self.member_of == None: - text += "::" + self.namespace + "::" + self.alias + "(" - elif self.is_static: - text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "(" - else: - text += "py_" + self.alias + "(" - for arg in self.args: - text += arg.gen_call_cpp() + ", " - if len(self.args) > 0: - text = text[:-2] - if self.ret_type.name in classnames: - text += ")" - text += ");" - for arg in self.args: - text += arg.gen_cleanup() - text += "\n\t}\n" - return text - - def gen_default_impl(self): - if self.duplicate: - return "" - if not self.is_virtual: - return "" - text = "\n\n\t\t" + self.ret_type.gen_text() + " py_" + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - - call_string = "py_" + self.alias + "(" - for arg in self.args: - call_string += arg.gen_varname() + ", " - if len(self.args) > 0: - call_string = call_string[0:-2] - call_string += ");" - - text += ")\n\t\t{" - text += "\n\t\t\tif(boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\"))" - text += "\n\t\t\t\t" + call_string - text += "\n\t\t\telse" - text += "\n\t\t\t\t" + self.member_of.name + "::" + call_string - text += "\n\t\t}" - - text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ")\n\t\t{" - text += "\n\t\t\tthis->" + self.member_of.name + "::" + call_string - text += "\n\t\t}" - return text - - - def gen_boost_py(self): - if self.duplicate: - return "" - if self.member_of == None: - text = "\n\t\tdef" - else: - text = "\n\t\t\t.def" - if len(self.args) > -1: - if self.ret_type.name in known_containers: - text += "<" + known_containers[self.ret_type.name].typename + " " - else: - text += "<" + self.ret_type.name + " " - if self.member_of == None or self.is_static: - text += "(*)(" - else: - text += "(" + self.member_of.name + "::*)(" - for a in self.args: - text += a.gen_listitem_hash() + ", " - if len(self.args) > 0: - text = text[0:-2] + ")>" - else: - text += "void)>" - - if self.is_operator: - text += "(\"" + wrappable_operators[self.name.replace("operator","")] + "\"" - else: - if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual: - text += "(\"py_" + self.alias + "\"" - else: - text += "(\"" + self.alias + "\"" - if self.member_of != None: - text += ", &" + self.member_of.name + "::" - if self.member_of.link_type == link_types.derive and self.is_virtual: - text += "py_" + self.alias - text += ", &" + self.member_of.name + "Wrap::default_py_" + self.alias - else: - text += self.alias - - text += ")" - else: - text += ", " + "YOSYS_PYTHON::" + self.alias + ");" - return text - -class WMember: - orig_text = None - wtype = attr_types.default - name = None - containing_file = None - member_of = None - namespace = "" - is_const = False - - def from_string(str_def, containing_file, class_, line_number, namespace): - member = WMember() - member.orig_text = str_def - member.wtype = None - member.name = "" - member.containing_file = containing_file - member.member_of = class_ - member.namespace = namespace - member.is_const = False - - if str.startswith(str_def, "const "): - member.is_const = True - str_def = str_def[6:] - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - member.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) - - if member.wtype == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1: - return None - - found = str_def.find(";") - if found == -1: - return None - - found_eq = str_def.find("=") - if found_eq != -1: - found = found_eq - - member.name = str_def[:found] - str_def = str_def[found+1:] - if member.name.find("*") == 0: - member.name = member.name.replace("*", "") - member.wtype.attr_type = attr_types.star - if member.name.find("&&") == 0: - member.name = member.name.replace("&&", "") - member.wtype.attr_type = attr_types.ampamp - if member.name.find("&") == 0: - member.name = member.name.replace("&", "") - member.wtype.attr_type = attr_types.amp - - if(len(str_def.strip()) != 0): - return None - - if len(member.name.split(",")) > 1: - member_list = [] - for name in member.name.split(","): - name = name.strip(); - member_list.append(WMember()) - member_list[-1].orig_text = member.orig_text - member_list[-1].wtype = member.wtype - member_list[-1].name = name - member_list[-1].containing_file = member.containing_file - member_list[-1].member_of = member.member_of - member_list[-1].namespace = member.namespace - member_list[-1].is_const = member.is_const - return member_list - - return member - - def gen_decl(self): - text = "\n\t\t" + self.wtype.gen_text() + " get_var_py_" + self.name + "();\n" - if self.is_const: - return text - if self.wtype.name in classnames: - text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs);\n" - else: - text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs);\n" - return text - - def gen_def(self): - text = "\n\t" + self.wtype.gen_text() + " " + self.member_of.name +"::get_var_py_" + self.name + "()" - text += "\n\t{\n\t\t" - if self.wtype.attr_type == attr_types.star: - text += "if(this->get_cpp_obj()->" + self.name + " == NULL)\n\t\t\t" - text += "throw std::runtime_error(\"Member \\\"" + self.name + "\\\" is NULL\");\n\t\t" - if self.wtype.name in known_containers: - text += self.wtype.gen_text_cpp() - else: - text += self.wtype.gen_text() - - if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): - text += "*" - text += " ret_ = " - if self.wtype.name in classnames: - text += self.wtype.name + "::get_py_obj(" - if self.wtype.attr_type != attr_types.star: - text += "&" - text += "this->get_cpp_obj()->" + self.name - if self.wtype.name in classnames: - text += ")" - text += ";" - - if self.wtype.name in classnames: - text += "\n\t\treturn *ret_;" - elif self.wtype.name in known_containers: - text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) - text += "\n\t\treturn ret____tmp;" - else: - text += "\n\t\treturn ret_;" - text += "\n\t}\n" - - if self.is_const: - return text - - ret = Attribute(self.wtype, "rhs"); - - if self.wtype.name in classnames: - text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)" - else: - text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)" - text += "\n\t{" - text += ret.gen_translation() - text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";" - text += "\n\t}\n" - - return text; - - def gen_boost_py(self): - text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name - if not self.is_const: - text += ", &" + self.member_of.name + "::set_var_py_" + self.name - text += ")" - return text - -class WGlobal: - orig_text = None - wtype = attr_types.default - name = None - containing_file = None - namespace = "" - is_const = False - - def from_string(str_def, containing_file, line_number, namespace): - glbl = WGlobal() - glbl.orig_text = str_def - glbl.wtype = None - glbl.name = "" - glbl.containing_file = containing_file - glbl.namespace = namespace - glbl.is_const = False - - if not str.startswith(str_def, "extern"): - return None - str_def = str_def[7:] - - if str.startswith(str_def, "const "): - glbl.is_const = True - str_def = str_def[6:] - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - glbl.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) - - if glbl.wtype == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1: - return None - - found = str_def.find(";") - if found == -1: - return None - - found_eq = str_def.find("=") - if found_eq != -1: - found = found_eq - - glbl.name = str_def[:found] - str_def = str_def[found+1:] - if glbl.name.find("*") == 0: - glbl.name = glbl.name.replace("*", "") - glbl.wtype.attr_type = attr_types.star - if glbl.name.find("&&") == 0: - glbl.name = glbl.name.replace("&&", "") - glbl.wtype.attr_type = attr_types.ampamp - if glbl.name.find("&") == 0: - glbl.name = glbl.name.replace("&", "") - glbl.wtype.attr_type = attr_types.amp - - if(len(str_def.strip()) != 0): - return None - - if len(glbl.name.split(",")) > 1: - glbl_list = [] - for name in glbl.name.split(","): - name = name.strip(); - glbl_list.append(WGlobal()) - glbl_list[-1].orig_text = glbl.orig_text - glbl_list[-1].wtype = glbl.wtype - glbl_list[-1].name = name - glbl_list[-1].containing_file = glbl.containing_file - glbl_list[-1].namespace = glbl.namespace - glbl_list[-1].is_const = glbl.is_const - return glbl_list - - return glbl - - def gen_def(self): - text = "\n\t" - if self.is_const: - text += "const " - text += self.wtype.gen_text() + " get_var_py_" + self.name + "()" - text += "\n\t{\n\t\t" - if self.wtype.attr_type == attr_types.star: - text += "if(" + self.namespace + "::" + self.name + " == NULL)\n\t\t\t" - text += "throw std::runtime_error(\"" + self.namespace + "::" + self.name + " is NULL\");\n\t\t" - if self.wtype.name in known_containers: - text += self.wtype.gen_text_cpp() - else: - if self.is_const: - text += "const " - text += self.wtype.gen_text() - - if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): - text += "*" - text += " ret_ = " - if self.wtype.name in classnames: - text += self.wtype.name + "::get_py_obj(" - if self.wtype.attr_type != attr_types.star: - text += "&" - text += self.namespace + "::" + self.name - if self.wtype.name in classnames: - text += ")" - text += ";" - - if self.wtype.name in classnames: - text += "\n\t\treturn *ret_;" - elif self.wtype.name in known_containers: - text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) - text += "\n\t\treturn ret____tmp;" - else: - text += "\n\t\treturn ret_;" - text += "\n\t}\n" - - if self.is_const: - return text - - ret = Attribute(self.wtype, "rhs"); - - if self.wtype.name in classnames: - text += "\n\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)" - else: - text += "\n\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)" - text += "\n\t{" - text += ret.gen_translation() - text += "\n\t\t" + self.namespace + "::" + self.name + " = " + ret.gen_call() + ";" - text += "\n\t}\n" - - return text; - - def gen_boost_py(self): - text = "\n\t\t\t.add_static_property(\"" + self.name + "\", &" + "YOSYS_PYTHON::get_var_py_" + self.name - if not self.is_const: - text += ", &YOSYS_PYTHON::set_var_py_" + self.name - text += ")" - return text - -def concat_namespace(tuple_list): - if len(tuple_list) == 0: - return "" - ret = "" - for namespace in tuple_list: - ret += "::" + namespace[0] - return ret[2:] - -def calc_ident(text): - if len(text) == 0 or text[0] != ' ': - return 0 - return calc_ident(text[1:]) + 1 - -def assure_length(text, length, left = False): - if len(text) > length: - return text[:length] - if left: - return text + " "*(length - len(text)) - return " "*(length - len(text)) + text - -def parse_header(source): - debug("Parsing " + source.name + ".pyh",1) - source_file = open(source.name + ".pyh", "r") - - source_text = [] - in_line = source_file.readline() - - namespaces = [] - - while(in_line): - if(len(in_line)>1): - source_text.append(in_line.replace("char *", "char_p ").replace("char* ", "char_p ")) - in_line = source_file.readline() - - i = 0 - - namespaces = [] - class_ = None - private_segment = False - - while i < len(source_text): - line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }") - ugly_line = unpretty_string(line) - - # for anonymous unions, ignore union enclosure by skipping start line and replacing end line with new line - if 'union {' in line: - j = i+1 - while j < len(source_text): - union_line = source_text[j] - if '};' in union_line: - source_text[j] = '\n' - break - j += 1 - if j != len(source_text): - i += 1 - continue - - if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1: - namespace_name = ugly_line[10:].replace("{","").strip() - namespaces.append((namespace_name, ugly_line.count("{"))) - debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----",3) - i += 1 - continue - - if len(namespaces) != 0: - namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}")) - if namespaces[-1][1] == 0: - debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3) - del namespaces[-1] - i += 1 - continue - - if class_ == None and (str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class")) and ugly_line.count(";") == 0: - - struct_name = ugly_line.split(" ")[1].split("::")[-1] - impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1] - complete_namespace = concat_namespace(namespaces) - for namespace in impl_namespaces: - complete_namespace += "::" + namespace - debug("\tFound " + struct_name + " in " + complete_namespace,2) - - base_class_name = None - if len(ugly_line.split(" : ")) > 1: # class is derived - deriv_str = ugly_line.split(" : ")[1] - if len(deriv_str.split("::")) > 1: # namespace of base class is given - base_class_name = deriv_str.split("::", 1)[1] - else: - base_class_name = deriv_str.split(" ")[0] - debug("\t " + struct_name + " is derived from " + base_class_name,2) - base_class = class_by_name(base_class_name) - - class_ = (class_by_name(struct_name), ugly_line.count("{"))#calc_ident(line)) - if struct_name in classnames: - class_[0].namespace = complete_namespace - class_[0].base_class = base_class - i += 1 - continue - - if class_ != None: - class_ = (class_[0], class_[1] + ugly_line.count("{") - ugly_line.count("}")) - if class_[1] == 0: - if class_[0] == None: - debug("\tExiting unknown class", 3) - else: - debug("\tExiting class " + class_[0].name, 3) - class_ = None - private_segment = False - i += 1 - continue - - if class_ != None and (line.find("private:") != -1 or line.find("protected:") != -1): - private_segment = True - i += 1 - continue - if class_ != None and line.find("public:") != -1: - private_segment = False - i += 1 - continue - - candidate = None - - if private_segment and class_ != None and class_[0] != None: - candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i, True) - if candidate != None: - debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_constrs.append(candidate) - i += 1 - continue - - if not private_segment and (class_ == None or class_[0] != None): - if class_ != None: - candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) - else: - candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces)) - if candidate != None and candidate.name.find("::") == -1: - if class_ == None: - debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) - unowned_functions.append(candidate) - else: - debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_funs.append(candidate) - else: - candidate = WEnum.from_string(ugly_line, concat_namespace(namespaces), i) - if candidate != None: - enums.append(candidate) - debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) - elif class_ != None and class_[1] == 1: - candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i) - if candidate != None: - debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_constrs.append(candidate) - else: - candidate = WMember.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) - if candidate != None: - if type(candidate) == list: - for c in candidate: - debug("\t\tFound member \"" + c.name + "\" of class \"" + class_[0].name + "\" of type \"" + c.wtype.name + "\"", 2) - class_[0].found_vars.extend(candidate) - else: - debug("\t\tFound member \"" + candidate.name + "\" of class \"" + class_[0].name + "\" of type \"" + candidate.wtype.name + "\"", 2) - class_[0].found_vars.append(candidate) - if candidate == None and class_ == None: - candidate = WGlobal.from_string(ugly_line, source.name, i, concat_namespace(namespaces)) - if candidate != None: - if type(candidate) == list: - for c in candidate: - glbls.append(c) - debug("\tFound global \"" + c.name + "\" in namespace " + concat_namespace(namespaces), 2) - else: - glbls.append(candidate) - debug("\tFound global \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces), 2) - - j = i - line = unpretty_string(line) - while candidate == None and j+1 < len(source_text) and line.count(';') <= 1 and line.count("(") >= line.count(")"): - j += 1 - line = line + "\n" + unpretty_string(source_text[j]) - if class_ != None: - candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) - else: - candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces)) - if candidate != None and candidate.name.find("::") == -1: - if class_ == None: - debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) - unowned_functions.append(candidate) - else: - debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_funs.append(candidate) - continue - candidate = WEnum.from_string(line, concat_namespace(namespaces), i) - if candidate != None: - enums.append(candidate) - debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) - continue - if class_ != None: - candidate = WConstructor.from_string(line, source.name, class_[0], i) - if candidate != None: - debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_constrs.append(candidate) - continue - if class_ == None: - candidate = WGlobal.from_string(line, source.name, i, concat_namespace(namespaces)) - if candidate != None: - if type(candidate) == list: - for c in candidate: - glbls.append(c) - debug("\tFound global \"" + c.name + "\" in namespace " + concat_namespace(namespaces), 2) - else: - glbls.append(candidate) - debug("\tFound global \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces), 2) - continue - if candidate != None: - while i < j: - i += 1 - line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }") - ugly_line = unpretty_string(line) - if len(namespaces) != 0: - namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}")) - if namespaces[-1][1] == 0: - debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3) - del namespaces[-1] - if class_ != None: - class_ = (class_[0] , class_[1] + ugly_line.count("{") - ugly_line.count("}")) - if class_[1] == 0: - if class_[0] == None: - debug("\tExiting unknown class", 3) - else: - debug("\tExiting class " + class_[0].name, 3) - class_ = None - private_segment = False - i += 1 - else: - i += 1 - -def debug(message, level): - if level <= debug.debug_level: - print(message) - -def expand_function(f): - fun_list = [] - arg_list = [] - for arg in f.args: - if arg.default_value != None and (arg.wtype.name.split(" ")[-1] in primitive_types or arg.wtype.name in enum_names or (arg.wtype.name in classnames and arg.default_value == "nullptr")): - fi = copy.deepcopy(f) - fi.args = copy.deepcopy(arg_list) - fun_list.append(fi) - arg_list.append(arg) - fun_list.append(f) - return fun_list - -def expand_functions(): - global unowned_functions - new_funs = [] - for fun in unowned_functions: - new_funs.extend(expand_function(fun)) - unowned_functions = new_funs - for source in sources: - for class_ in source.classes: - new_funs = [] - for fun in class_.found_funs: - new_funs.extend(expand_function(fun)) - class_.found_funs = new_funs - -def inherit_members(): - for source in sources: - for class_ in source.classes: - if class_.base_class: - base_funs = copy.deepcopy(class_.base_class.found_funs) - for fun in base_funs: - fun.member_of = class_ - fun.namespace = class_.namespace - base_vars = copy.deepcopy(class_.base_class.found_vars) - for var in base_vars: - var.member_of = class_ - var.namespace = class_.namespace - class_.found_funs.extend(base_funs) - class_.found_vars.extend(base_vars) - -def clean_duplicates(): - for source in sources: - for class_ in source.classes: - known_decls = {} - for fun in class_.found_funs: - if fun.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + fun.gen_decl_hash_py(),3) - other = known_decls[fun.gen_decl_hash_py()] - other.gen_alias() - fun.gen_alias() - if fun.gen_decl_hash_py() == other.gen_decl_hash_py(): - fun.duplicate = True - debug("Disabled \"" + fun.gen_decl_hash_py() + "\"", 3) - else: - known_decls[fun.gen_decl_hash_py()] = fun - known_decls = [] - for con in class_.found_constrs: - if con.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + con.gen_decl_hash_py(),3) - con.duplicate = True - else: - known_decls.append(con.gen_decl_hash_py()) - known_decls = [] - for fun in unowned_functions: - if fun.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + fun.gen_decl_hash_py(),3) - fun.duplicate = True - else: - known_decls.append(fun.gen_decl_hash_py()) - -def gen_wrappers(filename, debug_level_ = 0): - debug.debug_level = debug_level_ - for source in sources: - parse_header(source) - - expand_functions() - inherit_members() - clean_duplicates() - - import shutil - import math - col = shutil.get_terminal_size((80,20)).columns - debug("-"*col, 1) - debug("-"*math.floor((col-7)/2)+"SUMMARY"+"-"*math.ceil((col-7)/2), 1) - debug("-"*col, 1) - for source in sources: - for class_ in source.classes: - debug("Class " + assure_length(class_.name, len(max(classnames, key=len)), True) + " contains " + assure_length(str(len(class_.found_vars)), 3, False) + " member variables, "+ assure_length(str(len(class_.found_funs)), 3, False) + " methods and " + assure_length(str(len(class_.found_constrs)), 2, False) + " constructors", 1) - if len(class_.found_constrs) == 0: - class_.found_constrs.append(WConstructor(source.name, class_)) - debug(str(len(unowned_functions)) + " functions are unowned", 1) - debug(str(len(unowned_functions)) + " global variables", 1) - for enum in enums: - debug("Enum " + assure_length(enum.name, len(max(enum_names, key=len)), True) + " contains " + assure_length(str(len(enum.values)), 2, False) + " values", 1) - debug("-"*col, 1) - wrapper_file = open(filename, "w+") - wrapper_file.write( -"""/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia 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 a generated file and can be overwritten by make - */ - -#ifdef WITH_PYTHON -""") - for source in sources: - wrapper_file.write("#include \""+source.name+".h\"\n") - wrapper_file.write(""" -#include -#include -#include -#include -#include -#include // std::streamsize -#include -#include // boost::iostreams::sink -#include -USING_YOSYS_NAMESPACE - -namespace YOSYS_PYTHON { - - struct YosysStatics{}; -""") - - for source in sources: - for wclass in source.classes: - wrapper_file.write("\n\tstruct " + wclass.name + ";") - - wrapper_file.write("\n") - - for source in sources: - for wclass in source.classes: - wrapper_file.write(wclass.gen_decl(source.name)) - - wrapper_file.write("\n") - - for source in sources: - for wclass in source.classes: - wrapper_file.write(wclass.gen_funs(source.name)) - - for fun in unowned_functions: - wrapper_file.write(fun.gen_def()) - - for glbl in glbls: - wrapper_file.write(glbl.gen_def()) - - wrapper_file.write(""" struct Initializer - { - Initializer() { - if(!Yosys::yosys_already_setup()) - { - Yosys::log_streams.push_back(&std::cout); - Yosys::log_error_stderr = true; - Yosys::yosys_setup(); - } - } - - Initializer(Initializer const &) {} - - ~Initializer() { - Yosys::yosys_shutdown(); - } - }; - - - /// source: https://stackoverflow.com/questions/26033781/converting-python-io-object-to-stdostream-when-using-boostpython?noredirect=1&lq=1 - /// @brief Type that implements the Boost.IOStream's Sink and Flushable - /// concept for writing data to Python object that support: - /// n = object.write(str) # n = None or bytes written - /// object.flush() # if flush exists, then it is callable - class PythonOutputDevice - { - public: - - // This class models both the Sink and Flushable concepts. - struct category - : boost::iostreams::sink_tag, - boost::iostreams::flushable_tag - {}; - - explicit - PythonOutputDevice(boost::python::object object) - : object_(object) - {} - - // Sink concept. - public: - - typedef char char_type; - - std::streamsize write(const char* buffer, std::streamsize buffer_size) - { - namespace python = boost::python; - // Copy the buffer to a python string. - python::str data(buffer, buffer_size); - - // Invoke write on the python object, passing in the data. The following - // is equivalent to: - // n = object_.write(data) - python::extract bytes_written( - object_.attr("write")(data)); - - // Per the Sink concept, return the number of bytes written. If the - // Python return value provides a numeric result, then use it. Otherwise, - // such as the case of a File object, use the buffer_size. - return bytes_written.check() - ? bytes_written - : buffer_size; - } - - // Flushable concept. - public: - - bool flush() - { - // If flush exists, then call it. - boost::python::object flush = object_.attr("flush"); - if (!flush.is_none()) - { - flush(); - } - - // Always return true. If an error occurs, an exception should be thrown. - return true; - } - - private: - boost::python::object object_; - }; - - /// @brief Use an auxiliary function to adapt the legacy function. - void log_to_stream(boost::python::object object) - { - // Create an ostream that delegates to the python object. - boost::iostreams::stream* output = new boost::iostreams::stream(object); - Yosys::log_streams.insert(Yosys::log_streams.begin(), output); - }; - - - BOOST_PYTHON_MODULE(libyosys) - { - using namespace boost::python; - - class_("Initializer"); - scope().attr("_hidden") = new Initializer(); - - def("log_to_stream", &log_to_stream); -""") - - for enum in enums: - wrapper_file.write(enum.gen_boost_py()) - - for source in sources: - for wclass in source.classes: - wrapper_file.write(wclass.gen_boost_py()) - - for fun in unowned_functions: - wrapper_file.write(fun.gen_boost_py()) - - wrapper_file.write("\n\n\t\tclass_(\"Yosys\")\n") - for glbl in glbls: - wrapper_file.write(glbl.gen_boost_py()) - wrapper_file.write("\t\t;\n") - - wrapper_file.write("\n\t}\n}\n#endif") - -def print_includes(): - for source in sources: - print(source.name + ".pyh") diff --git a/yosys/misc/yosys-config.in b/yosys/misc/yosys-config.in deleted file mode 100644 index f0f0f755231..00000000000 --- a/yosys/misc/yosys-config.in +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env bash - -help() { - { - echo "" - echo "Usage: $0 [--exec] [--prefix pf] args.." - echo " $0 --build modname.so cppsources.." - echo "" - echo "Replacement args:" - echo " --cxx @CXX@" - echo " --cxxflags $( echo '@CXXFLAGS@' | fmt -w60 | sed ':a;N;$!ba;s/\n/ \\\n /g' )" - echo " --ldflags @LDFLAGS@" - echo " --ldlibs @LDLIBS@" - echo " --bindir @BINDIR@" - echo " --datdir @DATDIR@" - echo "" - echo "All other args are passed through as they are." - echo "" - echo "Use --exec to call a command instead of generating output. Example usage:" - echo "" - echo " $0 --exec --cxx --cxxflags --ldflags -o plugin.so -shared plugin.cc --ldlibs" - echo "" - echo "The above command can be abbreviated as:" - echo "" - echo " $0 --build plugin.so plugin.cc" - echo "" - echo "Use --prefix to change the prefix for the special args from '--' to" - echo "something else. Example:" - echo "" - echo " $0 --prefix @ bindir: @bindir" - echo "" - echo "The args --bindir and --datdir can be directly followed by a slash and" - echo "additional text. Example:" - echo "" - echo " $0 --datdir/simlib.v" - echo "" - } >&2 - exit 1 -} - -if [ $# -eq 0 ]; then - help -fi - -if [ "$1" == "--build" ]; then - modname="$2"; shift 2 - set -- --exec --cxx --cxxflags --ldflags -o "$modname" -shared "$@" --ldlibs -fi - -prefix="--" -get_prefix=false -exec_mode=false -declare -a tokens=() - -for opt; do - if $get_prefix; then - prefix="$opt" - get_prefix=false - continue - fi - case "$opt" in - "$prefix"cxx) - tokens=( "${tokens[@]}" @CXX@ ) ;; - "$prefix"cxxflags) - tokens=( "${tokens[@]}" @CXXFLAGS@ ) ;; - "$prefix"ldflags) - tokens=( "${tokens[@]}" @LDFLAGS@ ) ;; - "$prefix"ldlibs) - tokens=( "${tokens[@]}" @LDLIBS@ ) ;; - "$prefix"bindir) - tokens=( "${tokens[@]}" '@BINDIR@' ) ;; - "$prefix"datdir) - tokens=( "${tokens[@]}" '@DATDIR@' ) ;; - "$prefix"bindir/*) - tokens=( "${tokens[@]}" '@BINDIR@'"${opt#${prefix}bindir}" ) ;; - "$prefix"datdir/*) - tokens=( "${tokens[@]}" '@DATDIR@'"${opt#${prefix}datdir}" ) ;; - --help|-\?|-h) - if [ ${#tokens[@]} -eq 0 ]; then - help - else - tokens=( "${tokens[@]}" "$opt" ) - fi ;; - --exec) - if [ ${#tokens[@]} -eq 0 ]; then - exec_mode=true - else - tokens=( "${tokens[@]}" "$opt" ) - fi ;; - --prefix) - if [ ${#tokens[@]} -eq 0 ]; then - get_prefix=true - else - tokens=( "${tokens[@]}" "$opt" ) - fi ;; - *) - tokens=( "${tokens[@]}" "$opt" ) - esac -done - -if $exec_mode; then - exec "${tokens[@]}" -fi - -echo "${tokens[@]}" -exit 0 - diff --git a/yosys/misc/yosysjs/demo01.html b/yosys/misc/yosysjs/demo01.html deleted file mode 100644 index 3f9f737e908..00000000000 --- a/yosys/misc/yosysjs/demo01.html +++ /dev/null @@ -1,197 +0,0 @@ - - YosysJS Example Application #01 - - -

YosysJS Example Application #01

-
[ load example ]
- -
-

Loading...
- - - diff --git a/yosys/misc/yosysjs/demo02.html b/yosys/misc/yosysjs/demo02.html deleted file mode 100644 index 9191db98d42..00000000000 --- a/yosys/misc/yosysjs/demo02.html +++ /dev/null @@ -1,103 +0,0 @@ - - YosysJS Example Application #02 - - - -

YosysJS Example Application #02

-

- - - -

- - - - diff --git a/yosys/misc/yosysjs/demo03.html b/yosys/misc/yosysjs/demo03.html deleted file mode 100644 index c2ca40ef5d1..00000000000 --- a/yosys/misc/yosysjs/demo03.html +++ /dev/null @@ -1,103 +0,0 @@ - -YosysJS Example Application #02 - - - - - - -

-

YosysJS Example Application #03

- Your mission: Create a behavioral Verilog model for the following circuit: -

-

- - diff --git a/yosys/misc/yosysjs/yosysjs.js b/yosys/misc/yosysjs/yosysjs.js deleted file mode 100644 index ea98c9b5170..00000000000 --- a/yosys/misc/yosysjs/yosysjs.js +++ /dev/null @@ -1,312 +0,0 @@ -var YosysJS = new function() { - this.script_element = document.currentScript; - this.viz_element = undefined; - this.viz_ready = true; - - this.url_prefix = this.script_element.src.replace(/[^/]+$/, '') - - this.load_viz = function() { - if (this.viz_element) - return; - - this.viz_element = document.createElement('iframe') - this.viz_element.style.display = 'none' - document.body.appendChild(this.viz_element); - - this.viz_element.contentWindow.document.open(); - this.viz_element.contentWindow.document.write('