diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 2c1483345..2ed92c913 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -6,7 +6,7 @@ body: attributes: value: > - Learn more [here](https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/extending_yosys/contributing.html#reporting-bugs) about how to report bugs. We fix well-reported bugs the fastest. + Learn more in our [Reporting bugs](https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/extending_yosys/contributing.html#reporting-bugs) docs section. We fix well-reported bugs the fastest. If you have a general question, please ask it on the [Discourse forum](https://yosyshq.discourse.group/). diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index c6ea64e2e..7c1f7f60c 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -42,7 +42,7 @@ runs: if: runner.os == 'Linux' && inputs.get-build-deps == 'true' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: - packages: gawk git make python3 bison clang flex libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev libnsl-dev libdwarf-dev libelf-dev elfutils libdw-dev ccache libgtest-dev + packages: gawk git make python3 bison clang flex libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev libnsl-dev libdwarf-dev libelf-dev elfutils libdw-dev ccache libgtest-dev libgmock-dev version: ${{ inputs.runs-on }}-buildys - name: Linux docs dependencies diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 847c9e123..8635ac809 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,7 +12,7 @@ jobs: permissions: write-all steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true persist-credentials: false @@ -28,7 +28,7 @@ jobs: get-build-deps: true - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: cpp queries: security-extended,security-and-quality @@ -37,7 +37,13 @@ jobs: run: cd verific/tclmain && make -j6 - name: Build - run: make yosys -j6 + run: | + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + + cmake -C Configuration.cmake -B build . + cmake --build build -j6 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 5d0ac72d4..cdf0c7fd5 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -1,23 +1,20 @@ name: Test extra build flows on: - # always test main - push: - branches: - - main - merge_group: - # test PRs pull_request: - # allow triggering tests, ignores skip check + merge_group: + #push: + # branches: [ main ] workflow_dispatch: jobs: pre_job: runs-on: ubuntu-latest outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} + should_skip: ${{ steps.set_output.outputs.should_skip }} steps: - id: skip_check + if: ${{ github.event_name != 'merge_group' }} uses: fkirc/skip-duplicate-actions@v5 with: # don't run on documentation changes @@ -26,58 +23,67 @@ jobs: # but never cancel main cancel_others: ${{ github.ref != 'refs/heads/main' }} - vs-prep: - name: Prepare Visual Studio build - runs-on: ubuntu-latest - needs: [pre_job] - if: needs.pre_job.outputs.should_skip != 'true' - steps: - - uses: actions/checkout@v4 - with: - submodules: true - persist-credentials: false - - run: sudo apt-get install libfl-dev - - name: Build - run: make vcxsrc YOSYS_COMPILER="Visual Studio" VCX_DIR_NAME=yosys-win32-vcxsrc-latest - - uses: actions/upload-artifact@v4 - with: - name: vcxsrc - path: yosys-win32-vcxsrc-latest.zip + - id: set_output + run: | + if [ "${{ github.event_name }}" = "merge_group" ]; then + echo "should_skip=false" >> $GITHUB_OUTPUT + else + echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT + fi vs-build: name: Visual Studio build runs-on: windows-latest - needs: [vs-prep, pre_job] - if: needs.pre_job.outputs.should_skip != 'true' + needs: [pre_job] + if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true' steps: - - uses: actions/download-artifact@v4 + - uses: actions/checkout@v5 with: - name: vcxsrc - path: . - - name: unzip - run: unzip yosys-win32-vcxsrc-latest.zip - - name: setup-msbuild - uses: microsoft/setup-msbuild@v2 - - name: MSBuild - working-directory: yosys-win32-vcxsrc-latest - run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.26100.0 + submodules: true + persist-credentials: false + + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 + + - name: Install flex/bison + shell: pwsh + run: | + choco install winflexbison3 --no-progress + + # Make tools visible to CMake + echo "C:\Program Files (x86)\GnuWin32\bin" | Out-File -Append -FilePath $env:GITHUB_PATH + echo "C:\ProgramData\chocolatey\lib\winflexbison3\tools" | Out-File -Append -FilePath $env:GITHUB_PATH + + - name: Configure CMake + run: > + cmake -S . -B build + -A x64 + -DCMAKE_BUILD_TYPE=Release + -DYOSYS_WITHOUT_ABC=ON + + - name: Build + run: > + cmake --build build + --config Release + --parallel wasi-build: name: WASI build needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' + if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: submodules: true persist-credentials: false - name: Build run: | - WASI_SDK=wasi-sdk-27.0-x86_64-linux - WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-27/wasi-sdk-27.0-x86_64-linux.tar.gz + WASI_VER=33 + WASI_SDK=wasi-sdk-${WASI_VER}.0-x86_64-linux + WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VER}/${WASI_SDK}.tar.gz if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi - + WASI_SDK_PATH=$(pwd)/${WASI_SDK} FLEX_VER=2.6.4 FLEX=flex-${FLEX_VER} FLEX_URL=https://github.com/westes/flex/releases/download/v${FLEX_VER}/${FLEX}.tar.gz @@ -89,35 +95,21 @@ jobs: make && make install) - mkdir -p build - cat > build/Makefile.conf <> $GITHUB_OUTPUT + - id: set_output + run: | + if [ "${{ github.event_name }}" = "merge_group" ]; then + echo "should_skip=false" >> $GITHUB_OUTPUT + else + echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT + fi + prepare-docs: # docs builds are needed for anything on main, any tagged versions, and any tag # or branch starting with docs-preview needs: check_docs_rebuild - if: ${{ needs.check_docs_rebuild.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }} + if: ${{ needs.check_docs_rebuild.outputs.should_skip != 'true' && github.repository_owner == 'YosysHQ' }} runs-on: [self-hosted, linux, x64, fast] steps: - name: Checkout Yosys @@ -41,19 +57,19 @@ jobs: - name: Build Yosys run: | - make config-clang - echo "ENABLE_VERIFIC := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf - echo "ENABLE_CCACHE := 1" >> Makefile.conf - echo "ENABLE_HELP_SOURCE := 1" >> Makefile.conf - make -j$procs + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs - name: Prepare docs shell: bash run: - make docs/prep -j$procs TARGETS= EXTRA_TARGETS= + cmake --build build --target docs-prepare -j$procs - name: Upload artifact uses: actions/upload-artifact@v4 @@ -67,15 +83,15 @@ jobs: - name: Install doc prereqs shell: bash run: | - make docs/reqs + make -C docs reqs - name: Test build docs shell: bash run: | - make -C docs html -j$procs TARGETS= EXTRA_TARGETS= + cmake --build build --target docs-html -j$procs - name: Trigger RTDs build - if: ${{ needs.check_docs_rebuild.outputs.docs_export == 'true' }} + if: ${{ needs.check_docs_rebuild.outputs.docs_export == 'true' && github.repository == 'YosysHQ/yosys' }} uses: dfm/rtds-action@v1.1.0 with: webhook_url: ${{ secrets.RTDS_WEBHOOK_URL }} diff --git a/.github/workflows/source-vendor.yml b/.github/workflows/source-vendor.yml index 03750b05b..cdab23008 100644 --- a/.github/workflows/source-vendor.yml +++ b/.github/workflows/source-vendor.yml @@ -1,13 +1,18 @@ name: Create source archive with vendored dependencies -on: [push, workflow_dispatch] +on: + pull_request: + merge_group: + push: + branches: [ main ] + workflow_dispatch: jobs: vendor-sources: runs-on: ubuntu-latest steps: - name: Checkout repository with submodules - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: 'recursive' persist-credentials: false @@ -28,7 +33,7 @@ jobs: gzip yosys-src-vendored.tar - name: Store tarball artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: vendored-sources path: yosys-src-vendored.tar.gz diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 331c062d5..8df1fdeea 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -1,23 +1,20 @@ name: Build and run tests on: - # always test main - push: - branches: - - main - merge_group: - # test PRs pull_request: - # allow triggering tests, ignores skip check + merge_group: + #push: + # branches: [ main ] workflow_dispatch: jobs: pre_job: runs-on: ubuntu-latest outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} + should_skip: ${{ steps.set_output.outputs.should_skip }} steps: - id: skip_check + if: ${{ github.event_name != 'merge_group' }} uses: fkirc/skip-duplicate-actions@v5 with: # don't run on documentation changes @@ -26,12 +23,21 @@ jobs: # but never cancel main cancel_others: ${{ github.ref != 'refs/heads/main' }} + - id: set_output + run: | + if [ "${{ github.event_name }}" = "merge_group" ]; then + echo "should_skip=false" >> $GITHUB_OUTPUT + else + echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT + fi + pre_docs_job: runs-on: ubuntu-latest outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} + should_skip: ${{ steps.set_output.outputs.should_skip }} steps: - id: skip_check + if: ${{ github.event_name != 'merge_group' }} uses: fkirc/skip-duplicate-actions@v5 with: # don't run on readme changes @@ -40,6 +46,14 @@ jobs: # but never cancel main cancel_others: ${{ github.ref != 'refs/heads/main' }} + - id: set_output + run: | + if [ "${{ github.event_name }}" = "merge_group" ]; then + echo "should_skip=false" >> $GITHUB_OUTPUT + else + echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT + fi + build-yosys: name: Reusable build runs-on: ${{ matrix.os }} @@ -54,7 +68,7 @@ jobs: fail-fast: false steps: - name: Checkout Yosys - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true ssh-key: ${{ secrets.SSH_PRIVATE_KEY }} @@ -71,24 +85,23 @@ jobs: - name: Build shell: bash run: | - mkdir build - cd build - make -f ../Makefile config-$CC ENABLE_LTO=1 SMALL=0 ENABLE_PLUGINS=1 ENABLE_PYOSYS=0 ENABLE_CCACHE=0 ENABLE_EDITLINE=0 VERIFIC_DIR=../verific - make -f ../Makefile -j$procs ENABLE_LTO=1 SMALL=0 ENABLE_PLUGINS=1 ENABLE_PYOSYS=0 ENABLE_CCACHE=0 ENABLE_EDITLINE=0 VERIFIC_DIR=../verific - make -f ../Makefile unit-test -j$procs ENABLE_LTO=1 SMALL=0 ENABLE_PLUGINS=1 ENABLE_PYOSYS=0 ENABLE_CCACHE=0 ENABLE_EDITLINE=0 VERIFIC_DIR=../verific + rm -rf build + cmake -B build . -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release + cmake --build build -j$procs + ctest --test-dir build/tests/unit - name: Log yosys-config output run: | - ./yosys-config || true + ./build/yosys-config || true - name: Compress build shell: bash run: | cd build - tar -cvf ../build.tar share/ yosys yosys-* libyosys.so + tar -cvf ../build.tar share/ yosys yosys-* - name: Store build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: build-${{ matrix.os }} path: build.tar @@ -107,7 +120,7 @@ jobs: fail-fast: false steps: - name: Checkout Yosys - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true ssh-key: ${{ secrets.SSH_PRIVATE_KEY }} @@ -120,18 +133,19 @@ jobs: get-iverilog: true - name: Download build artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: build-${{ matrix.os }} - name: Uncompress build shell: bash - run: - tar -xvf build.tar + run: | + mkdir -p build + tar -xvf build.tar -C build - name: Log yosys-config output run: | - ./yosys-config || true + ./build/yosys-config || true - name: Build Verific run: cd verific/tclmain && make -j$procs @@ -139,7 +153,7 @@ jobs: - name: Run tests shell: bash run: | - make -j$procs vanilla-test TARGETS= EXTRA_TARGETS= CONFIG=$CC SMALL=0 ENABLE_PLUGINS=1 ENABLE_PYOSYS=0 ENABLE_CCACHE=0 ENABLE_EDITLINE=0 + make -C tests -j$procs vanilla-test - name: Report errors if: ${{ failure() }} @@ -159,7 +173,9 @@ jobs: os: [ubuntu-latest] steps: - name: Checkout Yosys - uses: actions/checkout@v4 + uses: actions/checkout@v5 + with: + persist-credentials: false - name: Setup environment uses: ./.github/actions/setup-build-env @@ -167,7 +183,7 @@ jobs: runs-on: ${{ matrix.os }} - name: Download build artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: build-${{ matrix.os }} @@ -189,15 +205,13 @@ jobs: runs-on: ${{ matrix.os }} needs: [build-yosys, pre_docs_job] if: needs.pre_docs_job.outputs.should_skip != 'true' - env: - CC: clang strategy: matrix: os: [ubuntu-latest] fail-fast: false steps: - name: Checkout Yosys - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true ssh-key: ${{ secrets.SSH_PRIVATE_KEY }} @@ -210,18 +224,19 @@ jobs: get-docs-deps: true - name: Download build artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: build-${{ matrix.os }} - name: Uncompress build shell: bash - run: - tar -xvf build.tar + run: | + mkdir -p build + tar -xvf build.tar -C build - name: Log yosys-config output run: | - ./yosys-config || true + ./build/yosys-config || true - name: Build Verific run: cd verific/tclmain && make -j$procs @@ -235,7 +250,7 @@ jobs: name: Try build docs runs-on: [self-hosted, linux, x64, fast] needs: [pre_docs_job] - if: ${{ needs.pre_docs_job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }} + if: ${{ needs.pre_docs_job.outputs.should_skip != 'true' && github.repository_owner == 'YosysHQ' }} strategy: matrix: docs-target: [html, latexpdf] @@ -253,20 +268,23 @@ jobs: - name: Build Yosys run: | - make config-clang - echo "ENABLE_CCACHE := 1" >> Makefile.conf - echo "ENABLE_HELP_SOURCE := 1" >> Makefile.conf - make -j$procs + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs - name: Install doc prereqs shell: bash run: | - make docs/reqs + make -C docs reqs - name: Build docs shell: bash run: | - make docs DOC_TARGET=${{ matrix.docs-target }} -j$procs + cmake --build build --target docs-${{ matrix.docs-target }} -j$procs - name: Store docs build artifact uses: actions/upload-artifact@v4 @@ -274,3 +292,22 @@ jobs: name: docs-build-${{ matrix.docs-target }} path: docs/build/ retention-days: 7 + + test-build-result: + runs-on: ubuntu-latest + needs: + - test-yosys + - test-cells + - test-docs + - test-docs-build + if: always() + steps: + - name: Check results + run: | + echo "Needs results: ${{ join(needs.*.result, ',') }}" + if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \ + [[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then + echo "Some jobs failed or were cancelled" + exit 1 + fi + - run: echo "All good" diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 000d1c400..3093e8dfd 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -1,23 +1,20 @@ name: Compiler testing on: - # always test main - push: - branches: - - main - merge_group: - # test PRs pull_request: - # allow triggering tests, ignores skip check + merge_group: + #push: + # branches: [ main ] workflow_dispatch: jobs: pre_job: runs-on: ubuntu-latest outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} + should_skip: ${{ steps.set_output.outputs.should_skip }} steps: - id: skip_check + if: ${{ github.event_name != 'merge_group' }} uses: fkirc/skip-duplicate-actions@v5 with: # don't run on documentation changes @@ -26,35 +23,42 @@ jobs: # but never cancel main cancel_others: ${{ github.ref != 'refs/heads/main' }} + - id: set_output + run: | + if [ "${{ github.event_name }}" = "merge_group" ]; then + echo "should_skip=false" >> $GITHUB_OUTPUT + else + echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT + fi + test-compile: runs-on: ${{ matrix.os }} needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' + if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true' env: CXXFLAGS: ${{ startsWith(matrix.compiler, 'gcc') && '-Wp,-D_GLIBCXX_ASSERTIONS' || ''}} - CC_SHORT: ${{ startsWith(matrix.compiler, 'gcc') && 'gcc' || 'clang' }} strategy: matrix: os: - ubuntu-latest compiler: # oldest supported - - 'clang-10' - - 'gcc-10' + - 'clang-14' + - 'gcc-11' # newest, make sure to update maximum standard step to match - - 'clang-19' - - 'gcc-14' + - 'clang-22' + - 'gcc-16' include: # macOS x86 - os: macos-15-intel - compiler: 'clang-19' + compiler: 'clang-22' # macOS arm - os: macos-latest - compiler: 'clang-19' + compiler: 'clang-22' fail-fast: false steps: - name: Checkout Yosys - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true persist-credentials: false @@ -69,6 +73,7 @@ jobs: uses: aminya/setup-cpp@v1 with: compiler: ${{ matrix.compiler }} + gcc: ${{ (matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang-14') && '12' || '' }} - name: Tool versions shell: bash @@ -76,17 +81,40 @@ jobs: $CC --version $CXX --version + - name: Fix clang-14 toolchain + if: matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang-14' + run: | + echo 'CXXFLAGS=--gcc-toolchain=/usr -isystem /usr/include/c++/12 -isystem /usr/include/x86_64-linux-gnu/c++/12' >> $GITHUB_ENV + # minimum standard - - name: Build C++17 + - name: Build C++20 shell: bash run: | - make config-$CC_SHORT - make -j$procs CXXSTD=c++17 compile-only + rm -rf build + cmake -B build -DCMAKE_CXX_STANDARD=20 . --fresh + cmake --build build --target yosys -j$procs # maximum standard, only on newest compilers - - name: Build C++20 - if: ${{ matrix.compiler == 'clang-19' || matrix.compiler == 'gcc-14' }} + - name: Build C++26 + if: ${{ matrix.compiler == 'clang-22' || matrix.compiler == 'gcc-16' }} shell: bash run: | - make config-$CC_SHORT - make -j$procs CXXSTD=c++20 compile-only + rm -rf build + cmake -B build -DCMAKE_CXX_STANDARD=26 . --fresh + cmake --build build --target yosys -j$procs + + test-compile-result: + runs-on: ubuntu-latest + needs: + - test-compile + if: always() + steps: + - name: Check results + run: | + echo "Needs results: ${{ join(needs.*.result, ',') }}" + if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \ + [[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then + echo "Some jobs failed or were cancelled" + exit 1 + fi + - run: echo "All good" diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index 22c725fac..6c1b7bce1 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -1,35 +1,44 @@ name: Check clang sanitizers on: - # always test main - push: - branches: - - main + pull_request: merge_group: - # ignore PRs due to time needed - # allow triggering tests, ignores skip check + #push: + # branches: [ main ] workflow_dispatch: jobs: pre_job: runs-on: ubuntu-latest outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} + should_skip: ${{ steps.set_output.outputs.should_skip }} steps: - id: skip_check + if: ${{ github.event_name != 'merge_group' }} uses: fkirc/skip-duplicate-actions@v5 with: # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' + # cancel previous builds if a new commit is pushed + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} + + - id: set_output + run: | + if [ "${{ github.event_name }}" = "merge_group" ]; then + echo "should_skip=false" >> $GITHUB_OUTPUT + else + echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT + fi run_san: name: Build and run tests runs-on: ${{ matrix.os }} needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' + if: (github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch') && needs.pre_job.outputs.should_skip != 'true' env: CC: clang - ASAN_OPTIONS: halt_on_error=1 + ASAN_OPTIONS: halt_on_error=1 detect_container_overflow=0 UBSAN_OPTIONS: halt_on_error=1 strategy: matrix: @@ -38,7 +47,7 @@ jobs: fail-fast: false steps: - name: Checkout Yosys - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true persist-credentials: false @@ -55,18 +64,20 @@ jobs: - name: Build shell: bash run: | - make config-$CC SMALL=0 ENABLE_PLUGINS=1 ENABLE_PYOSYS=0 ENABLE_CCACHE=0 ENABLE_EDITLINE=0 ENABLE_VERIFIC=0 - echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf - make -j$procs SMALL=0 ENABLE_PLUGINS=1 ENABLE_PYOSYS=0 ENABLE_CCACHE=0 ENABLE_EDITLINE=0 ENABLE_VERIFIC=0 + rm -rf build + cmake -B build . \ + -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_BUILD_TYPE=Sanitize -DSANITIZE=${{ matrix.sanitizer }} + cmake --build build -j$procs - name: Log yosys-config output run: | - ./yosys-config || true + ./build/yosys-config || true - name: Run tests shell: bash run: | - make -j$procs vanilla-test TARGETS= EXTRA_TARGETS= SMALL=0 ENABLE_PLUGINS=1 ENABLE_PYOSYS=0 ENABLE_CCACHE=0 ENABLE_EDITLINE=0 ENABLE_VERIFIC=0 + make -C tests -j$procs vanilla-test - name: Report errors if: ${{ failure() }} @@ -74,3 +85,18 @@ jobs: run: | find tests/**/*.err -print -exec cat {} \; + test-sanitizers-result: + runs-on: ubuntu-latest + needs: + - run_san + if: always() + steps: + - name: Check results + run: | + echo "Needs results: ${{ join(needs.*.result, ',') }}" + if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \ + [[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then + echo "Some jobs failed or were cancelled" + exit 1 + fi + - run: echo "All good" diff --git a/.github/workflows/test-verific-cfg.yml b/.github/workflows/test-verific-cfg.yml new file mode 100644 index 000000000..6721c0c9b --- /dev/null +++ b/.github/workflows/test-verific-cfg.yml @@ -0,0 +1,95 @@ +name: Build various Verific configurations + +on: + workflow_dispatch: + +jobs: + test-verific-cfg: + if: github.repository_owner == 'YosysHQ' + runs-on: [self-hosted, linux, x64, fast] + steps: + - name: Checkout Yosys + uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: true + - name: Runtime environment + run: | + echo "procs=$(nproc)" >> $GITHUB_ENV + + - name: verific [SV] + run: | + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_FEATURES "systemverilog" CACHE STRING "")' >> Configuration.cmake + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs + + - name: verific [VHDL] + run: | + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_FEATURES "vhdl" CACHE STRING "")' >> Configuration.cmake + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs + + - name: verific [SV + VHDL] + run: | + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_FEATURES "vhdl;systemverilog" CACHE STRING "")' >> Configuration.cmake + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs + + - name: verific [SV + HIER] + run: | + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_FEATURES "systemverilog;hier_tree" CACHE STRING "")' >> Configuration.cmake + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs + + - name: verific [VHDL + HIER] + run: | + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_FEATURES "vhdl;hier_tree" CACHE STRING "")' >> Configuration.cmake + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs + + - name: verific [SV + VHDL + HIER] + run: | + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_FEATURES "systemverilog;vhdl;hier_tree" CACHE STRING "")' >> Configuration.cmake + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs + + - name: verific [SV + VHDL + HIER + EDIF + LIBERTY] + run: | + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_FEATURES "systemverilog;vhdl;hier_tree;edif;liberty" CACHE STRING "")' >> Configuration.cmake + cmake -C Configuration.cmake -B build . + cmake --build build -j$procs diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index cd2545cc8..9143c2f19 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -1,23 +1,20 @@ name: Build and run tests with Verific (Linux) on: - # always test main - push: - branches: - - main - merge_group: - # test PRs pull_request: - # allow triggering tests, ignores skip check + merge_group: + #push: + # branches: [ main ] workflow_dispatch: jobs: - pre-job: + pre_job: runs-on: ubuntu-latest outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} + should_skip: ${{ steps.set_output.outputs.should_skip }} steps: - id: skip_check + if: ${{ github.event_name != 'merge_group' }} uses: fkirc/skip-duplicate-actions@v5 with: # don't run on documentation changes @@ -26,9 +23,17 @@ jobs: # but never cancel main cancel_others: ${{ github.ref != 'refs/heads/main' }} + - id: set_output + run: | + if [ "${{ github.event_name }}" = "merge_group" ]; then + echo "should_skip=false" >> $GITHUB_OUTPUT + else + echo "should_skip=${{ steps.skip_check.outputs.should_skip }}" >> $GITHUB_OUTPUT + fi + test-verific: - needs: pre-job - if: ${{ needs.pre-job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }} + needs: pre_job + if: ${{ needs.pre_job.outputs.should_skip != 'true' && github.repository_owner == 'YosysHQ' }} runs-on: [self-hosted, linux, x64, fast] steps: - name: Checkout Yosys @@ -39,21 +44,30 @@ jobs: - name: Runtime environment run: | echo "procs=$(nproc)" >> $GITHUB_ENV + mkdir -p "${GITHUB_WORKSPACE}/coverage" + echo "LLVM_PROFILE_FILE=${GITHUB_WORKSPACE}/coverage/coverage_%p.profraw" >> $GITHUB_ENV + echo "LLVM_PROFILE_FILE_BUFFER_SIZE=0" >> $GITHUB_ENV + + - name: Skip generating files + if: ${{ github.event_name != 'merge_group' && github.event_name != 'workflow_dispatch' }} + run: | + echo "LLVM_PROFILE_FILE=/dev/null" >> $GITHUB_ENV - name: Build Yosys run: | - make config-clang - echo "ENABLE_VERIFIC := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf - echo "ENABLE_CCACHE := 1" >> Makefile.conf - echo "ENABLE_FUNCTIONAL_TESTS := 1" >> Makefile.conf - make -j$procs ENABLE_LTO=1 + rm -rf build Configuration.cmake + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_ENABLE_COVERAGE ON CACHE BOOL "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + + cmake -C Configuration.cmake -B build . -DCMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/.local -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_BUILD_TYPE=Debug + cmake --build build -j$procs - name: Install Yosys run: | - make install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX= + cmake --build build --target install - name: Checkout SBY uses: actions/checkout@v4 @@ -68,21 +82,46 @@ jobs: - name: Run Yosys tests run: | - make -j$procs vanilla-test + make -C tests -j$procs vanilla-test - name: Run Verific specific Yosys tests run: | make -C tests/sva - cd tests/svtypes && bash run-test.sh + make -C tests/svtypes - name: Run SBY tests - if: ${{ github.ref == 'refs/heads/main' }} + if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }} run: | make -C sby run_ci + - name: Run coverage + if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }} + run: | + make -C tests coverage + make -C tests clean_coverage + + - name: Push coverage + if: ${{ github.event_name == 'merge_group' || github.event_name == 'workflow_dispatch' }} + run: | + git clone https://x-access-token:${{ secrets.REPORTS_TOKEN }}@github.com/YosysHQ/reports.git out + rm -rf out/coverage/main + mkdir -p out/coverage/main + cp -r coverage_html/* out/coverage/main/ + cd out + # find . -name "*.html" -type f -print0 | xargs -0 sed -i -z 's#\(Date:[[:space:]]*\)[^<]*\(\)#\1\2#g' + git config user.name "yosyshq-ci" + git config user.email "105224853+yosyshq-ci@users.noreply.github.com" + git add . + if ! git diff --cached --quiet; then + git commit -m "Update coverage" + git push + else + echo "No changes to commit" + fi + test-pyosys: - needs: pre-job - if: ${{ needs.pre-job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }} + needs: pre_job + if: ${{ needs.pre_job.outputs.should_skip != 'true' && github.repository_owner == 'YosysHQ' }} runs-on: [self-hosted, linux, x64, fast] steps: - name: Checkout Yosys @@ -100,21 +139,39 @@ jobs: - name: Build pyosys run: | - make config-clang - echo "ENABLE_VERIFIC := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf - echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf - echo "ENABLE_CCACHE := 1" >> Makefile.conf - echo "ENABLE_PYOSYS := 1" >> Makefile.conf - echo "PYTHON_DESTDIR := /usr/lib/python3/site-packages" >> Makefile.conf - make -j$procs + echo 'set(CMAKE_C_COMPILER clang CACHE STRING "")' >> Configuration.cmake + echo 'set(CMAKE_CXX_COMPILER clang++ CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_COMPILER_LAUNCHER ccache CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_VERIFIC_DIR "/usr/local/src/verific_lib" CACHE STRING "")' >> Configuration.cmake + echo 'set(YOSYS_WITH_PYTHON ON CACHE BOOL "")' >> Configuration.cmake + echo 'set(YOSYS_INSTALL_PYTHON ON CACHE BOOL "")' >> Configuration.cmake + cmake -C Configuration.cmake -B build . \ + -DCMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/.local \ + -DYOSYS_INSTALL_PYTHON_SITEDIR=$GITHUB_WORKSPACE/.local/usr/lib/python3/site-packages + cmake --build build -j$procs - name: Install pyosys run: | - make install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX= + cmake --build build --target install - name: Run pyosys tests run: | export PYTHONPATH=${GITHUB_WORKSPACE}/.local/usr/lib/python3/site-packages:$PYTHONPATH python3 tests/pyosys/run_tests.py + + test-verific-result: + runs-on: ubuntu-latest + needs: + - test-verific + - test-pyosys + if: always() + steps: + - name: Check results + run: | + echo "Needs results: ${{ join(needs.*.result, ',') }}" + if [[ "${{ join(needs.*.result, ',') }}" == *failure* ]] || \ + [[ "${{ join(needs.*.result, ',') }}" == *cancelled* ]]; then + echo "Some jobs failed or were cancelled" + exit 1 + fi + - run: echo "All good" diff --git a/.github/workflows/update-flake-lock.yml b/.github/workflows/update-flake-lock.yml deleted file mode 100644 index b32498baf..000000000 --- a/.github/workflows/update-flake-lock.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: update-flake-lock -on: - workflow_dispatch: # allows manual triggering - schedule: - - cron: '0 0 * * 0' # runs weekly on Sunday at 00:00 - -jobs: - lockfile: - if: github.repository == 'YosysHQ/Yosys' - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - persist-credentials: false - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main - - name: Update flake.lock - uses: DeterminateSystems/update-flake-lock@main - with: - token: ${{CI_CREATE_PR_TOKEN}} - pr-title: "Update flake.lock" # Title of PR to be created - pr-labels: | # Labels to be set on the PR - dependencies - automated diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml deleted file mode 100644 index 78d34db46..000000000 --- a/.github/workflows/version.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Bump version - -on: - workflow_dispatch: - schedule: - - cron: '0 0 * * *' - -jobs: - bump-version: - if: github.repository == 'YosysHQ/Yosys' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - submodules: true - persist-credentials: false - - name: Take last commit - id: log - run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT - - name: Bump version - if: ${{ !contains(steps.log.outputs.message, 'Bump version') }} - 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') }} - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 8e055f526..e6381a637 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -36,20 +36,18 @@ jobs: runner: "macos-15", archs: "arm64", }, - ## Windows is disabled because of an issue with compiling FFI as - ## under MinGW in the GitHub Actions environment (SHELL variable has - ## whitespace.) + ## Windows still needs to be tested. # { - # name: "Windows Server 2019", + # name: "Windows Server 2025", # family: "windows", - # runner: "windows-2019", + # runner: "windows-2025", # archs: "AMD64", # }, ] name: Build Wheels | ${{ matrix.os.name }} | ${{ matrix.os.archs }} runs-on: ${{ matrix.os.runner }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 submodules: true @@ -77,17 +75,14 @@ jobs: name: "[Windows] Flex/Bison" run: | choco install winflexbison3 - - if: ${{ matrix.os.family == 'macos' && matrix.os.archs == 'arm64' }} - name: "[macOS/arm64] Install Python 3.8 (see: https://cibuildwheel.pypa.io/en/stable/faq/#macos-building-cpython-38-wheels-on-arm64)" - uses: actions/setup-python@v5 - with: - python-version: 3.8 - name: Build wheels - uses: pypa/cibuildwheel@v2.21.1 + uses: pypa/cibuildwheel@v3.4.1 env: # * APIs not supported by PyPy # * Musllinux disabled because it increases build time from 48m to ~3h CIBW_SKIP: > + cp38* + cp39* pp* *musllinux* CIBW_ARCHS: ${{ matrix.os.archs }} @@ -104,17 +99,16 @@ jobs: OPTFLAGS=-O3 PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig MACOSX_DEPLOYMENT_TARGET=11 - makeFlags='CONFIG=clang' PATH="$PWD/bison/src:$PATH" CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh CIBW_TEST_COMMAND: python3 {project}/tests/pyosys/run_tests.py - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: python-wheels-${{ matrix.os.runner }} path: ./wheelhouse/*.whl upload_wheels: name: Upload Wheels - if: (github.repository == 'YosysHQ/Yosys') && (github.event_name == 'workflow_dispatch') + if: (github.repository == 'YosysHQ/yosys') && (github.event_name == 'workflow_dispatch') runs-on: ubuntu-latest # Specifying a GitHub environment is optional, but strongly encouraged environment: pypi @@ -123,7 +117,7 @@ jobs: id-token: write needs: build_wheels steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: path: "." pattern: python-wheels-* diff --git a/.github/workflows/wheels/_run_cibw_linux.py b/.github/workflows/wheels/_run_cibw_linux.py deleted file mode 100644 index 1e8a0f497..000000000 --- a/.github/workflows/wheels/_run_cibw_linux.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (C) 2024 Efabless Corporation -# -# 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 runs the cibuildwheel step from the wheels workflow locally. -""" - -import os -import yaml -import platform -import subprocess -from pathlib import Path - -__yosys_root__ = Path(__file__).absolute().parents[3] - -for source in ["ffi", "bison"]: - if not (__yosys_root__ / source).is_dir(): - print( - "You need to download ffi and bison in a similar manner to wheels.yml first." - ) - exit(-1) - -with open(__yosys_root__ / ".github" / "workflows" / "wheels.yml") as f: - workflow = yaml.safe_load(f) - -env = os.environ.copy() - -steps = workflow["jobs"]["build_wheels"]["steps"] -cibw_step = None -for step in steps: - if (step.get("uses") or "").startswith("pypa/cibuildwheel"): - cibw_step = step - break - -for key, value in cibw_step["env"].items(): - if key.endswith("WIN") or key.endswith("MAC"): - continue - env[key] = value - -env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS", platform.machine()) -subprocess.check_call(["cibuildwheel"], env=env) diff --git a/.github/workflows/wheels/cibw_before_all.sh b/.github/workflows/wheels/cibw_before_all.sh index 1aef650d7..6450ce273 100644 --- a/.github/workflows/wheels/cibw_before_all.sh +++ b/.github/workflows/wheels/cibw_before_all.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e -x # Build-time dependencies diff --git a/.github/workflows/wheels/cibw_before_build.sh b/.github/workflows/wheels/cibw_before_build.sh index 1ce96b291..217cb8875 100644 --- a/.github/workflows/wheels/cibw_before_build.sh +++ b/.github/workflows/wheels/cibw_before_build.sh @@ -1,9 +1,6 @@ set -e set -x -# Don't use Python objects from previous compiles -make clean-py - # DEBUG: show python3 and python3-config outputs if [ "$(uname)" != "Linux" ]; then # https://github.com/pypa/cibuildwheel/issues/2021 diff --git a/.gitignore b/.gitignore index a8b04ac45..bb1a08bba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ ## user config /Makefile.conf +/Configuration.cmake +/CMakeUserPresets.json ## homebrew /Brewfile.lock.json @@ -49,7 +51,9 @@ /tests/unit/objtest/ /tests/ystests /build +/build-* /result +/result-* /dist # pyosys @@ -65,10 +69,10 @@ /viz.js # other -/coverage.info +/yosys.profdata +/coverage /coverage_html - # these really belong in global gitignore since they're not specific to this project but rather to user tool choice # but too many people don't have a global gitignore configured: # https://docs.github.com/en/get-started/git-basics/ignoring-files#configuring-ignored-files-for-all-repositories-on-your-computer @@ -86,3 +90,5 @@ __pycache__ /qtcreator.creator /qtcreator.creator.user /compile_commands.json +/.direnv +/.envrc diff --git a/Brewfile b/Brewfile index c55bdcf5b..5f3b1c15f 100644 --- a/Brewfile +++ b/Brewfile @@ -6,10 +6,11 @@ brew "git" brew "graphviz" brew "pkg-config" brew "python3" +brew "tcl-tk" brew "uv" brew "xdot" brew "bash" -brew "llvm@20" +brew "llvm" brew "lld" brew "googletest" diff --git a/CHANGELOG b/CHANGELOG index e345a8514..61b221bc9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,65 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.62 .. Yosys 0.63-dev +Yosys 0.66 .. Yosys 0.67-dev -------------------------- +Yosys 0.65 .. Yosys 0.66 +-------------------------- + * Various + - C++ compiler with C++20 support is required. + - Please be aware that next release will also + migrate to CMake build system. + + * New commands and options + - Added "lattice_dsp_nexus" pass for Lattice Nexus + DSP inference. + - Added "-scopename" option to "synth_gatemate" pass + that is propagated to "flatten". + +Yosys 0.64 .. Yosys 0.65 +-------------------------- + * New commands and options + - Added "arith_tree" pass to convert add/sub/macc chains + to carry-save adder trees. + - Removed "-force" option from "share" pass. + + * Various + - read_verilog: support positional assignment patterns + for unpacked arrays. + +Yosys 0.63 .. Yosys 0.64 +-------------------------- + * New commands and options + - Added "synth_analogdevices" pass to support synthesis + for Analog Devices FPGAs. + + * Various + - Removed rarely-used options from ABC/ABC9. + - Removed "-S" option from "abc" pass. + - Removed "-fast" option from "abc9" and "abc9_exe". + - Calls to "abc -g AND -fast" to map logic to + AND-Inverter Graph form should be replaced with + "aigmap". + - The above change was made to SBY, so we recommend + updating it. + - Added hardware latch support for Gowin FPGAs. + +Yosys 0.62 .. Yosys 0.63 +-------------------------- + * Various + - Added DSP inference for Gowin GW1N and GW2A. + - Added support for subtract in preadder for Xilinx arch. + - Added infrastructure to run a sat solver as a command. + + * New commands and options + - Added "-ignore-unknown-cells" option to "equiv_induct" + and "equiv_simple" pass. + - Added "-force-params" option to "memory_libmap" pass. + - Added "-select-solver" option to "sat" pass. + - Added "-default_params" option to "write_verilog" pass. + - Added "-nodsp" option to "synth_gowin" pass. + Yosys 0.61 .. Yosys 0.62 -------------------------- * Various diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..3deacd232 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,577 @@ +if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR) + set(rm "rm -rf") + if (WIN32) + set(rm "del /s /q") + endif() + message(FATAL_ERROR + "In-tree builds are not supported. Instead, run:\n" + "${rm} CMakeCache.txt CMakeFiles ; cmake -B build " + ) +endif() + +cmake_minimum_required(VERSION 3.27) +project(yosys LANGUAGES C CXX) + +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +include(CMakeDependentOption) +include(FeatureSummary) +include(CheckPIESupported) + +include(Condition) +include(CheckLibcFeatures) +include(PkgConfig) +include(PmgenCommand) +include(YosysVersion) +include(YosysInstallDirs) +include(YosysConfigScript) +include(YosysComponent) +include(YosysLinkTarget) +include(YosysAbc) +include(YosysAbcSubmodule) +include(YosysVerific) + +# Build options. +set(YOSYS_COMPILER_LAUNCHER "" CACHE STRING "Compiler launcher (ccache, sccache)") +option(YOSYS_ENABLE_COVERAGE "Enable code coverage" OFF) +option(YOSYS_ENABLE_PROFILING "Enable instruction profiling" OFF) + +set(YOSYS_PROGRAM_PREFIX "" CACHE STRING "Name prefix for programs, libraries, and data") +set(YOSYS_COMPONENTS "everything" CACHE STRING "List of components to build (use pass names)") +option(BUILD_SHARED_LIBS "Build libyosys as a shared library" ON) + +option(YOSYS_DISABLE_THREADS "Disable threading" OFF) +set(YOSYS_ABC_EXECUTABLE "" CACHE FILEPATH + "Path to the ABC executable (empty for vendored, 'INTEGRATED-NOTFOUND' for in-process)") +option(YOSYS_WITHOUT_ABC "Disable ABC support (not recommended)" OFF) +option(YOSYS_WITHOUT_ZLIB "Disable zlib integration" OFF) +option(YOSYS_WITHOUT_LIBFFI "Disable libffi integration" OFF) +option(YOSYS_WITHOUT_READLINE "Disable readline integration" OFF) +option(YOSYS_WITHOUT_EDITLINE "Disable editline integration" OFF) +option(YOSYS_WITHOUT_TCL "Disable Tcl integration" OFF) +option(YOSYS_WITH_PYTHON "Enable Python integration" OFF) + +set(YOSYS_VERIFIC_DIR "" CACHE FILEPATH "Path to the Verific source code (empty to disable)") +set(YOSYS_VERIFIC_COMPONENTS "" CACHE STRING + "List of Verific components to link (empty for autodetect)") +set(YOSYS_VERIFIC_FEATURES "" CACHE STRING + "List of Yosys Verific frontend features to enable (empty for autodetect)") + +option(YOSYS_INSTALL_DRIVER "Install Yosys executable" ON) +option(YOSYS_INSTALL_LIBRARY "Install libyosys library" OFF) +cmake_dependent_option(YOSYS_INSTALL_PYTHON "Install Python extension module" OFF + YOSYS_WITH_PYTHON OFF) +set(YOSYS_INSTALL_PYTHON_SITEDIR "" CACHE STRING "Path to Python package installation directory") + +# This option is something of a hack to make Python wheels buildable in an environment that has +# the `Development.Module` component, but not `Development.Embed` (e.g. cibuildwheel). It is only +# present to be used in the wheel build and is not supported otherwise. +cmake_dependent_option(YOSYS_BUILD_PYTHON_ONLY "Build only Pyosys components" ON + "NOT (YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY) AND YOSYS_INSTALL_PYTHON" OFF) +mark_as_advanced(YOSYS_BUILD_PYTHON_ONLY) + +# Configure compiler. +set(CMAKE_EXPORT_COMPILE_COMMANDS YES) + +if (YOSYS_COMPILER_LAUNCHER) + set(CMAKE_C_COMPILER_LAUNCHER "${YOSYS_COMPILER_LAUNCHER}") + set(CMAKE_CXX_COMPILER_LAUNCHER "${YOSYS_COMPILER_LAUNCHER}") +endif() + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED YES) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +check_pie_supported() # opportunistically enable PIE + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(CMAKE_CXX_FLAGS_DEBUG "-Og -ggdb") + set(CMAKE_CXX_FLAGS_RELEASE "-O3") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -ggdb") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") + set(CMAKE_CXX_FLAGS_SANITIZE "-O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls") + if ("${SANITIZE}" MATCHES "memory") + set(CMAKE_CXX_FLAGS_SANITIZE "${CMAKE_CXX_FLAGS_SANITIZE} -fsanitize-memory-track-origins") + endif() + set(no_abc_options + "$<$>>,$>:-fsanitize=${SANITIZE}>" + "$<$>>:-Wall;-Wextra;-Werror=unused>" + ) + add_compile_options("${no_abc_options}") + add_link_options("${no_abc_options}") +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS_DEBUG "/Od /DEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "/O2") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/O2 /DEBUG") + set(CMAKE_CXX_FLAGS_MINSIZEREL "/Os") + add_compile_options(/Zc:__cplusplus) + add_compile_definitions( + _CRT_NONSTDC_NO_DEPRECATE + _CRT_SECURE_NO_WARNINGS + ) +else() + # We have to do this because CMake adds `-DNDEBUG` in release builds by default, and there's + # no particularly good way to prevent this without also erasing optimization flags. + # If you see this message, reproduce the block above with the flags supported by your compiler. + message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} compiler is not supported") +endif() + +if (YOSYS_ENABLE_COVERAGE) + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") + elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping") + else() + message(FATAL_ERROR "Code coverage is not supported on ${CMAKE_CXX_COMPILER_ID} compiler") + endif() +endif() + +if (YOSYS_ENABLE_PROFILING) + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") + else() + message(FATAL_ERROR "Instruction profiling is not supported on ${CMAKE_CXX_COMPILER_ID} compiler") + endif() +endif() + +if (NOT CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID) + message(FATAL_ERROR "C and C++ compilers must be provided by the same vendor") +endif() +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") +set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") +set(CMAKE_C_FLAGS_SANITIZE "${CMAKE_CXX_FLAGS_SANITIZE}") + +if (CMAKE_SYSTEM_NAME STREQUAL "WASI") + add_compile_options( + -fwasm-exceptions -mllvm -wasm-use-legacy-eh=false + -D_WASI_EMULATED_PROCESS_CLOCKS + ) + add_link_options( + -fwasm-exceptions -mllvm -wasm-use-legacy-eh=false -lunwind + -lwasi-emulated-process-clocks + -Wl,--stack-first,-z,stack-size=8388608 + ) +endif() + +if (MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "16.0.0") + # GCC 15.2 sometimes refuses to construct an import directory for yosys.exe/libyosys.dll with: + # .../ld.exe: error: export ordinal too large: 67035 + # The cause is unknown. + message(WARNING "MinGW GCC is supported starting with version 16.0.0") +endif() + +# Required dependencies. +find_package(FLEX) +set_package_properties(FLEX PROPERTIES + URL "https://github.com/westes/flex" + DESCRIPTION "The Fast Lexical Analyzer" + PURPOSE "Compiling the Verilog lexer" + TYPE REQUIRED +) + +find_package(BISON) +set_package_properties(BISON PROPERTIES + URL "https://www.gnu.org/software/bison/" + DESCRIPTION "The Yacc-compatible Parser Generator" + PURPOSE "Compiling the Verilog parser" + TYPE REQUIRED +) + +find_package(Python3 3.7 COMPONENTS Interpreter) +set_package_properties(Python3 PROPERTIES + URL "https://www.python.org/" + DESCRIPTION "Dynamic programming language (Interpreter)" + PURPOSE "Generating data files\n Running external SMT2 solvers" + TYPE REQUIRED +) + +# Optional dependencies. +check_glob() +check_system() +check_popen() +find_package(Threads QUIET) +check_pthread_create() +find_package(Dlfcn QUIET) + +find_package(PkgConfig) +set_package_properties(PkgConfig PROPERTIES + URL "https://www.freedesktop.org/wiki/Software/pkg-config/" + DESCRIPTION "Library metadata manager" + PURPOSE "Discovering dependencies" + TYPE RECOMMENDED +) + +pkg_config_import(zlib) +set_package_properties(zlib PROPERTIES + URL "https://github.com/madler/zlib" + DESCRIPTION "A massively spiffy yet delicately unobtrusive compression library" + PURPOSE "Handling Gzip and FST file formats" +) + +pkg_config_import(libffi) +set_package_properties(libffi PROPERTIES + URL "https://sourceware.org/libffi/" + DESCRIPTION "A Portable Foreign Function Interface Library" + PURPOSE "Implementing Verilog DPI-C" +) + +pkg_config_import(editline MODULES libedit) +set_package_properties(editline PROPERTIES + URL "https://www.thrysoee.dk/editline/" + DESCRIPTION "Line editing and history library (BSD)" + PURPOSE "Enhancing the command prompt" + TYPE RECOMMENDED +) + +pkg_config_import(readline) +set_package_properties(readline PROPERTIES + URL "https://tiswww.case.edu/php/chet/readline/rltop.html" + DESCRIPTION "Line editing and history library (GPL)" + PURPOSE "Enhancing the command prompt" + TYPE RECOMMENDED +) + +# See https://core.tcl-lang.org/tips/doc/trunk/tip/538.md +pkg_config_import(tcl MODULES tcl) +set_package_properties(tcl PROPERTIES + URL "https://www.tcl-lang.org/" + DESCRIPTION "Dynamic programming language" + PURPOSE "Parsing SDC constraint files\n Binding Yosys API" +) + +if (tcl_FOUND) + get_target_property(tcl_options PkgConfig::tcl INTERFACE_COMPILE_OPTIONS) + if (tcl_options MATCHES "TCL_WITH_EXTERNAL_TOMMATH") + pkg_config_import(libtommath) + set_package_properties(libtommath PROPERTIES + URL "https://www.libtom.net/LibTomMath/" + DESCRIPTION "Multiple-precision integer library" + PURPOSE "Required by this build of Tcl" + TYPE REQUIRED + ) + # Unfortunately the pkg-config file for Tcl includes libtommath as a private dependency, + # while it should be public since it is exposed in the public API and necessary for its use. + target_link_libraries(PkgConfig::tcl INTERFACE PkgConfig::libtommath) + else() + # Vendored within Tcl itself. + set(libtommath_FOUND TRUE) + endif() +endif() + +if (YOSYS_WITH_PYTHON) + find_package(Python3Devel REQUIRED) + set_property(GLOBAL PROPERTY _CMAKE_Python3Devel_REQUIRED_VERSION "== ${Python3_VERSION}") + set_package_properties(Python3Devel PROPERTIES + URL "https://www.python.org/" + DESCRIPTION "Dynamic programming language (Embedding)" + PURPOSE "Binding Yosys API" + ) + + find_package(PyosysEnv REQUIRED) + set_package_properties(PyosysEnv PROPERTIES + DESCRIPTION "Pyosys wrapper generator environment" + PURPOSE "Either 'uv' or 'pybind11>3,<4 cxxheaderparser'" + ) +endif() + +find_package(GTest) +set_package_properties(GTest PROPERTIES + URL "https://google.github.io/googletest/" + DESCRIPTION "C++ testing and mocking framework by Google" + PURPOSE "Running unit tests" + TYPE RECOMMENDED +) + +# Configure features based on dependency availability. +message(VERBOSE "Conditional features:") +condition(YOSYS_ENABLE_GLOB HAVE_GLOB) +condition(YOSYS_ENABLE_SPAWN HAVE_SYSTEM AND HAVE_POPEN) +condition(YOSYS_ENABLE_THREADS Threads_FOUND AND HAVE_PTHREAD_CREATE AND NOT YOSYS_DISABLE_THREADS) +condition(YOSYS_ENABLE_PLUGINS Dlfcn_FOUND) +condition(YOSYS_ENABLE_ABC NOT YOSYS_WITHOUT_ABC) +condition(YOSYS_ENABLE_ZLIB zlib_FOUND AND NOT YOSYS_WITHOUT_ZLIB) +condition(YOSYS_ENABLE_LIBFFI Dlfcn_FOUND AND libffi_FOUND AND NOT YOSYS_WITHOUT_LIBFFI) +condition(YOSYS_ENABLE_READLINE readline_FOUND AND NOT YOSYS_WITHOUT_READLINE) +condition(YOSYS_ENABLE_EDITLINE editline_FOUND AND NOT YOSYS_WITHOUT_EDITLINE AND NOT YOSYS_ENABLE_READLINE) +condition(YOSYS_ENABLE_TCL tcl_FOUND AND libtommath_FOUND AND NOT YOSYS_WITHOUT_TCL) +condition(YOSYS_ENABLE_PYTHON Python3Devel_FOUND AND PyosysEnv_FOUND AND YOSYS_WITH_PYTHON) +condition(YOSYS_ENABLE_VERIFIC YOSYS_VERIFIC_DIR AND zlib_FOUND) + +# Describe dependencies and features +# CMake 4.0 would let us use proper conditions, but that's too new for now. +add_feature_info(have_glob YOSYS_ENABLE_GLOB "Glob expansion in filenames") +add_feature_info(have_spawn YOSYS_ENABLE_SPAWN "Passes that invoke external tools") +add_feature_info(have_threads YOSYS_ENABLE_THREADS "Multithreaded netlist operations") +add_feature_info(have_plugins YOSYS_ENABLE_PLUGINS "Dynamically loadable binary plugins") +add_feature_info(with_abc YOSYS_ENABLE_ABC "Production-quality logic synthesis flow") +add_feature_info(with_zlib YOSYS_ENABLE_ZLIB "Transparent Gzip decompression and FST file format support") +add_feature_info(with_libffi YOSYS_ENABLE_LIBFFI "Verilog DPI-C foreign function interface") +add_feature_info(with_readline YOSYS_ENABLE_READLINE "Using readline for prompt editing and history") +add_feature_info(with_editline YOSYS_ENABLE_EDITLINE "Using editline for prompt editing and history") +add_feature_info(with_tcl YOSYS_ENABLE_TCL "Tcl scripting and SDC parsing") +add_feature_info(with_python YOSYS_ENABLE_PYTHON "Python scripting and embedding") +add_feature_info(with_verific YOSYS_ENABLE_VERIFIC "Verific frontend integration") +message(STATUS "") +feature_summary(WHAT PACKAGES_FOUND + DEFAULT_DESCRIPTION) +feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND + DEFAULT_DESCRIPTION QUIET_ON_EMPTY FATAL_ON_MISSING_REQUIRED_PACKAGES +) +feature_summary(WHAT PACKAGES_NOT_FOUND + DEFAULT_DESCRIPTION QUIET_ON_EMPTY +) +feature_summary(WHAT ENABLED_FEATURES + DEFAULT_DESCRIPTION QUIET_ON_EMPTY) +feature_summary(WHAT DISABLED_FEATURES + DEFAULT_DESCRIPTION QUIET_ON_EMPTY) + +# Describe project version. +yosys_extract_version() + +# Describe ABC integration. +if (YOSYS_ENABLE_ABC AND NOT YOSYS_ENABLE_SPAWN AND NOT YOSYS_ABC_EXECUTABLE STREQUAL "INTEGRATED-NOTFOUND") + message(WARNING "ABC support on this platform forces -DYOSYS_ABC_EXECUTABLE=INTEGRATED-NOTFOUND") + set(YOSYS_ABC_EXECUTABLE "INTEGRATED-NOTFOUND" CACHE FILEPATH "" FORCE) +endif() + +set(YOSYS_LINK_ABC 0) +if (YOSYS_ENABLE_ABC) + if (NOT YOSYS_ABC_EXECUTABLE AND NOT YOSYS_SKIP_ABC_SUBMODULE_CHECK) + yosys_check_abc_submodule() + endif() + if (YOSYS_ABC_EXECUTABLE STREQUAL "INTEGRATED-NOTFOUND") + set(YOSYS_LINK_ABC 1) + message(STATUS "Building ABC: (integrated)") + elseif (YOSYS_ABC_EXECUTABLE STREQUAL "") + set(abc_filename ${YOSYS_PROGRAM_PREFIX}yosys-abc${CMAKE_EXECUTABLE_SUFFIX}) + message(STATUS "Building ABC: ${YOSYS_INSTALL_FULL_BINDIR}/${abc_filename}") + else() + message(STATUS "External ABC: ${YOSYS_ABC_EXECUTABLE}") + endif() +endif() + +# Ensure invalid dependencies fail at configuration time, not link time. +set(CMAKE_LINK_LIBRARIES_ONLY_TARGETS ON) + +# Pseudo-library that injects common compilation options into every Yosys component. +add_library(yosys_common INTERFACE) +target_compile_definitions(yosys_common INTERFACE + _YOSYS_ + $<$:DEBUG> +) +target_include_directories(yosys_common INTERFACE + ${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} +) +if (SANITIZE) + target_compile_options(yosys_common INTERFACE + ${sanitize_options} + ) +endif() + +# Two pseudo-components used for dependency tracking only. +yosys_core(essentials BOOTSTRAP) +yosys_core(everything BOOTSTRAP) + +# All of the source code. +add_subdirectory(libs) +add_subdirectory(kernel) +add_subdirectory(passes) +add_subdirectory(frontends) +add_subdirectory(backends) +add_subdirectory(techlibs) +if (YOSYS_ENABLE_PYTHON) + add_subdirectory(pyosys) +endif() + +# ABC submodule. +if (YOSYS_ENABLE_ABC AND NOT YOSYS_ABC_EXECUTABLE) + set(YOSYS_ABC_INSTALL NO) + if (YOSYS_ABC_EXECUTABLE STREQUAL "" AND (YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY)) + set(YOSYS_ABC_INSTALL YES) + endif() + yosys_abc_target(libyosys-abc yosys-abc + INSTALL_IF ${YOSYS_ABC_INSTALL} + ) +endif() + +# Compute a transitive closure of enabled components. +yosys_expand_components(library_components essentials ${YOSYS_COMPONENTS}) +if (NOT YOSYS_BUILD_PYTHON_ONLY) + yosys_expand_components(driver_components driver ${YOSYS_COMPONENTS}) +endif() + +# Main Yosys executable (compiler driver). +if (NOT YOSYS_BUILD_PYTHON_ONLY) + yosys_cxx_executable(yosys + OUTPUT_NAME yosys + INSTALL_IF ${YOSYS_INSTALL_DRIVER} + ) + yosys_link_components(yosys PRIVATE ${driver_components}) + set_property(TARGET yosys PROPERTY ENABLE_EXPORTS ON) + if (MINGW) + target_link_options(yosys PRIVATE LINKER:--export-all-symbols) + set_target_properties(yosys PROPERTIES + # Final name: `yosys.exe.a` (linked to explicitly) + IMPORT_PREFIX "" + IMPORT_SUFFIX ".exe.a" + ) + if (YOSYS_INSTALL_DRIVER) + install(FILES ${CMAKE_BINARY_DIR}/yosys.exe.a DESTINATION ${YOSYS_INSTALL_LIBDIR}) + endif() + endif() + + target_compile_options(yosys PRIVATE -fsanitize=undefined) +endif() + +# Yosys components as a library. +if (NOT YOSYS_BUILD_PYTHON_ONLY) + if (BUILD_SHARED_LIBS) + set(libyosys_type SHARED) + else() + set(libyosys_type STATIC) + endif() + yosys_cxx_library(libyosys ${libyosys_type} + OUTPUT_NAME libyosys + INSTALL_IF ${YOSYS_INSTALL_LIBRARY} + ) + yosys_link_components(libyosys PRIVATE ${library_components}) + add_library(Yosys::libyosys ALIAS libyosys) + if (MINGW) + set_target_properties(libyosys PROPERTIES + # Final name: `libyosys.dll.a` (linked to via `-lyosys`) + IMPORT_PREFIX "" + ) + endif() +endif() + +# Yosys data files (mainly headers and technological libraries). +if (YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY) + yosys_install_component_data(${library_components} DESTINATION ${YOSYS_INSTALL_DATADIR}) +endif() + +# Python binary extension (for using Yosys as a Python library). +if (YOSYS_ENABLE_PYTHON) + yosys_cxx_library(pyosys MODULE + OUTPUT_NAME pyosys + ) + yosys_link_components(pyosys PRIVATE ${library_components}) + set_target_properties(pyosys PROPERTIES EXCLUDE_FROM_ALL FALSE) # build but not install + if (YOSYS_ENABLE_ABC AND YOSYS_ABC_EXECUTABLE STREQUAL "") + add_dependencies(pyosys yosys-abc) + endif() + + if (YOSYS_INSTALL_PYTHON) + string(REPLACE "-" "_" PYOSYS_MODULE_PREFIX "${YOSYS_PROGRAM_PREFIX}") + if (YOSYS_INSTALL_PYTHON_SITEDIR STREQUAL "") + set(YOSYS_INSTALL_PYTHON_SITEDIR ${Python3_SITEARCH}) + endif() + set(pyosys_install_dir ${YOSYS_INSTALL_PYTHON_SITEDIR}/${PYOSYS_MODULE_PREFIX}pyosys) + install(FILES pyosys/modinit.py + RENAME __init__.py + DESTINATION ${pyosys_install_dir} + ) + install(FILES $ + RENAME libyosys${CMAKE_SHARED_MODULE_SUFFIX} + DESTINATION ${pyosys_install_dir} + ) + if (YOSYS_ENABLE_ABC AND YOSYS_ABC_EXECUTABLE STREQUAL "") + # If ABC is vendored it needs to be installed as a part of pyosys. + install(TARGETS yosys-abc + DESTINATION ${pyosys_install_dir} + ) + endif() + yosys_install_component_data(${library_components} DESTINATION ${pyosys_install_dir}/share) + endif() +endif() + +# Plugin build tool. +yosys_config_script(BUILD) +if (YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY) + yosys_config_script(INSTALL) +endif() + +# Configuration for Makefile-based steps. +# (The use of `${makefile_vars}` in `add_custom_{target,command}()` adds dependencies for +# all of the targets specified via `$`.) +set(makefile_vars + BUILD_DIR=${CMAKE_BINARY_DIR} + PROGRAM_PREFIX=${YOSYS_PROGRAM_PREFIX} + ABC=$,$,${YOSYS_ABC_EXECUTABLE}> + YOSYS=$ + YOSYS_CONFIG=${CMAKE_BINARY_DIR}/${YOSYS_PROGRAM_PREFIX}yosys-config + YOSYS_FILTERLIB=$<$:$> + YOSYS_SMTBMC=${CMAKE_BINARY_DIR}/${YOSYS_PROGRAM_PREFIX}yosys-smtbmc + YOSYS_WITNESS=${CMAKE_BINARY_DIR}/${YOSYS_PROGRAM_PREFIX}yosys-witness +) +set(makefile_depends + # abc is implied via $ + # yosys is implied via $ + # yosys-filterlib is implied via $ + $<$:yosys-smtbmc> + $<$:yosys-witness> +) + +if (NOT YOSYS_BUILD_PYTHON_ONLY) + # Tests. + add_subdirectory(tests/unit) + + add_custom_target(test-unit + COMMAND ${CMAKE_CTEST_COMMAND} --test-dir tests/unit --output-on-failure + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + + add_custom_target(test-vanilla + COMMAND make vanilla-test ${makefile_vars} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests + DEPENDS ${makefile_depends} + ) + + add_custom_target(test + DEPENDS test-unit test-vanilla + ) + + # Docs. + add_custom_target(docs-prepare + COMMAND make gen ${makefile_vars} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs + DEPENDS ${makefile_depends} + ) + foreach (format html latexpdf) + add_custom_target(docs-${format} + COMMAND make ${format} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs + DEPENDS docs-prepare + ) + endforeach() + add_custom_target(test-docs + COMMAND make test ${makefile_vars} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs + DEPENDS ${makefile_depends} + ) +endif() + +# Utilities. +add_custom_target(print-version + COMMAND ${CMAKE_COMMAND} -E echo ${YOSYS_VERSION} + VERBATIM +) + +yosys_expand_components(all_components everything QUIET) +list(TRANSFORM all_components PREPEND "COMMAND;${CMAKE_COMMAND};-E;echo;" OUTPUT_VARIABLE echo_all_components) +add_custom_target(print-yosys-components + ${echo_all_components} + VERBATIM +) + +math(EXPR YOSYS_VERSION_MINOR_next "${YOSYS_VERSION_MINOR} + 1") +add_custom_target(increment-minor-version + COMMAND ${CMAKE_COMMAND} -E echo + "set(YOSYS_VERSION_MAJOR ${YOSYS_VERSION_MAJOR})" + > ${CMAKE_SOURCE_DIR}/cmake/YosysVersionData.cmake + COMMAND ${CMAKE_COMMAND} -E echo + "set(YOSYS_VERSION_MINOR ${YOSYS_VERSION_MINOR_next})" + >> ${CMAKE_SOURCE_DIR}/cmake/YosysVersionData.cmake + VERBATIM +) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6eadbec31..849d1fb00 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,59 +5,11 @@ first time contributing to an open source project, please take a look at the following guide about the basics: https://opensource.guide/how-to-contribute/#orienting-yourself-to-a-new-project. -## Asking questions +Check out our [Contributing guidelines](https://yosys.readthedocs.io/en/latest/yosys_internals/extending_yosys/contributing.html) to learn the best ways to -If you have a question about how to use Yosys, please ask on our [Discourse forum](https://yosyshq.discourse.group/). -The Discourse is also a great place to ask questions about developing or -contributing to Yosys. ++ get help ++ report bugs ++ contribute code ++ review code -We have open [dev 'jour fixe' (JF) meetings](https://docs.google.com/document/d/1SapA6QAsJcsgwsdKJDgnGR2mr97pJjV4eeXg_TVJhRU/edit?usp=sharing) where developers from YosysHQ and the -community come together to discuss open issues and PRs. This is also a good -place to talk to us about how to implement larger PRs. - -## Using the issue tracker - -The [issue tracker](https://github.com/YosysHQ/yosys/issues) is used for -tracking bugs or other problems with Yosys or its documentation. It is also the -place to go for requesting new features. - -### Bug reports - -Learn more [here](https://yosyshq.readthedocs.io/projects/yosys/en/latest/yosys_internals/extending_yosys/contributing.html#reporting-bugs) about how to report bugs. We fix well-reported bugs the fastest. - -## Contributing code - -If you're adding complex functionality, or modifying core parts of Yosys, -we highly recommend discussing your motivation and approach -ahead of time on the [Discourse forum](https://yosyshq.discourse.group/). - -### Using pull requests - -If you are working on something to add to Yosys, or fix something that isn't -working quite right, -make a [pull request (PR)](https://github.com/YosysHQ/yosys/pulls). - -An open PR, even as a draft, tells everyone that you're working on it and they -don't have to. It can also be a useful way to solicit feedback on in-progress -changes. See above to find the best way to [ask us questions](#asking-questions). - -### Continuous integration - -[Continuous Integration (CI)](https://github.com/YosysHQ/yosys/actions) tools -automatically compile Yosys and run it with the full suite of tests. -If you're a first time contributor, a maintainer has to trigger a run for you. -We test on various platforms, compilers. Sanitizer builds are only tested -on the main branch. - -### Labels - -We use [labels](https://github.com/YosysHQ/yosys/labels) to help categorise -issues and PRs. If a label seems relevant to your work, please do add it; this -also includes the labels beginning with 'status-'. The 'merge-' labels are used -by maintainers for tracking and communicating which PRs are ready and pending -merge; please do not use these labels if you are not a maintainer. - - -### Coding style - -Learn more [here](https://yosys.readthedocs.io/en/latest/yosys_internals/extending_yosys/contributing.html). +If you're reading this file offline and don't have internet access, you can [read the contributing.rst file locally](docs/source/yosys_internals/extending_yosys/contributing.rst). diff --git a/Makefile b/Makefile deleted file mode 100644 index d01936be5..000000000 --- a/Makefile +++ /dev/null @@ -1,1480 +0,0 @@ - -CONFIG := none -# CONFIG := clang -# CONFIG := gcc -# CONFIG := wasi -# CONFIG := msys2-32 -# CONFIG := msys2-64 - -# features (the more the better) -ENABLE_TCL := 1 -ENABLE_ABC := 1 -ENABLE_GLOB := 1 -ENABLE_PLUGINS := 0 -ENABLE_READLINE := 0 -ENABLE_EDITLINE := 0 -ENABLE_GHDL := 0 -ENABLE_SLANG := 0 -ENABLE_VERIFIC := 1 -ENABLE_VERIFIC_SYSTEMVERILOG := 1 -ENABLE_VERIFIC_VHDL := 1 -ENABLE_VERIFIC_HIER_TREE := 1 -ENABLE_VERIFIC_SILIMATE_EXTENSIONS := 1 -ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0 -ENABLE_VERIFIC_EDIF := 0 -ENABLE_VERIFIC_LIBERTY := 0 -ENABLE_VERIFIC_UPF := 0 -ENABLE_LIBYOSYS := 0 -ENABLE_LIBYOSYS_STATIC := 0 -ENABLE_ZLIB := 1 -ENABLE_HELP_SOURCE := 0 -ENABLE_BACKTRACE := 1 - -# python wrappers -ENABLE_PYOSYS := 1 -PYOSYS_USE_UV := 0 - -# other configuration flags -ENABLE_GCOV := 0 -ENABLE_GPROF := 0 -ENABLE_DEBUG := 0 -ENABLE_LTO := 0 -ENABLE_CCACHE := 1 -# sccache is not always a drop-in replacement for ccache in practice -ENABLE_SCCACHE := 0 -ENABLE_FUNCTIONAL_TESTS := 0 -LINK_CURSES := 0 -LINK_TERMCAP := 0 -LINK_ABC := 0 -# Needed for environments that can't run executables (i.e. emscripten, wasm) -DISABLE_SPAWN := 0 -# Needed for environments that don't have proper thread support (i.e. emscripten, wasm--for now) -ENABLE_THREADS := 1 -ifeq ($(ENABLE_THREADS),1) -DISABLE_ABC_THREADS := 0 -else -DISABLE_ABC_THREADS := 1 -endif - -# UPF requires TCL -ifeq ($(ENABLE_VERIFIC_UPF),1) -ENABLE_TCL := 1 -endif - -# clang sanitizers -SANITIZER = -# SANITIZER = address -# SANITIZER = memory -# SANITIZER = undefined -# SANITIZER = cfi - -# Prefer using ENABLE_DEBUG over setting these -OPT_LEVEL := -O3 -g -GCC_LTO := -CLANG_LTO := -flto=thin - -PROGRAM_PREFIX := - -OS := $(shell uname -s) -PREFIX ?= /usr/local -INSTALL_SUDO := -ifneq ($(filter MINGW%,$(OS)),) -OS := MINGW -endif - -ifneq ($(wildcard Makefile.conf),) -include Makefile.conf -endif - -ifeq ($(ENABLE_PYOSYS),1) -ENABLE_LIBYOSYS := 1 -endif - -BINDIR := $(PREFIX)/bin -LIBDIR := $(PREFIX)/lib/$(PROGRAM_PREFIX)yosys -DATDIR := $(PREFIX)/share/$(PROGRAM_PREFIX)yosys - -EXE = -OBJS = -GENFILES = -EXTRA_OBJS = -EXTRA_TARGETS = -TARGETS = $(PROGRAM_PREFIX)yosys$(EXE) $(PROGRAM_PREFIX)yosys-config - -PRETTY = 1 -SMALL = 1 - -all: top-all - -YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) -VPATH := $(YOSYS_SRC) - -# Unit test -UNITESTPATH := $(YOSYS_SRC)/tests/unit - -export CXXSTD ?= c++17 -CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include -LIBS := $(LIBS) -lstdc++ -lm -PLUGIN_LINKFLAGS := -PLUGIN_LIBS := -EXE_LINKFLAGS := -EXE_LIBS := -ifeq ($(OS), MINGW) -EXE_LINKFLAGS := -Wl,--export-all-symbols -Wl,--out-implib,libyosys_exe.a -PLUGIN_LINKFLAGS += -L"$(LIBDIR)" -PLUGIN_LIBS := -lyosys_exe -endif - -ifeq ($(ENABLE_HELP_SOURCE),1) -CXXFLAGS += -DYOSYS_ENABLE_HELP_SOURCE -endif - -PKG_CONFIG ?= pkg-config -SED ?= sed -BISON ?= bison -STRIP ?= strip -AWK ?= awk - -ifeq ($(OS), Linux) -LIBS += -ldw # SILIMATE: support for backward-cpp -CXXFLAGS += -I/usr/include/libdwarf/ -DBACKWARD_HAS_DW # SILIMATE: support for backward-cpp -endif - -ifeq ($(OS), Darwin) -PLUGIN_LINKFLAGS += -undefined dynamic_lookup -LINKFLAGS += -rdynamic - -# homebrew search paths -ifneq ($(shell :; command -v brew),) -BREW_PREFIX := $(shell brew --prefix)/opt -$(info $$BREW_PREFIX is [${BREW_PREFIX}]) -CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include -LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib -PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) -PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk@8/lib/pkgconfig:$(PKG_CONFIG_PATH) -export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) -export LIBRARY_PATH := $(BREW_PREFIX)/dwarfutils/lib:$(BREW_PREFIX)/libelf/lib:$(LIBRARY_PATH) - -# macports search paths -else ifneq ($(shell :; command -v port),) -PORT_PREFIX := $(patsubst %/bin/port,%,$(shell :; command -v port)) -CXXFLAGS += -I$(PORT_PREFIX)/include -LINKFLAGS += -L$(PORT_PREFIX)/lib -PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH) -export PATH := $(PORT_PREFIX)/bin:$(PATH) -endif - -else -LINKFLAGS += -rdynamic -ifneq ($(OS), OpenBSD) -LIBS += -lrt -endif -endif - -ifeq ($(OS), Haiku) -# Allow usage of non-posix vasprintf, mkstemps functions -CXXFLAGS += -D_DEFAULT_SOURCE -endif - -YOSYS_VER := 0.62+55 -YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) -YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2) -YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'.' -f3) -CXXFLAGS += -DYOSYS_VER=\\"$(YOSYS_VER)\\" \ - -DYOSYS_MAJOR=$(YOSYS_MAJOR) \ - -DYOSYS_MINOR=$(YOSYS_MINOR) \ - -DYOSYS_COMMIT=$(YOSYS_COMMIT) - -# Note: We arrange for .gitcommit to contain the (short) commit hash in -# tarballs generated with git-archive(1) using .gitattributes. The git repo -# will have this file in its unexpanded form tough, in which case we fall -# back to calling git directly. -TARBALL_GIT_REV := $(shell cat $(YOSYS_SRC)/.gitcommit) -ifneq ($(findstring Format:,$(TARBALL_GIT_REV)),) -GIT_REV := $(shell cd .. && git rev-parse --short=9 HEAD || echo UNKNOWN) -GIT_DIRTY := $(shell cd .. && git diff --exit-code --quiet 2>/dev/null; if [ $$? -ne 0 ]; then echo "-dirty"; fi) -else -GIT_REV := $(TARBALL_GIT_REV) -GIT_DIRTY := "" -endif - -OBJS = kernel/version_$(GIT_REV).o - -bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 7326bb7.. | wc -l`/;" Makefile - -ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) OPTFLAGS="-g -O3" - -# set ABCEXTERNAL = to use an external ABC instance -# Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set. -ABCEXTERNAL ?= - -define newline - - -endef - -ifneq ($(wildcard Makefile.conf),) -# don't echo Makefile.conf contents when invoked to print source versions -ifeq ($(findstring echo-,$(MAKECMDGOALS)),) -$(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$,;' < Makefile.conf | tr -d '\n' | sed 's,\$$--\$$$$,,'))) -endif -include Makefile.conf -endif - -PYTHON_EXECUTABLE ?= $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) -ifeq ($(ENABLE_PYOSYS),1) -PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" -PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") -PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.) - -PYTHON_CONFIG := $(PYTHON_EXECUTABLE)-config -PYTHON_CONFIG_FOR_EXE := $(PYTHON_CONFIG) -PYTHON_CONFIG_EMBED_AVAILABLE ?= $(shell $(PYTHON_EXECUTABLE)-config --embed --libs > /dev/null && echo 1) -ifeq ($(PYTHON_CONFIG_EMBED_AVAILABLE),1) -PYTHON_CONFIG_FOR_EXE := $(PYTHON_CONFIG) --embed -endif - -PYTHON_DESTDIR := $(shell $(PYTHON_EXECUTABLE) -c "import site; print(site.getsitepackages()[-1]);") - -# Reload Makefile.conf to override python specific variables if defined -ifneq ($(wildcard Makefile.conf),) -include Makefile.conf -endif - -endif - -ABC_ARCHFLAGS = "" -ifeq ($(OS), OpenBSD) -ABC_ARCHFLAGS += "-DABC_NO_RLIMIT" -endif - -# This gets overridden later. -LTOFLAGS := $(GCC_LTO) - -ifeq ($(CONFIG),clang) -CXX = clang++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ifeq ($(ENABLE_LTO),1) -LINKFLAGS += -fuse-ld=lld -endif -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)" -LTOFLAGS := $(CLANG_LTO) - -ifneq ($(SANITIZER),) -$(info [Clang Sanitizer] $(SANITIZER)) -CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER) -LINKFLAGS += -g -fsanitize=$(SANITIZER) -ifneq ($(findstring memory,$(SANITIZER)),) -CXXFLAGS += -fPIE -fsanitize-memory-track-origins -LINKFLAGS += -fPIE -fsanitize-memory-track-origins -endif -ifneq ($(findstring cfi,$(SANITIZER)),) -CXXFLAGS += -flto -LINKFLAGS += -flto -LTOFLAGS = -endif -endif - -else ifeq ($(CONFIG),gcc) -CXX = g++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)" - -else ifeq ($(CONFIG),gcc-static) -LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -static -LIBS := $(filter-out -lrt,$(LIBS)) -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(CXX)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \ - ARCHFLAGS="-DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING=1 -Wno-unused-but-set-variable $(ARCHFLAGS)" ABC_USE_NO_READLINE=1 -ifeq ($(DISABLE_ABC_THREADS),1) -ABCMKARGS += "ABC_USE_NO_PTHREADS=1" -endif - -else ifeq ($(CONFIG),wasi) -ifeq ($(WASI_SDK),) -CXX = clang++ -AR = llvm-ar -RANLIB = llvm-ranlib -WASIFLAGS := -target wasm32-wasi $(WASIFLAGS) -else -CXX = $(WASI_SDK)/bin/clang++ -AR = $(WASI_SDK)/bin/ar -RANLIB = $(WASI_SDK)/bin/ranlib -endif -CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) $(OPT_LEVEL) -D_WASI_EMULATED_PROCESS_CLOCKS $(filter-out -fPIC,$(CXXFLAGS)) -LINKFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LINKFLAGS)) -LIBS := -lwasi-emulated-process-clocks $(filter-out -lrt,$(LIBS)) -ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)" -ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -D_WASI_EMULATED_PROCESS_CLOCKS -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -DABC_NO_RLIMIT" -ABCMKARGS += OPTFLAGS="-Os" -EXE = .wasm - -DISABLE_SPAWN := 1 - -ifeq ($(ENABLE_ABC),1) -LINK_ABC := 1 -ENABLE_THREADS := 0 -DISABLE_ABC_THREADS := 1 -endif - -else ifeq ($(CONFIG),msys2-32) -CXX = i686-w64-mingw32-g++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s -LIBS := $(filter-out -lrt,$(LIBS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DWIN32 -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" -EXE = .exe - -else ifeq ($(CONFIG),msys2-64) -CXX = x86_64-w64-mingw32-g++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s -LIBS := $(filter-out -lrt,$(LIBS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DWIN32 -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" -EXE = .exe - -else ifeq ($(CONFIG),none) -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)" -LTOFLAGS = - -else -$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, msys2-32, msys2-64, none) -endif - - -ifeq ($(ENABLE_LTO),1) -CXXFLAGS += $(LTOFLAGS) -LINKFLAGS += $(LTOFLAGS) -endif - -ifeq ($(ENABLE_LIBYOSYS),1) -TARGETS += libyosys.so -ifeq ($(ENABLE_LIBYOSYS_STATIC),1) -TARGETS += libyosys.a -endif -endif - -PY_WRAPPER_FILE = pyosys/wrappers - -# running make clean on just those and then recompiling saves a lot of -# time when running cibuildwheel -PYTHON_OBJECTS = pyosys/wrappers.o kernel/drivers.o kernel/yosys.o passes/cmds/plugin.o - -ifeq ($(ENABLE_PYOSYS),1) -# python-config --ldflags includes -l and -L, but LINKFLAGS is only -L - -UV_ENV := -ifeq ($(PYOSYS_USE_UV),1) -UV_ENV := uv run --no-project --with 'pybind11>3,<4' --with 'cxxheaderparser' -endif - -LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags)) -LIBS += $(shell $(PYTHON_CONFIG) --libs) -EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs)) -PYBIND11_INCLUDE ?= $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) -m pybind11 --includes) -CXXFLAGS += -I$(PYBIND11_INCLUDE) -DYOSYS_ENABLE_PYTHON -CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DYOSYS_ENABLE_PYTHON - -OBJS += $(PY_WRAPPER_FILE).o -PY_GEN_SCRIPT = $(YOSYS_SRC)/pyosys/generator.py -PY_WRAP_INCLUDES := $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes) -endif # ENABLE_PYOSYS - -ifeq ($(ENABLE_BACKTRACE),1) -ifeq ($(OS), Darwin) -LIBS += -ldwarf -lelf -CXXFLAGS += -I/usr/include/libdwarf/ -DBACKWARD_HAS_DWARF -endif -endif - -ifeq ($(ENABLE_READLINE),1) -CXXFLAGS += -DYOSYS_ENABLE_READLINE -ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) -CXXFLAGS += -I/usr/local/include -endif -LIBS += -lreadline -ifeq ($(LINK_CURSES),1) -LIBS += -lcurses -ABCMKARGS += "ABC_READLINE_LIBRARIES=-lcurses -lreadline" -endif -ifeq ($(LINK_TERMCAP),1) -LIBS += -ltermcap -ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap" -endif -else -ifeq ($(ENABLE_EDITLINE),1) -CXXFLAGS += -DYOSYS_ENABLE_EDITLINE -LIBS += -ledit -endif -ABCMKARGS += "ABC_USE_NO_READLINE=1" -endif - -ifeq ($(DISABLE_ABC_THREADS),1) -ABCMKARGS += "ABC_USE_NO_PTHREADS=1" -endif - -ifeq ($(LINK_ABC),1) -ABCMKARGS += "ABC_USE_PIC=1" -endif - -ifeq ($(DISABLE_SPAWN),1) -CXXFLAGS += -DYOSYS_DISABLE_SPAWN -endif - -ifeq ($(ENABLE_PLUGINS),1) -CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS -ifeq ($(OS), MINGW) -CXXFLAGS += -Ilibs/dlfcn-win32 -endif -LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD MINGW)) -LIBS += -ldl -endif -endif - -ifeq ($(ENABLE_GLOB),1) -CXXFLAGS += -DYOSYS_ENABLE_GLOB -endif - -ifeq ($(ENABLE_ZLIB),1) -CXXFLAGS += -DYOSYS_ENABLE_ZLIB -LIBS += -lz -endif - - -ifeq ($(ENABLE_TCL),1) -TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") -ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) -# BSDs usually use tcl8.6, but the lib is named "libtcl86" -TCL_INCLUDE ?= /usr/local/include/$(TCL_VERSION) -TCL_LIBS ?= -l$(subst .,,$(TCL_VERSION)) -else -TCL_INCLUDE ?= /usr/include/$(TCL_VERSION) -TCL_LIBS ?= -l$(TCL_VERSION) -endif - -CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL -LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo $(TCL_LIBS)) -ifneq (,$(findstring TCL_WITH_EXTERNAL_TOMMATH,$(CXXFLAGS))) -LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libtommath || echo) -endif -endif - -ifeq ($(ENABLE_GCOV),1) -CXXFLAGS += --coverage -LINKFLAGS += --coverage -endif - -ifeq ($(ENABLE_GPROF),1) -CXXFLAGS += -pg -LINKFLAGS += -pg -endif - -ifeq ($(ENABLE_DEBUG),1) -CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS)) -STRIP := -endif - -ifeq ($(ENABLE_THREADS),1) -CXXFLAGS += -DYOSYS_ENABLE_THREADS -LIBS += -lpthread -endif - -ifeq ($(ENABLE_ABC),1) -CXXFLAGS += -DYOSYS_ENABLE_ABC -ifeq ($(LINK_ABC),1) -CXXFLAGS += -DYOSYS_LINK_ABC -ifeq ($(DISABLE_ABC_THREADS),0) -LIBS += -lpthread -endif -else -ifeq ($(ABCEXTERNAL),) -TARGETS := $(PROGRAM_PREFIX)yosys-abc$(EXE) $(TARGETS) -endif -ifeq ($(DISABLE_SPAWN),1) -$(error ENABLE_ABC=1 requires either LINK_ABC=1 or DISABLE_SPAWN=0) -endif -endif -endif - -ifeq ($(ENABLE_GHDL),1) -GHDL_PREFIX ?= $(PREFIX) -GHDL_INCLUDE_DIR ?= $(GHDL_PREFIX)/include -GHDL_LIB_DIR ?= $(GHDL_PREFIX)/lib -CXXFLAGS += -I$(GHDL_INCLUDE_DIR) -DYOSYS_ENABLE_GHDL -LIBS += $(GHDL_LIB_DIR)/libghdl.a $(file <$(GHDL_LIB_DIR)/libghdl.link) -endif - -LIBS_VERIFIC = -ifeq ($(ENABLE_VERIFIC),1) -VERIFIC_DIR ?= ./verific -VERIFIC_COMPONENTS ?= database util containers pct -ifeq ($(ENABLE_VERIFIC_HIER_TREE),1) -VERIFIC_COMPONENTS += hier_tree -CXXFLAGS += -DVERIFIC_HIER_TREE_SUPPORT -else -ifneq ($(wildcard $(VERIFIC_DIR)/hier_tree),) -VERIFIC_COMPONENTS += hier_tree -endif -endif -ifeq ($(ENABLE_VERIFIC_SYSTEMVERILOG),1) -VERIFIC_COMPONENTS += verilog -CXXFLAGS += -DVERIFIC_SYSTEMVERILOG_SUPPORT -else -ifneq ($(wildcard $(VERIFIC_DIR)/verilog),) -VERIFIC_COMPONENTS += verilog -endif -endif -ifeq ($(ENABLE_VERIFIC_VHDL),1) -VERIFIC_COMPONENTS += vhdl -CXXFLAGS += -DVERIFIC_VHDL_SUPPORT -else -ifneq ($(wildcard $(VERIFIC_DIR)/vhdl),) -VERIFIC_COMPONENTS += vhdl -endif -endif -ifeq ($(ENABLE_VERIFIC_EDIF),1) -VERIFIC_COMPONENTS += edif -CXXFLAGS += -DVERIFIC_EDIF_SUPPORT -endif -ifeq ($(ENABLE_VERIFIC_LIBERTY),1) -VERIFIC_COMPONENTS += synlib -CXXFLAGS += -DVERIFIC_LIBERTY_SUPPORT -endif -ifeq ($(ENABLE_VERIFIC_UPF),1) -VERIFIC_COMPONENTS += hdl_file_sort verilog_nl -VERIFIC_COMPONENTS += commands upf -CXXFLAGS += -DVERIFIC_UPF_SUPPORT -endif -VERIFIC_SILIMATE_OBJS = -ifeq ($(ENABLE_VERIFIC_SILIMATE_EXTENSIONS),1) -CXXFLAGS += -DSILIMATE_VERIFIC_EXTENSIONS -VERIFIC_SILIMATE_OBJS += $(VERIFIC_DIR)/database/DBSilimate.o -VERIFIC_SILIMATE_OBJS += $(VERIFIC_DIR)/verilog/VeriSilimate.o -VERIFIC_SILIMATE_OBJS += $(VERIFIC_DIR)/util/UtilSilimate.o -# Override flex/bison-generated parser/lexer so local edits to -# verific/verilog/verilog.l and verific/verilog/verilog.y are reflected in -# the linked yosys binary. Without these, the precompiled veri_lex.o and -# veri_yacc.o inside verilog-{mac,linux}.raw.a win and edits silently have -# no effect. -VERIFIC_SILIMATE_OBJS += $(VERIFIC_DIR)/verilog/veri_yacc.o -VERIFIC_SILIMATE_OBJS += $(VERIFIC_DIR)/verilog/veri_lex.o -endif -ifeq ($(ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS),1) -VERIFIC_COMPONENTS += extensions -CXXFLAGS += -DYOSYSHQ_VERIFIC_EXTENSIONS -else -# YosysHQ flavor of Verific always needs extensions linked -# if disabled it will just not be invoked but parts -# are required for it to initialize properly -ifneq ($(wildcard $(VERIFIC_DIR)/extensions),) -VERIFIC_COMPONENTS += extensions -OBJS += kernel/log_compat.o -endif -endif -CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC -ifeq ($(OS), Darwin) -LIBS_VERIFIC += $(foreach comp,$(patsubst %,$(VERIFIC_DIR)/%/*-mac.a,$(VERIFIC_COMPONENTS)),-Wl,-force_load $(comp)) -lz -else -LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -Wl,--no-whole-archive -lz -endif - -# Silimate extension override objects: compile .cpp files. On macOS we patch the -# pre-compiled archives (from .raw.a originals) to localize overridden symbols, -# since the macOS linker doesn't support --allow-multiple-definition. On Linux -# we just copy .raw.a to .a and rely on --allow-multiple-definition so override -# .o definitions (linked before the archives) take precedence. -ifeq ($(ENABLE_VERIFIC_SILIMATE_EXTENSIONS),1) - -# Bison emits both veri_yacc.cpp and veri_yacc.h from a single invocation. -# We pick veri_yacc.cpp as the canonical generated target because it is -# gitignored (verific/.gitignore) and therefore always missing on a fresh -# checkout - which guarantees the bison rule fires. veri_yacc.h is -# committed to the verific repo so it always exists with an up-to-date -# mtime, which means making it the canonical target would silently skip -# bison and leave the gitignored veri_yacc.cpp missing on the next compile. -# Anything that conceptually depends on the regenerated veri_yacc.h's -# contents instead depends on veri_yacc.cpp here, since both are generated -# atomically by the single bison invocation. -$(VERIFIC_DIR)/verilog/veri_yacc.cpp: $(VERIFIC_DIR)/verilog/verilog.y - $(P) cd $(VERIFIC_DIR)/verilog && bison -l -p veri --defines=veri_yacc.h -o veri_yacc.cpp verilog.y - -$(VERIFIC_DIR)/verilog/veri_lex.cpp: $(VERIFIC_DIR)/verilog/verilog.l - $(P) cd $(VERIFIC_DIR)/verilog && flex -Pveri -L -overi_lex.cpp verilog.l - -# The Silimate .cpp files (and the flex/bison outputs) include veri_tokens.h -# transitively, which pulls in veri_yacc.h. Token IDs are baked into the -# compiled .o files, so they must be rebuilt whenever veri_yacc.h changes, -# even if the .cpp source itself is untouched. We track that via a -# dependency on veri_yacc.cpp (which is regenerated together with the -# header). Without this dependency, editing only verilog.y silently leaves -# veri_lex.o (and the others) holding stale token IDs that no longer match -# the regenerated veri_yacc.o, which manifests as "my overrides in -# verilog.y/verilog.l aren't showing up". $(CXXFLAGS) already contains -I -# for the verific component dirs. -$(VERIFIC_DIR)/verilog/veri_yacc.o: $(VERIFIC_DIR)/verilog/veri_yacc.cpp - $(P) $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) -c $< - -$(VERIFIC_DIR)/verilog/veri_lex.o: $(VERIFIC_DIR)/verilog/veri_lex.cpp $(VERIFIC_DIR)/verilog/veri_yacc.cpp - $(P) $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) -c $< - -$(VERIFIC_DIR)/database/DBSilimate.o: $(VERIFIC_DIR)/database/DBSilimate.cpp $(VERIFIC_DIR)/verilog/veri_yacc.cpp - $(P) $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) -c $< - -$(VERIFIC_DIR)/verilog/VeriSilimate.o: $(VERIFIC_DIR)/verilog/VeriSilimate.cpp $(VERIFIC_DIR)/verilog/veri_yacc.cpp - $(P) $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) -c $< - -$(VERIFIC_DIR)/util/UtilSilimate.o: $(VERIFIC_DIR)/util/UtilSilimate.cpp $(VERIFIC_DIR)/verilog/veri_yacc.cpp - $(P) $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) -c $< - -ifeq ($(OS), Darwin) -VERIFIC_LIB_OS_SUFFIX = mac - -$(VERIFIC_DIR)/_override_syms.txt: $(VERIFIC_SILIMATE_OBJS) - $(Q) nm -gjU $^ | grep '^_' | sort -u > $@ - -$(VERIFIC_DIR)/database/database-mac.a: $(VERIFIC_DIR)/database/database-mac.raw.a $(VERIFIC_DIR)/_override_syms.txt - $(Q) cp $< $@ - $(Q) mkdir -p $@_patch_tmp - $(Q) cd $@_patch_tmp && ar x $(CURDIR)/$@ && \ - for o in *.o; do \ - nm -gjU "$$o" 2>/dev/null | grep -Fx -f $(CURDIR)/$(VERIFIC_DIR)/_override_syms.txt > "$$o.syms" 2>/dev/null; \ - if [ -s "$$o.syms" ]; then nmedit -R "$$o.syms" "$$o"; fi; \ - rm -f "$$o.syms"; \ - done - $(Q) ar rcs $@ $@_patch_tmp/*.o - $(Q) rm -rf $@_patch_tmp - -$(VERIFIC_DIR)/verilog/verilog-mac.a: $(VERIFIC_DIR)/verilog/verilog-mac.raw.a $(VERIFIC_DIR)/_override_syms.txt - $(Q) cp $< $@ - $(Q) mkdir -p $@_patch_tmp - $(Q) cd $@_patch_tmp && ar x $(CURDIR)/$@ && \ - for o in *.o; do \ - nm -gjU "$$o" 2>/dev/null | grep -Fx -f $(CURDIR)/$(VERIFIC_DIR)/_override_syms.txt > "$$o.syms" 2>/dev/null; \ - if [ -s "$$o.syms" ]; then nmedit -R "$$o.syms" "$$o"; fi; \ - rm -f "$$o.syms"; \ - done - $(Q) ar rcs $@ $@_patch_tmp/*.o - $(Q) rm -rf $@_patch_tmp - -$(VERIFIC_DIR)/util/util-mac.a: $(VERIFIC_DIR)/util/util-mac.raw.a $(VERIFIC_DIR)/_override_syms.txt - $(Q) cp $< $@ - $(Q) mkdir -p $@_patch_tmp - $(Q) cd $@_patch_tmp && ar x $(CURDIR)/$@ && \ - for o in *.o; do \ - nm -gjU "$$o" 2>/dev/null | grep -Fx -f $(CURDIR)/$(VERIFIC_DIR)/_override_syms.txt > "$$o.syms" 2>/dev/null; \ - if [ -s "$$o.syms" ]; then nmedit -R "$$o.syms" "$$o"; fi; \ - rm -f "$$o.syms"; \ - done - $(Q) ar rcs $@ $@_patch_tmp/*.o - $(Q) rm -rf $@_patch_tmp - -else -VERIFIC_LIB_OS_SUFFIX = linux -LINKFLAGS += -Wl,--allow-multiple-definition - -$(VERIFIC_DIR)/database/database-linux.a: $(VERIFIC_DIR)/database/database-linux.raw.a - $(Q) cp $< $@ - -$(VERIFIC_DIR)/verilog/verilog-linux.a: $(VERIFIC_DIR)/verilog/verilog-linux.raw.a - $(Q) cp $< $@ - -$(VERIFIC_DIR)/util/util-linux.a: $(VERIFIC_DIR)/util/util-linux.raw.a - $(Q) cp $< $@ - -endif - -VERIFIC_PATCHED_ARCHIVES = \ - $(VERIFIC_DIR)/database/database-$(VERIFIC_LIB_OS_SUFFIX).a \ - $(VERIFIC_DIR)/verilog/verilog-$(VERIFIC_LIB_OS_SUFFIX).a \ - $(VERIFIC_DIR)/util/util-$(VERIFIC_LIB_OS_SUFFIX).a - -endif # ENABLE_VERIFIC_SILIMATE_EXTENSIONS - -endif - -ifeq ($(ENABLE_CCACHE),1) -CXX := ccache $(CXX) -else -ifeq ($(ENABLE_SCCACHE),1) -CXX := sccache $(CXX) -endif -endif - -define add_share_file -EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) -$(subst //,/,$(1)/$(notdir $(2))): $(2) - $$(P) mkdir -p $(1) - $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(notdir $(2))) -endef - -define add_share_file_and_rename -EXTRA_TARGETS += $(subst //,/,$(1)/$(3)) -$(subst //,/,$(1)/$(3)): $(2) - $$(P) mkdir -p $(1) - $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(3)) -endef - -define add_gen_share_file -EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) -$(subst //,/,$(1)/$(notdir $(2))): $(2) - $$(P) mkdir -p $(1) - $$(Q) cp $(2) $(subst //,/,$(1)/$(notdir $(2))) -endef - -define add_include_file -$(eval $(call add_share_file,$(dir share/include/$(1)),$(1))) -endef - -define add_extra_objs -EXTRA_OBJS += $(1) -.SECONDARY: $(1) -endef - -ifeq ($(PRETTY), 1) -P_STATUS = 0 -P_OFFSET = 0 -P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) $(PROGRAM_PREFIX)yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }')) -P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) $(PROGRAM_PREFIX)yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%] -P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@"; -Q = @ -S = -s -else -P_SHOW = -> -P = -Q = -S = -endif - -$(eval $(call add_include_file,kernel/binding.h)) -$(eval $(call add_include_file,kernel/bitpattern.h)) -$(eval $(call add_include_file,kernel/cellaigs.h)) -$(eval $(call add_include_file,kernel/celledges.h)) -$(eval $(call add_include_file,kernel/celltypes.h)) -$(eval $(call add_include_file,kernel/consteval.h)) -$(eval $(call add_include_file,kernel/constids.inc)) -$(eval $(call add_include_file,kernel/cost.h)) -$(eval $(call add_include_file,kernel/drivertools.h)) -$(eval $(call add_include_file,kernel/ff.h)) -$(eval $(call add_include_file,kernel/ffinit.h)) -$(eval $(call add_include_file,kernel/ffmerge.h)) -$(eval $(call add_include_file,kernel/fmt.h)) -ifeq ($(ENABLE_ZLIB),1) -$(eval $(call add_include_file,kernel/fstdata.h)) -endif -$(eval $(call add_include_file,kernel/gzip.h)) -$(eval $(call add_include_file,kernel/hashlib.h)) -$(eval $(call add_include_file,kernel/io.h)) -$(eval $(call add_include_file,kernel/json.h)) -$(eval $(call add_include_file,kernel/log.h)) -$(eval $(call add_include_file,kernel/macc.h)) -$(eval $(call add_include_file,kernel/modtools.h)) -$(eval $(call add_include_file,kernel/mem.h)) -$(eval $(call add_include_file,kernel/qcsat.h)) -$(eval $(call add_include_file,kernel/register.h)) -$(eval $(call add_include_file,kernel/rtlil.h)) -$(eval $(call add_include_file,kernel/satgen.h)) -$(eval $(call add_include_file,kernel/scopeinfo.h)) -$(eval $(call add_include_file,kernel/sexpr.h)) -$(eval $(call add_include_file,kernel/sigtools.h)) -$(eval $(call add_include_file,kernel/threading.h)) -$(eval $(call add_include_file,kernel/timinginfo.h)) -$(eval $(call add_include_file,kernel/utils.h)) -$(eval $(call add_include_file,kernel/yosys.h)) -$(eval $(call add_include_file,kernel/yosys_common.h)) -$(eval $(call add_include_file,kernel/yw.h)) -$(eval $(call add_include_file,libs/ezsat/ezsat.h)) -$(eval $(call add_include_file,libs/ezsat/ezminisat.h)) -$(eval $(call add_include_file,libs/ezsat/ezcmdline.h)) -ifeq ($(ENABLE_ZLIB),1) -$(eval $(call add_include_file,libs/fst/fstapi.h)) -endif -$(eval $(call add_include_file,libs/sha1/sha1.h)) -$(eval $(call add_include_file,libs/json11/json11.hpp)) -$(eval $(call add_include_file,passes/fsm/fsmdata.h)) -$(eval $(call add_include_file,passes/techmap/libparse.h)) -$(eval $(call add_include_file,frontends/blif/blifparse.h)) -$(eval $(call add_include_file,backends/rtlil/rtlil_backend.h)) - -OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o kernel/io.o kernel/gzip.o -OBJS += kernel/rtlil_bufnorm.o -OBJS += kernel/log_help.o -ifeq ($(ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS),1) -OBJS += kernel/log_compat.o -endif -OBJS += kernel/binding.o kernel/tclapi.o -OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o -OBJS += kernel/drivertools.o kernel/functional.o kernel/threading.o -ifeq ($(ENABLE_ZLIB),1) -OBJS += kernel/fstdata.o -endif -ifeq ($(ENABLE_PLUGINS),1) -ifeq ($(OS), MINGW) -OBJS += libs/dlfcn-win32/dlfcn.o -endif -endif - -kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' -kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"' -ifeq ($(ENABLE_ABC),1) -ifneq ($(ABCEXTERNAL),) -kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' -endif -endif - -OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o -OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o - -OBJS += libs/sha1/sha1.o - -OBJS += libs/json11/json11.o - -OBJS += libs/ezsat/ezsat.o -OBJS += libs/ezsat/ezminisat.o -OBJS += libs/ezsat/ezcmdline.o - -OBJS += libs/minisat/Options.o -OBJS += libs/minisat/SimpSolver.o -OBJS += libs/minisat/Solver.o -OBJS += libs/minisat/System.o - -ifeq ($(ENABLE_ZLIB),1) -OBJS += libs/fst/fstapi.o -OBJS += libs/fst/fastlz.o -OBJS += libs/fst/lz4.o -endif - -ifeq ($(ENABLE_SLANG),1) -OBJS += yosys-slang/build/*.o -OBJS += yosys-slang/build/slang*/lib*/*.a -endif - -techlibs/%_pm.h: passes/pmgen/pmgen.py techlibs/%.pmg - $(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p $(notdir $*) $(filter-out $<,$^) - -OBJS += libs/subcircuit/subcircuit.o - -ifneq ($(SMALL),1) - -include $(YOSYS_SRC)/frontends/*/Makefile.inc -include $(YOSYS_SRC)/passes/*/Makefile.inc -include $(YOSYS_SRC)/backends/*/Makefile.inc -include $(YOSYS_SRC)/techlibs/*/Makefile.inc - -else - -include $(YOSYS_SRC)/frontends/verilog/Makefile.inc -ifeq ($(ENABLE_VERIFIC),1) -include $(YOSYS_SRC)/frontends/verific/Makefile.inc -endif -include $(YOSYS_SRC)/frontends/rtlil/Makefile.inc -include $(YOSYS_SRC)/frontends/ast/Makefile.inc -include $(YOSYS_SRC)/frontends/blif/Makefile.inc - -include $(YOSYS_SRC)/frontends/liberty/Makefile.inc -include $(YOSYS_SRC)/frontends/json/Makefile.inc -include $(YOSYS_SRC)/passes/equiv/Makefile.inc - -include $(YOSYS_SRC)/passes/cmds/Makefile.inc -include $(YOSYS_SRC)/passes/silimate/Makefile.inc - -OBJS += passes/sat/recover_names.o -OBJS += passes/sat/sim.o -OBJS += passes/sat/sat.o -OBJS += passes/sat/miter.o -OBJS += passes/sat/async2sync.o -OBJS += passes/sat/clk2fflogic.o -OBJS += passes/techmap/extract.o -OBJS += passes/techmap/extract_reduce.o -OBJS += passes/techmap/alumacc.o -OBJS += passes/techmap/pmuxtree.o -OBJS += passes/techmap/bmuxmap.o -OBJS += passes/techmap/demuxmap.o -OBJS += passes/techmap/muxcover.o -OBJS += passes/techmap/aigmap.o -OBJS += passes/techmap/attrmap.o -OBJS += passes/techmap/clockgate.o -OBJS += passes/techmap/dfflegalize.o -OBJS += passes/techmap/dffunmap.o -OBJS += passes/techmap/zinit.o - -include $(YOSYS_SRC)/passes/hierarchy/Makefile.inc -include $(YOSYS_SRC)/passes/memory/Makefile.inc -include $(YOSYS_SRC)/passes/pmgen/Makefile.inc - -include $(YOSYS_SRC)/passes/proc/Makefile.inc -include $(YOSYS_SRC)/passes/opt/Makefile.inc -include $(YOSYS_SRC)/passes/techmap/Makefile.inc - -include $(YOSYS_SRC)/backends/verilog/Makefile.inc -include $(YOSYS_SRC)/backends/rtlil/Makefile.inc -include $(YOSYS_SRC)/backends/json/Makefile.inc -include $(YOSYS_SRC)/backends/blif/Makefile.inc - -include $(YOSYS_SRC)/techlibs/common/Makefile.inc - -endif - -ifeq ($(LINK_ABC),1) -OBJS += $(PROGRAM_PREFIX)yosys-libabc.a -endif - -# prevent the CXXFLAGS set by this Makefile from reaching abc/Makefile, -# especially the -MD flag which will break the build when CXX is clang -unexport CXXFLAGS - -top-all: $(TARGETS) $(EXTRA_TARGETS) - @echo "" - @echo " Build successful." - @echo "" - -.PHONY: compile-only -compile-only: $(OBJS) $(GENFILES) $(EXTRA_TARGETS) - @echo "" - @echo " Compile successful." - @echo "" - -.PHONY: share -share: $(EXTRA_TARGETS) - @echo "" - @echo " Share directory created." - @echo "" - -$(PROGRAM_PREFIX)yosys$(EXE): $(OBJS) $(VERIFIC_SILIMATE_OBJS) $(VERIFIC_PATCHED_ARCHIVES) - $(P) $(CXX) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LINKFLAGS) $(LINKFLAGS) $(OBJS) $(VERIFIC_SILIMATE_OBJS) $(EXE_LIBS) $(LIBS) $(LIBS_VERIFIC) - -libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) $(VERIFIC_SILIMATE_OBJS) $(VERIFIC_PATCHED_ARCHIVES) -ifeq ($(OS), Darwin) - $(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,libyosys.so $(LINKFLAGS) $(filter-out kernel/driver.o,$(OBJS)) $(VERIFIC_SILIMATE_OBJS) $(LIBS) $(LIBS_VERIFIC) -else - $(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $(filter-out kernel/driver.o,$(OBJS)) $(VERIFIC_SILIMATE_OBJS) $(LIBS) $(LIBS_VERIFIC) -endif - -libyosys.a: $(filter-out kernel/driver.o,$(OBJS)) - $(P) $(AR) rcs $@ $^ - -%.o: %.cc - $(Q) mkdir -p $(dir $@) - $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< - -%.pyh: %.h - $(Q) mkdir -p $(dir $@) - $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(CXX) $(CXXFLAGS) -x c++ -o $@ -E -P - - -ifeq ($(ENABLE_PYOSYS),1) -$(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT) pyosys/wrappers_tpl.cc $(PY_WRAP_INCLUDES) pyosys/hashlib.h - $(Q) mkdir -p $(dir $@) - $(P) $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) $(PY_WRAPPER_FILE).cc -endif - -%.o: %.cpp - $(Q) mkdir -p $(dir $@) - $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< - -YOSYS_GIT_STR := $(GIT_REV)$(GIT_DIRTY) -YOSYS_COMPILER := $(notdir $(CXX)) $(shell $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)) -YOSYS_VER_STR := Preqorsor $(YOSYS_VER) (git sha1 $(YOSYS_GIT_STR), $(YOSYS_COMPILER)) - -kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile - $(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc - $(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; const char *yosys_git_hash_str=\"$(YOSYS_GIT_STR)\"; }" > kernel/version_$(GIT_REV).cc - -ifeq ($(ENABLE_VERIFIC),1) -CXXFLAGS_NOVERIFIC = $(foreach v,$(CXXFLAGS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v))) -LIBS_NOVERIFIC = $(foreach v,$(LIBS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v))) -else -CXXFLAGS_NOVERIFIC = $(CXXFLAGS) -LIBS_NOVERIFIC = $(LIBS) -endif - -$(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in $(YOSYS_SRC)/Makefile - $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -Ilibs/dlfcn-win32,,$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC))))#;' \ - -e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LINKFLAGS@#$(strip $(LINKFLAGS) $(PLUGIN_LINKFLAGS))#;' -e 's#@LIBS@#$(strip $(LIBS_NOVERIFIC) $(PLUGIN_LIBS))#;' \ - -e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > $(PROGRAM_PREFIX)yosys-config - $(Q) chmod +x $(PROGRAM_PREFIX)yosys-config - -.PHONY: check-git-abc - -check-git-abc: - @if [ ! -d "$(YOSYS_SRC)/abc" ] && git -C "$(YOSYS_SRC)" status >/dev/null 2>&1; then \ - echo "Error: The 'abc' directory does not exist."; \ - echo "Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \ - exit 1; \ - elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^ '; then \ - exit 0; \ - elif [ -f "$(YOSYS_SRC)/abc/.gitcommit" ] && ! grep -q '\$$Format:%[hH]\$$' "$(YOSYS_SRC)/abc/.gitcommit"; then \ - echo "'abc' comes from a tarball. Continuing."; \ - exit 0; \ - elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^+'; then \ - echo "'abc' submodule does not match expected commit."; \ - echo "Run 'git submodule update' to check out the correct version."; \ - echo "Note: If testing a different version of abc, call 'git commit abc' in the Yosys source directory to update the expected commit."; \ - exit 1; \ - elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^U'; then \ - echo "'abc' submodule has merge conflicts."; \ - echo "Please resolve merge conflicts before continuing."; \ - exit 1; \ - elif [ -f "$(YOSYS_SRC)/abc/.gitcommit" ] && grep -q '\$$Format:%[hH]\$$' "$(YOSYS_SRC)/abc/.gitcommit"; then \ - echo "Error: 'abc' is not configured as a git submodule."; \ - echo "To resolve this:"; \ - echo "1. Back up your changes: Save any modifications from the 'abc' directory to another location."; \ - echo "2. Remove the existing 'abc' directory: Delete the 'abc' directory and all its contents."; \ - echo "3. Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \ - echo "4. Reapply your changes: Move your saved changes back to the 'abc' directory, if necessary."; \ - exit 1; \ - elif ! git -C "$(YOSYS_SRC)" status >/dev/null 2>&1; then \ - echo "$(realpath $(YOSYS_SRC)) is not configured as a git repository, and 'abc' folder is missing."; \ - echo "If you already have ABC, set 'ABCEXTERNAL' make variable to point to ABC executable."; \ - echo "Otherwise, download release archive 'yosys.tar.gz' from https://github.com/YosysHQ/yosys/releases."; \ - echo " ('Source code' archive does not contain submodules.)"; \ - exit 1; \ - else \ - echo "Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \ - exit 1; \ - fi - -.git-abc-submodule-hash: FORCE - @new=$$(cd abc 2>/dev/null && git rev-parse HEAD 2>/dev/null || echo none); \ - old=$$(cat .git-abc-submodule-hash 2>/dev/null || echo none); \ - if [ "$$new" != "$$old" ]; then \ - echo "$$new" > .git-abc-submodule-hash; \ - fi - -abc/abc$(EXE) abc/libabc.a: .git-abc-submodule-hash | check-git-abc - @if [ "$$(cd abc 2>/dev/null && git rev-parse HEAD 2>/dev/null)" != "$$(cat ../.git-abc-submodule-hash 2>/dev/null || echo none)" ]; then \ - rm -f abc/abc$(EXE); \ - fi - $(P) - $(Q) mkdir -p abc && $(MAKE) -C $(PROGRAM_PREFIX)abc -f "$(realpath $(YOSYS_SRC)/abc/Makefile)" ABCSRC="$(realpath $(YOSYS_SRC)/abc/)" $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc",PROG="abc$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc.a) - -$(PROGRAM_PREFIX)yosys-abc$(EXE): abc/abc$(EXE) - $(P) cp $< $(PROGRAM_PREFIX)yosys-abc$(EXE) - -$(PROGRAM_PREFIX)yosys-libabc.a: abc/libabc.a - $(P) cp $< $(PROGRAM_PREFIX)yosys-libabc.a - -ifneq ($(SEED),) -SEEDOPT="-S $(SEED)" -else -SEEDOPT="" -endif - -ifneq ($(ABCEXTERNAL),) -ABCOPT="-A $(ABCEXTERNAL)" -else -ABCOPT="" -endif - -# Tests that generate .mk with tests/gen-tests-makefile.sh -MK_TEST_DIRS = -MK_TEST_DIRS += tests/arch/anlogic -MK_TEST_DIRS += tests/arch/ecp5 -MK_TEST_DIRS += tests/arch/efinix -MK_TEST_DIRS += tests/arch/gatemate -MK_TEST_DIRS += tests/arch/gowin -MK_TEST_DIRS += tests/arch/ice40 -MK_TEST_DIRS += tests/arch/intel_alm -MK_TEST_DIRS += tests/arch/machxo2 -MK_TEST_DIRS += tests/arch/microchip -MK_TEST_DIRS += tests/arch/nanoxplore -MK_TEST_DIRS += tests/arch/nexus -MK_TEST_DIRS += tests/arch/quicklogic/pp3 -MK_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f -MK_TEST_DIRS += tests/arch/xilinx -MK_TEST_DIRS += tests/bugpoint -MK_TEST_DIRS += tests/opt -MK_TEST_DIRS += tests/sat -MK_TEST_DIRS += tests/sdc -MK_TEST_DIRS += tests/sim -MK_TEST_DIRS += tests/svtypes -MK_TEST_DIRS += tests/techmap -MK_TEST_DIRS += tests/various -MK_TEST_DIRS += tests/rtlil -ifeq ($(ENABLE_VERIFIC),1) -ifneq ($(YOSYS_NOVERIFIC),1) -MK_TEST_DIRS += tests/verific -endif -endif -MK_TEST_DIRS += tests/verilog - -# Tests that don't generate .mk -SH_TEST_DIRS = -SH_TEST_DIRS += tests/simple -SH_TEST_DIRS += tests/simple_abc9 -SH_TEST_DIRS += tests/hana -SH_TEST_DIRS += tests/asicworld -# SH_TEST_DIRS += tests/realmath -SH_TEST_DIRS += tests/share -SH_TEST_DIRS += tests/opt_share -SH_TEST_DIRS += tests/fsm -SH_TEST_DIRS += tests/memlib -SH_TEST_DIRS += tests/bram -SH_TEST_DIRS += tests/svinterfaces -SH_TEST_DIRS += tests/xprop -SH_TEST_DIRS += tests/select -SH_TEST_DIRS += tests/peepopt -SH_TEST_DIRS += tests/proc -SH_TEST_DIRS += tests/blif -SH_TEST_DIRS += tests/arch -SH_TEST_DIRS += tests/rpc -SH_TEST_DIRS += tests/memfile -SH_TEST_DIRS += tests/fmt -SH_TEST_DIRS += tests/cxxrtl -SH_TEST_DIRS += tests/liberty -SH_TEST_DIRS += tests/silimate -ifeq ($(ENABLE_FUNCTIONAL_TESTS),1) -SH_TEST_DIRS += tests/functional -endif - -# Tests that don't generate .mk and need special args -SH_ABC_TEST_DIRS = -SH_ABC_TEST_DIRS += tests/memories -SH_ABC_TEST_DIRS += tests/aiger -SH_ABC_TEST_DIRS += tests/alumacc - -# seed-tests/ is a dummy string, not a directory -.PHONY: seed-tests -seed-tests: $(SH_TEST_DIRS:%=seed-tests/%) -.PHONY: seed-tests/% -seed-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS) - +cd $* && bash run-test.sh $(SEEDOPT) - +@echo "...passed tests in $*" - -# abcopt-tests/ is a dummy string, not a directory -.PHONY: abcopt-tests -abcopt-tests: $(SH_ABC_TEST_DIRS:%=abcopt-tests/%) -abcopt-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS) - +cd $* && bash run-test.sh $(ABCOPT) $(SEEDOPT) - +@echo "...passed tests in $*" - -# makefile-tests/ is a dummy string, not a directory -.PHONY: makefile-tests -makefile-tests: $(MK_TEST_DIRS:%=makefile-tests/%) -# this target actually emits .mk files -%.mk: - +cd $(dir $*) && bash run-test.sh -# this one spawns submake on each -makefile-tests/%: %/run-test.mk $(TARGETS) $(EXTRA_TARGETS) - $(MAKE) -C $* -f run-test.mk - +@echo "...passed tests in $*" - -test: vanilla-test unit-test - -vanilla-test: makefile-tests abcopt-tests seed-tests - @echo "" - @echo " Passed \"make vanilla-test\"." -ifeq ($(ENABLE_VERIFIC),1) -ifeq ($(YOSYS_NOVERIFIC),1) - @echo " Ran tests without verific support due to YOSYS_NOVERIFIC=1." -endif -endif - @echo "" - -VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all - -vgtest: $(TARGETS) $(EXTRA_TARGETS) - $(VALGRIND) ./yosys -p 'setattr -mod -unset top; synth' $$( ls tests/simple/*.v | grep -v repwhile.v ) - @echo "" - @echo " Passed \"make vgtest\"." - @echo "" - -vloghtb: $(TARGETS) $(EXTRA_TARGETS) - +cd tests/vloghtb && bash run-test.sh - @echo "" - @echo " Passed \"make vloghtb\"." - @echo "" - -ystests: $(TARGETS) $(EXTRA_TARGETS) - rm -rf tests/ystests - git clone https://github.com/YosysHQ/yosys-tests.git tests/ystests - +$(MAKE) PATH="$$PWD:$$PATH" -C tests/ystests - @echo "" - @echo " Finished \"make ystests\"." - @echo "" - -# Unit test -unit-test: libyosys.so - @$(MAKE) -f $(UNITESTPATH)/Makefile CXX="$(CXX)" CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" \ - CXXFLAGS="$(CXXFLAGS)" LINKFLAGS="$(LINKFLAGS)" LIBS="$(LIBS)" ROOTPATH="$(CURDIR)" - -clean-unit-test: - @$(MAKE) -f $(UNITESTPATH)/Makefile clean - -install-dev: $(PROGRAM_PREFIX)yosys-config share - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) - $(INSTALL_SUDO) cp $(PROGRAM_PREFIX)yosys-config $(DESTDIR)$(BINDIR) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) - $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. - -install: $(TARGETS) $(EXTRA_TARGETS) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) - $(INSTALL_SUDO) cp $(filter-out libyosys.so libyosys.a,$(TARGETS)) $(DESTDIR)$(BINDIR) -ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),) - if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys; fi -endif -ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),) - if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc; fi -endif -ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),) - if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib; fi -endif - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) - $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. -ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) - $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/ - if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so; fi -ifeq ($(ENABLE_LIBYOSYS_STATIC),1) - $(INSTALL_SUDO) cp libyosys.a $(DESTDIR)$(LIBDIR)/ -endif -ifeq ($(ENABLE_PYOSYS),1) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys - $(INSTALL_SUDO) cp $(YOSYS_SRC)/pyosys/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py - $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so - $(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys -ifeq ($(ENABLE_ABC),1) -ifeq ($(ABCEXTERNAL),) - $(INSTALL_SUDO) cp $(PROGRAM_PREFIX)yosys-abc$(EXE) $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc$(EXE) -endif -endif -endif -endif -ifeq ($(ENABLE_PLUGINS),1) -ifeq ($(OS), MINGW) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) - $(INSTALL_SUDO) cp libyosys_exe.a $(DESTDIR)$(LIBDIR)/ -endif -endif - -uninstall: - $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR)/,$(notdir $(TARGETS))) - $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) -ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so -ifeq ($(ENABLE_LIBYOSYS_STATIC),1) - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.a -endif -ifeq ($(ENABLE_PYOSYS),1) - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py - $(INSTALL_SUDO) rmdir $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys -endif -endif - -docs/source/generated/cmds.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) - $(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cmds-json $@' - -docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) - $(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@' - -docs/source/generated/%.cc: backends/%.cc - $(Q) mkdir -p $(@D) - $(Q) cp $< $@ - -# diff returns exit code 1 if the files are different, but it's not an error -docs/source/generated/functional/rosette.diff: backends/functional/smtlib.cc backends/functional/smtlib_rosette.cc - $(Q) mkdir -p $(@D) - $(Q) diff -U 20 $^ > $@ || exit 0 - -PHONY: docs/gen/functional_ir -docs/gen/functional_ir: docs/source/generated/functional/smtlib.cc docs/source/generated/functional/rosette.diff - -docs/source/generated/%.log: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) - $(Q) ./$(PROGRAM_PREFIX)yosys -qQT -h '$*' -l $@ - -docs/source/generated/chformal.cc: passes/cmds/chformal.cc docs/source/generated - $(Q) cp $< $@ - -PHONY: docs/gen/chformal -docs/gen/chformal: docs/source/generated/chformal.log docs/source/generated/chformal.cc - -PHONY: docs/gen docs/usage docs/reqs -docs/gen: $(TARGETS) - $(Q) $(MAKE) -C docs gen - -docs/source/generated: - $(Q) mkdir -p docs/source/generated - -# some commands return an error and print the usage text to stderr -define DOC_USAGE_STDERR -docs/source/generated/$(1): $(TARGETS) docs/source/generated FORCE - -$(Q) ./$(PROGRAM_PREFIX)$(1) --help 2> $$@ -endef -DOCS_USAGE_STDERR := yosys-filterlib - -# The in-tree ABC (yosys-abc) is only built when ABCEXTERNAL is not set. -ifeq ($(ABCEXTERNAL),) -DOCS_USAGE_STDERR += yosys-abc -endif - -$(foreach usage,$(DOCS_USAGE_STDERR),$(eval $(call DOC_USAGE_STDERR,$(usage)))) - -# others print to stdout -define DOC_USAGE_STDOUT -docs/source/generated/$(1): $(TARGETS) docs/source/generated - $(Q) ./$(PROGRAM_PREFIX)$(1) --help > $$@ || rm $$@ -endef -DOCS_USAGE_STDOUT := yosys yosys-smtbmc yosys-witness yosys-config -$(foreach usage,$(DOCS_USAGE_STDOUT),$(eval $(call DOC_USAGE_STDOUT,$(usage)))) - -docs/usage: $(addprefix docs/source/generated/,$(DOCS_USAGE_STDOUT) $(DOCS_USAGE_STDERR)) - -docs/reqs: - $(Q) $(MAKE) -C docs reqs - -.PHONY: docs/prep -docs/prep: docs/source/generated/cells.json docs/source/generated/cmds.json docs/gen docs/usage docs/gen/functional_ir docs/gen/chformal - -DOC_TARGET ?= html -docs: docs/prep - $(Q) $(MAKE) -C docs $(DOC_TARGET) - -clean: clean-py clean-unit-test - rm -rf share - rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) - rm -f kernel/version_*.o kernel/version_*.cc -ifeq ($(ENABLE_VERIFIC),1) -ifeq ($(ENABLE_VERIFIC_SILIMATE_EXTENSIONS),1) - rm -f $(VERIFIC_SILIMATE_OBJS) $(VERIFIC_DIR)/_override_syms.txt - rm -f $(VERIFIC_PATCHED_ARCHIVES) - rm -rf $(addsuffix _patch_tmp,$(VERIFIC_PATCHED_ARCHIVES)) - rm -f $(VERIFIC_DIR)/verilog/veri_lex.cpp - rm -f $(VERIFIC_DIR)/verilog/veri_yacc.cpp $(VERIFIC_DIR)/verilog/veri_yacc.h -endif -endif - rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d - rm -rf tests/asicworld/*.out tests/asicworld/*.log - rm -rf tests/hana/*.out tests/hana/*.log - rm -rf tests/simple/*.out tests/simple/*.log - rm -rf tests/memories/*.out tests/memories/*.log tests/memories/*.dmp - rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log - rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp tests/various/temp - rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_* - rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff - rm -f tests/tools/cmp_tbdata - rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS)) - -$(MAKE) -C $(YOSYS_SRC)/docs clean - rm -rf docs/util/__pycache__ - rm -f libyosys.so - -clean-py: - rm -f $(PY_WRAPPER_FILE).inc.cc $(PY_WRAPPER_FILE).cc - rm -f $(PYTHON_OBJECTS) - rm -f *.whl - rm -f libyosys.so libyosys.a - rm -rf kernel/*.pyh - -clean-abc: - $(MAKE) -C $(YOSYS_SRC)/abc DEP= clean - rm -f $(PROGRAM_PREFIX)yosys-abc$(EXE) $(PROGRAM_PREFIX)yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a .git-abc-submodule-hash - -mrproper: clean - git clean -xdf - -coverage: - ./$(PROGRAM_PREFIX)yosys -qp 'help; help -all' - rm -rf coverage.info coverage_html - lcov --capture -d . --no-external -o coverage.info - genhtml coverage.info --output-directory coverage_html - -clean_coverage: - find . -name "*.gcda" -type f -delete - -FUNC_KERNEL := functional.cc functional.h sexpr.cc sexpr.h compute_graph.h -FUNC_INCLUDES := $(addprefix --include *,functional/* $(FUNC_KERNEL)) -coverage_functional: - rm -rf coverage.info coverage_html - lcov --capture -d backends/functional -d kernel $(FUNC_INCLUDES) --no-external -o coverage.info - genhtml coverage.info --output-directory coverage_html - -qtcreator: - echo "$(CXXFLAGS)" | grep -o '\-D[^ ]*' | tr ' ' '\n' | sed 's/-D/#define /' | sed 's/=/ /'> qtcreator.config - { for file in $(basename $(OBJS)); do \ - for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \ - done; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \); } > qtcreator.files - { echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes - touch qtcreator.creator - -VCX_DIR_NAME := yosys-win32-vcxsrc-$(YOSYS_VER) -vcxsrc: $(GENFILES) $(EXTRA_TARGETS) kernel/version_$(GIT_REV).cc - rm -rf $(VCX_DIR_NAME){,.zip} - cp -f kernel/version_$(GIT_REV).cc kernel/version.cc - set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \ - echo "Analyse: $$f" >&2; cpp -std=c++17 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt - echo "libs/fst/fst_win_unistd.h" >> srcfiles.txt - echo "kernel/version.cc" >> srcfiles.txt - bash misc/create_vcxsrc.sh $(VCX_DIR_NAME) $(YOSYS_VER) - zip $(VCX_DIR_NAME)/genfiles.zip $(GENFILES) kernel/version.cc - zip -r $(VCX_DIR_NAME).zip $(VCX_DIR_NAME)/ - rm -f srcfiles.txt kernel/version.cc - -config-clean: clean - rm -f Makefile.conf - -config-clang: clean - echo 'CONFIG := clang' > Makefile.conf - -config-gcc: clean - echo 'CONFIG := gcc' > Makefile.conf - -config-gcc-static: clean - echo 'CONFIG := gcc-static' > Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - echo 'ENABLE_READLINE := 0' >> Makefile.conf - echo 'ENABLE_TCL := 0' >> Makefile.conf - -config-wasi: clean - echo 'CONFIG := wasi' > Makefile.conf - echo 'ENABLE_TCL := 0' >> Makefile.conf - echo 'ENABLE_ABC := 0' >> Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - echo 'ENABLE_READLINE := 0' >> Makefile.conf - echo 'ENABLE_ZLIB := 0' >> Makefile.conf - -config-msys2-32: clean - echo 'CONFIG := msys2-32' > Makefile.conf - echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf - -config-msys2-64: clean - echo 'CONFIG := msys2-64' > Makefile.conf - echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf - -config-gcov: clean - echo 'CONFIG := gcc' > Makefile.conf - echo 'ENABLE_GCOV := 1' >> Makefile.conf - echo 'ENABLE_DEBUG := 1' >> Makefile.conf - -config-gprof: clean - echo 'CONFIG := gcc' > Makefile.conf - echo 'ENABLE_GPROF := 1' >> Makefile.conf - -config-sudo: - echo "INSTALL_SUDO := sudo" >> Makefile.conf - -echo-yosys-ver: - @echo "$(YOSYS_VER)" - -echo-git-rev: - @echo "$(GIT_REV)" - -echo-cxx: - @echo "$(CXX)" - --include libs/*/*.d --include frontends/*/*.d --include passes/*/*.d --include backends/*/*.d --include kernel/*.d --include techlibs/*/*.d - -FORCE: - -.PHONY: all top-all abc test install-dev install install-abc docs clean mrproper qtcreator coverage vcxsrc -.PHONY: config-clean config-clang config-gcc config-gcc-static config-gprof config-sudo diff --git a/README.md b/README.md index df65a6a10..f8b3dfa4f 100644 --- a/README.md +++ b/README.md @@ -75,10 +75,11 @@ or $ cd yosys $ git submodule update --init --recursive -You need a C++ compiler with C++17 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. +A C++ compiler with C++20 support is required as well as some standard tools +such as GNU Flex, GNU Bison (>=3.8), CMake (>=3.27), Make (or other CMake +generator such as Ninja), and Python (>=3.11). Some additional tools: readline, +libffi, Tcl and zlib; will be used if available but are optional. Graphviz and +Xdot are used by the `show` command to display schematics. For example on Ubuntu Linux 22.04 LTS the following commands will install all prerequisites for building yosys: @@ -86,45 +87,66 @@ prerequisites for building yosys: $ sudo apt-get install gawk git make python3 lld bison clang flex \ libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev \ graphviz xdot - $ curl -LsSf https://astral.sh/uv/install.sh | sh -The environment variable `CXX` can be used to control the C++ compiler used, or -run one of the following to override it: +**NOTE**: By default, Ubuntu 22.04 LTS is limited to CMake 3.22 via `apt`. To +install a newer version and meet the minimum required for building Yosys, use +`sudo snap install cmake --classic`. - $ make config-clang - $ make config-gcc +CMake is used for build configuration, and requires a separate build directory: -The Makefile has many variables influencing the build process. These can be -adjusted by modifying the Makefile.conf file which is created at the `make -config-...` step (see above), or they can be set by passing an option to the -make command directly: + $ cmake -B build . - $ make CXX=$CXX +Once generated, available build variables can be inspected and modified with +`ccmake` or opening the generated `build/CMakeCache.txt` file: -For other compilers and build configurations it might be necessary to make some -changes to the config section of the Makefile. It's also an alternative way to -set the make variables mentioned above. + $ ccmake build #..or.. + $ vi build/CMakeCache.txt - $ vi Makefile # ..or.. - $ vi Makefile.conf +When setting one-off variables, CMake provides the `-D =` command +line option. For example, disabling zlib support: -To build Yosys simply type 'make' in this directory. + $ cmake -B build . -DYOSYS_WITHOUT_ZLIB=ON - $ make - $ sudo make install +For a more persistent configuration, we recommend creating and using a +`CMakeUserPresets.json` file in the root `yosys` directory. Below is an example +file which enables ccache and sets the default compiler to clang when calling +`cmake --preset clang`: -Tests are located in the tests subdirectory and can be executed using the test +```json +{ + "version": 1, + "configurePresets": [ + { + "name": "default", + "binaryDir": "build", + "generator": "Unix Makefiles", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++", + "YOSYS_COMPILER_LAUNCHER": "ccache" + } + } + ] +} +``` + +Once generated, the build system can be run as follows: + + $ cmake --build build #..or.. + $ cd build + $ cmake --build . + +To quickly install Yosys with the default settings: + + $ cmake -B build . -DCMAKE_BUILD_TYPE=Release + $ cmake --build build --config Release --parallel $(nproc) + $ sudo cmake --install build --strip + +Tests are located in the tests subdirectory and can be executed using the `test` target. Note that you need gawk, a recent version of iverilog, and gtest. 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. + $ cmake --build build --target test --parallel $(nproc) Getting Started @@ -134,7 +156,7 @@ 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 + $ ./build/yosys yosys> the command ``help`` can be used to print a list of all available @@ -256,7 +278,7 @@ following are used for building the website: Or for MacOS, using homebrew: - $ brew install pdf2svg libfaketime + $ brew install pdf2svg libfaketime PDFLaTeX, included with most LaTeX distributions, is also needed during the build process for the website. Or, run the following: @@ -265,24 +287,20 @@ build process for the website. Or, run the following: Or for MacOS, using homebrew: - $ brew install basictex - $ sudo tlmgr update --self - $ sudo tlmgr install collection-latexextra latexmk tex-gyre + $ brew install basictex + $ sudo tlmgr update --self + $ sudo tlmgr install collection-latexextra latexmk tex-gyre 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`. +DOCS (e.g.) + + $ cmake --build build --target docs-html --parallel + +This will build/rebuild yosys as necessary before generating the website +documentation from the yosys help commands. To build for pdf instead of html, +use the `docs-latexpdf` target. -It is recommended to use the `ENABLE_HELP_SOURCE` make option for Yosys builds -that will be used to build the documentation. This option enables source -location tracking for passes and improves the command reference through grouping -related commands and allowing for the documentation to link to the corresponding -source files. Without this, a warning will be raised during the Sphinx build -about `Found commands assigned to group unknown` and `make docs` is configured -to fail on warnings by default. diff --git a/abc b/abc index 223d685c5..72d015f65 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit 223d685c5d8e22b90362524bd7189720a6621aeb +Subproject commit 72d015f6567281d84bd4fe6328ce4b7233b596ca diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt new file mode 100644 index 000000000..a38c2ec94 --- /dev/null +++ b/backends/CMakeLists.txt @@ -0,0 +1,18 @@ +add_subdirectory(aiger) +add_subdirectory(aiger2) +add_subdirectory(blif) +add_subdirectory(btor) +add_subdirectory(cxxrtl) +add_subdirectory(edif) +add_subdirectory(firrtl) +add_subdirectory(functional) +add_subdirectory(intersynth) +add_subdirectory(jny) +add_subdirectory(json) +add_subdirectory(rtlil) +add_subdirectory(simplec) +add_subdirectory(smt2) +add_subdirectory(smv) +add_subdirectory(spice) +add_subdirectory(table) +add_subdirectory(verilog) diff --git a/backends/aiger/CMakeLists.txt b/backends/aiger/CMakeLists.txt new file mode 100644 index 000000000..4cf940196 --- /dev/null +++ b/backends/aiger/CMakeLists.txt @@ -0,0 +1,8 @@ +yosys_backend(aiger + aiger.cc + REQUIRES + json11 +) +yosys_backend(xaiger + xaiger.cc +) diff --git a/backends/aiger/Makefile.inc b/backends/aiger/Makefile.inc deleted file mode 100644 index 4a4cf30bd..000000000 --- a/backends/aiger/Makefile.inc +++ /dev/null @@ -1,4 +0,0 @@ - -OBJS += backends/aiger/aiger.o -OBJS += backends/aiger/xaiger.o - diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc index 95f4c19e2..1320937a0 100644 --- a/backends/aiger/aiger.cc +++ b/backends/aiger/aiger.cc @@ -340,7 +340,7 @@ struct AigerWriter if (cell->type == ID($scopeinfo)) continue; - log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); + log_error("Unsupported cell type: %s (%s)\n", cell->type.unescape(), cell); } for (auto bit : unused_bits) @@ -349,10 +349,10 @@ struct AigerWriter if (!undriven_bits.empty()) { undriven_bits.sort(); for (auto bit : undriven_bits) { - log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit)); + log_warning("Treating undriven bit %s.%s like $anyseq.\n", module, log_signal(bit)); input_bits.insert(bit); } - log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module)); + log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), module); } init_map.sort(); @@ -635,35 +635,35 @@ struct AigerWriter int a = aig_map.at(sig[i]); log_assert((a & 1) == 0); if (GetSize(wire) != 1) - symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s[%d]", log_id(wire), i)); + symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s[%d]", wire, i)); else - symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s", log_id(wire))); + symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s", wire)); } if (wire->port_output) { int o = ordered_outputs.at(SigSpec(wire, i)); if (GetSize(wire) != 1) - symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", log_id(wire), i)); + symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", wire, i)); else - symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", log_id(wire))); + symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", wire)); } if (init_inputs.count(sig[i])) { int a = init_inputs.at(sig[i]); log_assert((a & 1) == 0); if (GetSize(wire) != 1) - symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", log_id(wire), i)); + symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", wire, i)); else - symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", log_id(wire))); + symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", wire)); } if (ordered_latches.count(sig[i])) { int l = ordered_latches.at(sig[i]); const char *p = (zinit_mode && (aig_latchinit.at(l) == 1)) ? "!" : ""; if (GetSize(wire) != 1) - symbols[stringf("l%d", l)].push_back(stringf("%s%s[%d]", p, log_id(wire), i)); + symbols[stringf("l%d", l)].push_back(stringf("%s%s[%d]", p, wire, i)); else - symbols[stringf("l%d", l)].push_back(stringf("%s%s", p, log_id(wire))); + symbols[stringf("l%d", l)].push_back(stringf("%s%s", p, wire)); } } } @@ -705,30 +705,30 @@ struct AigerWriter int index = no_startoffset ? i : (wire->start_offset+i); if (verbose_map) - wire_lines[a] += stringf("wire %d %d %s\n", a, index, log_id(wire)); + wire_lines[a] += stringf("wire %d %d %s\n", a, index, wire); if (wire->port_input) { log_assert((a & 1) == 0); - input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, index, log_id(wire)); + input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, index, wire); } if (wire->port_output) { int o = ordered_outputs.at(SigSpec(wire, i)); - output_lines[o] += stringf("output %d %d %s\n", o, index, log_id(wire)); + output_lines[o] += stringf("output %d %d %s\n", o, index, wire); } if (init_inputs.count(sig[i])) { int a = init_inputs.at(sig[i]); log_assert((a & 1) == 0); - init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, index, log_id(wire)); + init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, index, wire); } if (ordered_latches.count(sig[i])) { int l = ordered_latches.at(sig[i]); if (zinit_mode && (aig_latchinit.at(l) == 1)) - latch_lines[l] += stringf("invlatch %d %d %s\n", l, index, log_id(wire)); + latch_lines[l] += stringf("invlatch %d %d %s\n", l, index, wire); else - latch_lines[l] += stringf("latch %d %d %s\n", l, index, log_id(wire)); + latch_lines[l] += stringf("latch %d %d %s\n", l, index, wire); } } } @@ -930,7 +930,9 @@ struct AigerBackend : public Backend { log(" make indexes zero based, enable using map files with smt solvers.\n"); log("\n"); log(" -ywmap \n"); - log(" write a map file for conversion to and from yosys witness traces.\n"); + log(" write a map file for conversion to and from yosys witness traces,\n"); + log(" also allows for mapping AIGER bad-state properties and invariant\n"); + log(" constraints back to individual formal properties by name.\n"); log("\n"); log(" -I, -O, -B, -L\n"); log(" If the design contains no input/output/assert/flip-flop then create one\n"); @@ -1025,12 +1027,12 @@ struct AigerBackend : public Backend { 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)); + log_cmd_error("Can't handle partially selected module %s!\n", top_module); if (!top_module->processes.empty()) - log_error("Found unmapped processes in module %s: unmapped processes are not supported in AIGER backend!\n", log_id(top_module)); + log_error("Found unmapped processes in module %s: unmapped processes are not supported in AIGER backend!\n", top_module); if (!top_module->memories.empty()) - log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", log_id(top_module)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", top_module); AigerWriter writer(top_module, no_sort, zinit_mode, imode, omode, bmode, lmode); writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 988bc558b..cc1085f96 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -268,7 +268,7 @@ struct XAigerWriter 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); + cell->type.unescape(), i.first.name.unescape(), offset, d); } #endif arrival_times[rhs[offset]] = d; @@ -285,7 +285,7 @@ struct XAigerWriter 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)); + log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", c.first.unescape(), cell, cell->type.unescape()); if (is_input) for (auto b : c.second) { @@ -303,7 +303,7 @@ struct XAigerWriter } } - //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); + //log_warning("Unsupported cell type: %s (%s)\n", cell->type.unescape(), cell); } dict> box_ports; @@ -325,12 +325,12 @@ struct XAigerWriter 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)); + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", 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)); + log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", box_module); carry_out = port_name; } } @@ -339,9 +339,9 @@ struct XAigerWriter } 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)); + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", 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)); + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", box_module); if (carry_in != IdString()) { r.first->second.push_back(carry_in); r.first->second.push_back(carry_out); @@ -612,7 +612,7 @@ struct XAigerWriter 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)); + log_debug("Cell '%s' (type %s) has (* init *) value '%s'.\n", cell, cell->type.unescape(), log_signal(init)); if (init == State::S1) write_s_buffer(1); else if (init == State::S0) @@ -692,12 +692,12 @@ struct XAigerWriter 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)); + input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, wire->start_offset+i, 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)); + output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), wire->start_offset+i, wire); } } } @@ -709,7 +709,7 @@ struct XAigerWriter int box_count = 0; for (auto cell : box_list) - f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); + f << stringf("box %d %d %s\n", box_count++, 0, cell->name.unescape()); output_lines.sort(); for (auto &it : output_lines) @@ -774,12 +774,12 @@ struct XAigerBackend : public Backend { 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)); + log_cmd_error("Can't handle partially selected module %s!\n", 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)); + log_error("Found unmapped processes in module %s: unmapped processes are not supported in XAIGER backend!\n", 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)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", top_module); XAigerWriter writer(top_module, dff_mode); writer.write_aiger(*f, ascii_mode); diff --git a/backends/aiger2/CMakeLists.txt b/backends/aiger2/CMakeLists.txt new file mode 100644 index 000000000..f77b8d9ee --- /dev/null +++ b/backends/aiger2/CMakeLists.txt @@ -0,0 +1,5 @@ +yosys_backend(aiger2 + aiger.cc + PROVIDES + write_xaiger2 +) diff --git a/backends/aiger2/Makefile.inc b/backends/aiger2/Makefile.inc deleted file mode 100644 index 494b8d6c6..000000000 --- a/backends/aiger2/Makefile.inc +++ /dev/null @@ -1 +0,0 @@ -OBJS += backends/aiger2/aiger.o diff --git a/backends/aiger2/aiger.cc b/backends/aiger2/aiger.cc index 3c22ad210..3e5621c2d 100644 --- a/backends/aiger2/aiger.cc +++ b/backends/aiger2/aiger.cc @@ -21,9 +21,12 @@ // - gracefully handling inout ports (an error message probably) // - undriven wires // - zero-width operands +// - decide how to unify this with cellaigs +// - break up Index into something smaller +// - (C++20) remove snprintf-into-std::ostream weirdness #include "kernel/register.h" -#include "kernel/celltypes.h" +#include "kernel/newcelltypes.h" #include "kernel/rtlil.h" USING_YOSYS_NAMESPACE @@ -45,8 +48,22 @@ PRIVATE_NAMESPACE_BEGIN // TODO //#define ARITH_OPS ID($add), ID($sub), ID($neg) -#define KNOWN_OPS BITWISE_OPS, REDUCE_OPS, LOGIC_OPS, GATE_OPS, ID($pos), CMP_OPS, \ - ID($pmux), ID($bmux) /*, ARITH_OPS*/ +static constexpr auto known_ops = []() constexpr { + StaticCellTypes::Categories::Category c{}; + for (auto id : {BITWISE_OPS}) + c.set_id(id); + for (auto id : {REDUCE_OPS}) + c.set_id(id); + for (auto id : {LOGIC_OPS}) + c.set_id(id); + for (auto id : {GATE_OPS}) + c.set_id(id); + for (auto id : {CMP_OPS}) + c.set_id(id); + for (auto id : {ID($pos), ID($pmux), ID($bmux)}) + c.set_id(id); + return c; +}(); template struct Index { @@ -92,7 +109,7 @@ struct Index { int pos = index_wires(info, m); for (auto cell : m->cells()) { - if (cell->type.in(KNOWN_OPS) || cell->type.in(ID($scopeinfo), ID($specify2), ID($specify3), ID($input_port))) + if (known_ops(cell->type) || cell->type.in(ID($scopeinfo), ID($specify2), ID($specify3), ID($input_port))) continue; Module *submodule = m->design->module(cell->type); @@ -104,7 +121,7 @@ struct Index { pos += index_module(submodule); } else { if (allow_blackboxes) { - info.found_blackboxes.insert(cell); + info.found_blackboxes.insert(cell); } else { // Even if we don't allow blackboxes these might still be // present outside of any traversed input cones, so we @@ -115,7 +132,7 @@ struct Index { continue; if (!submodule || submodule->get_blackbox_attribute()) log_warning("Unsupported cell type: %s (%s in %s)\n", - log_id(cell->type), log_id(cell), log_id(m)); + cell->type.unescape(), cell, m); } } } @@ -163,6 +180,11 @@ struct Index { if (!strashing) { return (static_cast(this))->emit_gate(a, b); } else { + // AigMaker::node2index + + // In XAIGER, the ordering of inputs is used to distinguish between AND + // and XOR gates. AND gates have their first input literal be larger + // than their second, and vice-versa for XORs. if (a < b) std::swap(a, b); auto pair = std::make_pair(a, b); @@ -183,7 +205,9 @@ struct Index { Lit OR(Lit a, Lit b) { - return NOT(AND(NOT(a), NOT(b))); + Lit not_a = NOT(a); + Lit not_b = NOT(b); + return NOT(AND(not_a, not_b)); } Lit MUX(Lit a, Lit b, Lit s) @@ -197,17 +221,24 @@ struct Index { return b; } - return OR(AND(a, NOT(s)), AND(b, s)); + Lit not_s = NOT(s); + Lit a_active = AND(a, not_s); + Lit b_active = AND(b, s); + return OR(a_active, b_active); } Lit XOR(Lit a, Lit b) { - return OR(AND(a, NOT(b)), AND(NOT(a), b)); + Lit not_a = NOT(a); + Lit not_b = NOT(b); + Lit a_and_not_b = AND(a, not_b); + Lit not_a_and_b = AND(not_a, b); + return OR(a_and_not_b, not_a_and_b); } Lit XNOR(Lit a, Lit b) { - return NOT(OR(AND(a, NOT(b)), AND(NOT(a), b))); + return NOT(XOR(a, b)); } Lit CARRY(Lit a, Lit b, Lit c) @@ -219,7 +250,10 @@ struct Index { return AND(a, b); } } - return OR(AND(a, b), AND(c, OR(a, b))); + Lit a_or_b = OR(a, b); + Lit a_or_b_and_c = AND(c, a_or_b); + Lit a_and_b = AND(a, b); + return OR(a_and_b, a_or_b_and_c); } Lit REDUCE(std::vector lits, bool op_xor=false) @@ -269,7 +303,7 @@ struct Index { } else if (cell->type.in(ID($lt), ID($le), ID($gt), ID($ge))) { if (cell->type.in(ID($gt), ID($ge))) std::swap(aport, bport); - int carry = cell->type.in(ID($le), ID($ge)) ? CFALSE : CTRUE; + int carry = cell->type.in(ID($le), ID($ge)) ? CFALSE : CTRUE; Lit a = Writer::EMPTY_LIT; Lit b = Writer::EMPTY_LIT; // TODO: this might not be the most economic structure; revisit at a later date @@ -367,7 +401,7 @@ struct Index { } else if (cell->type.in(ID($xor), ID($_XOR_))) { return XOR(a, b); } else if (cell->type.in(ID($xnor), ID($_XNOR_))) { - return NOT(XOR(a, b)); + return XNOR(a, b); } else if (cell->type.in(ID($_ANDNOT_))) { return AND(a, NOT(b)); } else if (cell->type.in(ID($_ORNOT_))) { @@ -387,7 +421,9 @@ struct Index { if (oport == ID::Y) { return XOR(ab, c); } else /* oport == ID::X */ { - return OR(AND(a, b), AND(c, ab)); + Lit a_and_b = AND(a, b); + Lit c_and_ab = AND(c, ab); + return OR(a_and_b, c_and_ab); } } else if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) { Lit c, d; @@ -398,10 +434,15 @@ struct Index { else d = cell->type == ID($_AOI3_) ? CTRUE : CFALSE; - if (/* aoi */ cell->type.in(ID($_AOI3_), ID($_AOI4_))) - return NOT(OR(AND(a, b), AND(c, d))); - else - return NOT(AND(OR(a, b), OR(c, d))); + if (/* aoi */ cell->type.in(ID($_AOI3_), ID($_AOI4_))) { + Lit a_and_b = AND(a, b); + Lit c_and_d = AND(c, d); + return NOT(OR(a_and_b, c_and_d)); + } else { + Lit a_or_b = OR(a, b); + Lit c_or_d = OR(c, d); + return NOT(AND(a_or_b, c_or_d)); + } } else { log_abort(); } @@ -422,7 +463,11 @@ struct Index { sels.push_back(NOT(s)); } - return OR(AND(REDUCE(sels), a), NOT(REDUCE(bar))); + Lit reduce_sels = REDUCE(sels); + Lit reduce_sels_and_a = AND(reduce_sels, a); + Lit reduce_bar = NOT(REDUCE(bar)); + + return OR(reduce_sels_and_a, reduce_bar); } else if (cell->type == ID($bmux)) { SigSpec aport = cell->getPort(ID::A); SigSpec sport = cell->getPort(ID::S); @@ -492,7 +537,7 @@ struct Index { Design *design = index.design; auto &minfo = leaf_minfo(index); if (!minfo.suboffsets.count(cell)) - log_error("Reached unsupport cell %s (%s in %s)\n", log_id(cell->type), log_id(cell), log_id(cell->module)); + log_error("Reached unsupported cell %s (%s in %s)\n", cell->type.unescape(), cell, cell->module); Module *def = design->module(cell->type); log_assert(def); levels.push_back(Level(index.modules.at(def), cell)); @@ -511,13 +556,13 @@ struct Index { { std::string ret; bool first = true; - for (auto pair : levels) { + for (auto [minfo, cell] : levels) { if (!first) ret += "."; - if (!pair.second) - ret += RTLIL::unescape_id(pair.first.module->name); + if (!cell) + ret += minfo.module->name.unescape(); else - ret += RTLIL::unescape_id(pair.second->name); + ret += cell->name.unescape(); first = false; } return ret; @@ -526,8 +571,8 @@ struct Index { int hash() const { int hash = 0; - for (auto pair : levels) - hash += (uintptr_t) pair.second; + for (auto [_, cell] : levels) + hash += (uintptr_t) cell; return hash; } @@ -536,9 +581,12 @@ struct Index { if (levels.size() != other.levels.size()) return false; - for (int i = 0; i < levels.size(); i++) - if (levels[i].second != other.levels[i].second) + for (int i = 0; i < levels.size(); i++) { + auto* cell = levels[i].second; + auto* other_cell = other.levels[i].second; + if (cell != other_cell) return false; + } return true; } @@ -579,7 +627,7 @@ struct Index { // an output of a cell Cell *driver = bit.wire->driverCell(); - if (driver->type.in(KNOWN_OPS)) { + if (known_ops(driver->type)) { ret = impl_op(cursor, driver, bit.wire->driverPort(), bit.offset); } else { Module *def = cursor.enter(*this, driver); @@ -588,10 +636,10 @@ struct Index { Wire *w = def->wire(portname); if (!w) log_error("Output port %s on instance %s of %s doesn't exist\n", - log_id(portname), log_id(driver), log_id(def)); + portname.unescape(), driver, def); if (bit.offset >= w->width) log_error("Bit position %d of output port %s on instance %s of %s is out of range (port has width %d)\n", - bit.offset, log_id(portname), log_id(driver), log_id(def), w->width); + bit.offset, portname.unescape(), driver, def, w->width); ret = visit(cursor, SigBit(w, bit.offset)); } cursor.exit(*this); @@ -607,11 +655,11 @@ struct Index { IdString portname = bit.wire->name; if (!instance->hasPort(portname)) log_error("Input port %s on instance %s of %s unconnected\n", - log_id(portname), log_id(instance), log_id(instance->type)); + portname.unescape(), instance, instance->type); auto &port = instance->getPort(portname); if (bit.offset >= port.size()) log_error("Bit %d of input port %s on instance %s of %s unconnected\n", - bit.offset, log_id(portname), log_id(instance), log_id(instance->type)); + bit.offset, portname.unescape(), instance, instance->type.unescape()); ret = visit(cursor, port[bit.offset]); } cursor.enter(*this, instance); @@ -701,6 +749,9 @@ struct AigerWriter : Index { nands++; lit_counter += 2; + // In XAIGER, the ordering of inputs is used to distinguish between AND + // and XOR gates. AND gates have their first input literal be larger + // than their second, and vice-versa for XORs. if (a < b) std::swap(a, b); encode(out - a); encode(a - b); @@ -717,7 +768,7 @@ struct AigerWriter : Index { log_assert(lit_counter == (Lit) (ninputs + nlatches + nands) * 2 + 2); char buf[128]; - snprintf(buf, sizeof(buf) - 1, "aig %08d %08d %08d %08d %08d\n", + snprintf(buf, sizeof(buf), "aig %08d %08d %08d %08d %08d\n", ninputs + nlatches + nands, ninputs, nlatches, noutputs, nands); f->write(buf, strlen(buf)); } @@ -730,15 +781,16 @@ struct AigerWriter : Index { // populate inputs std::vector inputs; for (auto id : top->ports) { - Wire *w = top->wire(id); - log_assert(w); - if (w->port_input && !w->port_output) - for (int i = 0; i < w->width; i++) { - pi_literal(SigBit(w, i)) = lit_counter; - inputs.push_back(SigBit(w, i)); - lit_counter += 2; - ninputs++; - } + Wire *w = top->wire(id); + log_assert(w); + if (w->port_input && !w->port_output) + for (int i = 0; i < w->width; i++) { + auto bit = SigBit(w, i); + pi_literal(bit) = lit_counter; + inputs.push_back(bit); + lit_counter += 2; + ninputs++; + } } this->f = f; @@ -746,35 +798,38 @@ struct AigerWriter : Index { write_header(); // insert padding where output literals will go (once known) for (auto id : top->ports) { - Wire *w = top->wire(id); - log_assert(w); - if (w->port_output) { - for (auto bit : SigSpec(w)) { - (void) bit; - char buf[16]; - snprintf(buf, sizeof(buf) - 1, "%08d\n", 0); - f->write(buf, strlen(buf)); - noutputs++; + Wire *w = top->wire(id); + log_assert(w); + if (w->port_output) { + for (auto bit : SigSpec(w)) { + (void) bit; + char buf[16]; + snprintf(buf, sizeof(buf), "%08d\n", 0); + f->write(buf, strlen(buf)); + noutputs++; + } } } - } auto data_start = f->tellp(); // now the guts std::vector> outputs; for (auto w : top->wires()) - if (w->port_output) { - for (auto bit : SigSpec(w)) - outputs.push_back({bit, eval_po(bit)}); - } + if (w->port_output) { + for (auto bit : SigSpec(w)) + // Each call to eval_po eventually reaches emit_gate and + // encode which writes to f. + outputs.push_back({bit, eval_po(bit)}); + } + auto data_end = f->tellp(); // revisit header and the list of outputs f->seekp(file_start); write_header(); - for (auto pair : outputs) { + for (auto [_, po] : outputs) { char buf[16]; - snprintf(buf, sizeof(buf) - 1, "%08d\n", pair.second); + snprintf(buf, sizeof(buf), "%08d\n", po); f->write(buf, strlen(buf)); } // double check we arrived at the same offset for the @@ -783,12 +838,13 @@ struct AigerWriter : Index { f->seekp(data_end); int i = 0; - for (auto pair : outputs) { - if (SigSpec(pair.first).is_wire()) { + for (auto [bit, _] : outputs) { + if (SigSpec(bit).is_wire()) { + // primary output symbol char buf[32]; - snprintf(buf, sizeof(buf) - 1, "o%d ", i); + snprintf(buf, sizeof(buf), "o%d ", i); f->write(buf, strlen(buf)); - std::string name = RTLIL::unescape_id(pair.first.wire->name); + std::string name = bit.wire->name.unescape(); f->write(name.data(), name.size()); f->put('\n'); } @@ -797,10 +853,11 @@ struct AigerWriter : Index { i = 0; for (auto bit : inputs) { if (SigSpec(bit).is_wire()) { + // primary input symbol char buf[32]; - snprintf(buf, sizeof(buf) - 1, "i%d ", i); + snprintf(buf, sizeof(buf), "i%d ", i); f->write(buf, strlen(buf)); - std::string name = RTLIL::unescape_id(bit.wire->name); + std::string name = bit.wire->name.unescape(); f->write(name.data(), name.size()); f->put('\n'); } @@ -871,33 +928,34 @@ struct XAigerAnalysis : Index { Wire *w = top->wire(id); log_assert(w); if (w->port_input && !w->port_output) - for (int i = 0; i < w->width; i++) - pi_literal(SigBit(w, i)) = 0; + for (int i = 0; i < w->width; i++) + pi_literal(SigBit(w, i)) = 0; } HierCursor cursor; for (auto box : top_minfo->found_blackboxes) { Module *def = design->module(box->type); if (!(def && def->has_attribute(ID::abc9_box_id))) - for (auto &conn : box->connections_) - if (box->port_dir(conn.first) != RTLIL::PD_INPUT) - for (auto bit : conn.second) - pi_literal(bit, &cursor) = 0; + for (auto &conn : box->connections_) + if (box->port_dir(conn.first) != RTLIL::PD_INPUT) + for (auto bit : conn.second) + pi_literal(bit, &cursor) = 0; } - for (auto w : top->wires()) - if (w->port_output) { - for (auto bit : SigSpec(w)) - (void) eval_po(bit); + for (auto w : top->wires()) { + if (w->port_output) { + for (auto bit : SigSpec(w)) + (void) eval_po(bit); + } } for (auto box : top_minfo->found_blackboxes) { Module *def = design->module(box->type); if (!(def && def->has_attribute(ID::abc9_box_id))) - for (auto &conn : box->connections_) - if (box->port_dir(conn.first) == RTLIL::PD_INPUT) - for (auto bit : conn.second) - (void) eval_po(bit); + for (auto &conn : box->connections_) + if (box->port_dir(conn.first) == RTLIL::PD_INPUT) + for (auto bit : conn.second) + (void) eval_po(bit); } } }; @@ -916,15 +974,15 @@ struct XAigerWriter : AigerWriter { std::vector pos; std::vector pis; - // * The aiger output port sequence is COs (inputs to modeled boxes), - // inputs to opaque boxes, then module outputs. COs going first is - // required by abc. - // * proper_pos_counter counts ports which follow after COs - // * The mapping file `pseudopo` and `po` statements use indexing relative - // to the first port following COs. - // * If a module output is directly driven by an opaque box, the emission - // of the po statement in the mapping file is skipped. This is done to - // aid re-integration of the mapped result. + // * The aiger output port sequence is COs (inputs to modeled boxes), + // inputs to opaque boxes, then module outputs. COs going first is + // required by abc. + // * proper_pos_counter counts ports which follow after COs + // * The mapping file `pseudopo` and `po` statements use indexing relative + // to the first port following COs. + // * If a module output is directly driven by an opaque box, the emission + // of the po statement in the mapping file is skipped. This is done to + // aid re-integration of the mapped result. int proper_pos_counter = 0; pool driven_by_opaque_box; @@ -990,7 +1048,7 @@ struct XAigerWriter : AigerWriter { } else if (!is_input && !inputs) { for (auto &bit : conn.second) { if (!bit.wire || (bit.wire->port_input && !bit.wire->port_output)) - log_error("Bad connection %s/%s ~ %s\n", log_id(box), log_id(conn.first), log_signal(conn.second)); + log_error("Bad connection %s/%s ~ %s\n", box, conn.first.unescape(), log_signal(conn.second)); ensure_pi(bit, cursor); @@ -1015,9 +1073,9 @@ struct XAigerWriter : AigerWriter { void prep_boxes(int pending_pos_num) { XAigerAnalysis analysis; - log_debug("preforming analysis on '%s'\n", log_id(top)); + log_debug("preforming analysis on '%s'\n", top); analysis.analyze(top); - log_debug("analysis on '%s' done\n", log_id(top)); + log_debug("analysis on '%s' done\n", top); // boxes which have timing data, maybe a whitebox model std::vector> nonopaque_boxes; @@ -1030,8 +1088,8 @@ struct XAigerWriter : AigerWriter { for (auto box : minfo.found_blackboxes) { log_debug(" - %s.%s (type %s): ", cursor.path(), - RTLIL::unescape_id(box->name), - log_id(box->type)); + box, + box->type.unescape()); Module *box_module = design->module(box->type), *box_derived; @@ -1100,7 +1158,7 @@ struct XAigerWriter : AigerWriter { } else { // FIXME: hierarchical path log_warning("connection on port %s[%d] of instance %s (type %s) missing, using 1'bx\n", - log_id(port_id), i, log_id(box), log_id(box->type)); + port_id.unescape(), i, box, box->type.unescape()); bit = RTLIL::Sx; } @@ -1135,7 +1193,7 @@ struct XAigerWriter : AigerWriter { } else { // FIXME: hierarchical path log_warning("connection on port %s[%d] of instance %s (type %s) missing\n", - log_id(port_id), i, log_id(box), log_id(box->type)); + port_id.unescape(), i, box, box->type.unescape()); pad_pi(); continue; } @@ -1152,7 +1210,7 @@ struct XAigerWriter : AigerWriter { holes_wb->setPort(port_id, w); } else { log_error("Ambiguous port direction on %s/%s\n", - log_id(box->type), log_id(port_id)); + box->type.unescape(), port_id.unescape()); } } } @@ -1202,29 +1260,29 @@ struct XAigerWriter : AigerWriter { reset_counters(); for (auto w : top->wires()) - if (w->port_input && !w->port_output) - for (int i = 0; i < w->width; i++) - ensure_pi(SigBit(w, i)); + if (w->port_input && !w->port_output) + for (int i = 0; i < w->width; i++) + ensure_pi(SigBit(w, i)); int proper_po_num = 0; for (auto w : top->wires()) - if (w->port_output) - proper_po_num += w->width; + if (w->port_output) + proper_po_num += w->width; prep_boxes(proper_po_num); for (auto w : top->wires()) - if (w->port_output) - for (int i = 0; i < w->width; i++) { - // When a module output is directly driven by an opaque box, we - // don't emit it to the mapping file to aid re-integration, but we - // do emit a proper PO. - if (map_file.is_open() && !driven_by_opaque_box.count(SigBit(w, i))) { - map_file << "po " << proper_pos_counter << " " << i - << " " << w->name.c_str() << "\n"; - } - proper_pos_counter++; - pos.push_back(std::make_pair(SigBit(w, i), HierCursor{})); - } + if (w->port_output) + for (int i = 0; i < w->width; i++) { + // When a module output is directly driven by an opaque box, we + // don't emit it to the mapping file to aid re-integration, but we + // do emit a proper PO. + if (map_file.is_open() && !driven_by_opaque_box.count(SigBit(w, i))) { + map_file << "po " << proper_pos_counter << " " << i + << " " << w->name.c_str() << "\n"; + } + proper_pos_counter++; + pos.push_back(std::make_pair(SigBit(w, i), HierCursor{})); + } this->f = f; // start with the header @@ -1234,7 +1292,7 @@ struct XAigerWriter : AigerWriter { // insert padding where output literals will go (once known) for (auto _ : pos) { char buf[16]; - snprintf(buf, sizeof(buf) - 1, "%08d\n", 0); + snprintf(buf, sizeof(buf), "%08d\n", 0); f->write(buf, strlen(buf)); } auto data_start = f->tellp(); @@ -1251,35 +1309,36 @@ struct XAigerWriter : AigerWriter { write_header(); for (auto lit : outlits) { char buf[16]; - snprintf(buf, sizeof(buf) - 1, "%08d\n", lit); + snprintf(buf, sizeof(buf), "%08d\n", lit); f->write(buf, strlen(buf)); } // double check we arrived at the same offset for the // main data section log_assert(data_start == f->tellp()); - // extensions + // XAIGER extensions f->seekp(0, std::ios::end); - f->put('c'); + f->put('c'); // 'c': comment (marks beginning of extensions) // insert empty 'r' and 's' sections (abc crashes if we provide 'a' without those) - f->put('r'); - write_be32(*f, 4); - write_be32(*f, 0); - f->put('s'); - write_be32(*f, 4); - write_be32(*f, 0); + f->put('r'); // 'r': register classes + write_be32(*f, 4); // length in bytes + write_be32(*f, 0); // no register classes - f->put('h'); + f->put('s'); // 's': register initial values + write_be32(*f, 4); // length in bytes + write_be32(*f, 0); // no register initial values + + f->put('h'); // 'h': hierarchy information // TODO: get rid of std::string copy std::string h_buffer_str = h_buffer.str(); - write_be32(*f, h_buffer_str.size()); - f->write(h_buffer_str.data(), h_buffer_str.size()); + write_be32(*f, h_buffer_str.size()); // length in bytes + f->write(h_buffer_str.data(), h_buffer_str.size()); // data #if 1 - f->put('a'); - write_be32(*f, 0); // size to be filled later + f->put('a'); // 'a': additional AIG (used for holes) + write_be32(*f, 0); // length in bytes (to be filled later) auto holes_aiger_start = f->tellp(); { AigerWriter holes_writer; @@ -1291,7 +1350,7 @@ struct XAigerWriter : AigerWriter { auto holes_aiger_size = f->tellp() - holes_aiger_start; f->seekp(holes_aiger_start, std::ios::beg); f->seekp(-4, std::ios::cur); - write_be32(*f, holes_aiger_size); + write_be32(*f, holes_aiger_size); // length in bytes #endif f->seekp(0, std::ios::end); @@ -1331,41 +1390,50 @@ struct Aiger2Backend : Backend { log(" perform structural hashing while writing\n"); log("\n"); log(" -flatten\n"); - log(" allow descending into submodules and write a flattened view of the design\n"); - log(" hierarchy starting at the selected top\n"); - log("\n"); + log(" allow descending into submodules and write a flattened view of the design\n"); + log(" hierarchy starting at the selected top\n"); + log("\n"); log("This command is able to ingest all combinational cells except for:\n"); log("\n"); - pool supported = {KNOWN_OPS}; - CellTypes ct; - ct.setup_internals_eval(); log(" "); int col = 0; - for (auto pair : ct.cell_types) - if (!supported.count(pair.first)) { - if (col + pair.first.size() + 2 > 72) { + for (size_t i = 0; i < StaticCellTypes::builder.count; i++) { + auto &cell = StaticCellTypes::builder.cells[i]; + if (!cell.features.is_evaluable) + continue; + if (cell.features.is_stdcell) + continue; + if (known_ops(cell.type)) + continue; + std::string name = cell.type.unescape(); + if (col + name.size() + 2 > 72) { log("\n "); col = 0; } - col += pair.first.size() + 2; - log("%s, ", log_id(pair.first)); + col += name.size() + 2; + log("%s, ", name.c_str()); } log("\n"); log("\n"); log("And all combinational gates except for:\n"); log("\n"); - CellTypes ct2; - ct2.setup_stdcells(); log(" "); col = 0; - for (auto pair : ct2.cell_types) - if (!supported.count(pair.first)) { - if (col + pair.first.size() + 2 > 72) { + for (size_t i = 0; i < StaticCellTypes::builder.count; i++) { + auto &cell = StaticCellTypes::builder.cells[i]; + if (!cell.features.is_evaluable) + continue; + if (!cell.features.is_stdcell) + continue; + if (known_ops(cell.type)) + continue; + std::string name = cell.type.unescape(); + if (col + name.size() + 2 > 72) { log("\n "); col = 0; } - col += pair.first.size() + 2; - log("%s, ", log_id(pair.first)); + col += name.size() + 2; + log("%s, ", name.c_str()); } log("\n"); } @@ -1423,20 +1491,20 @@ struct XAiger2Backend : Backend { log(" perform structural hashing while writing\n"); log("\n"); log(" -flatten\n"); - log(" allow descending into submodules and write a flattened view of the design\n"); - log(" hierarchy starting at the selected top\n"); - log("\n"); - log(" -mapping_prep\n"); - log(" after the file is written, prepare the module for reintegration of\n"); - log(" a mapping in a subsequent command. all cells which are not blackboxed nor\n"); - log(" whiteboxed are removed from the design as well as all wires which only\n"); - log(" connect to removed cells\n"); - log(" (conflicts with -flatten)\n"); - log("\n"); - log(" -map2 \n"); - log(" write a map2 file which 'read_xaiger2 -sc_mapping' can read to\n"); - log(" reintegrate a mapping\n"); - log(" (conflicts with -flatten)\n"); + log(" allow descending into submodules and write a flattened view of the design\n"); + log(" hierarchy starting at the selected top\n"); + log("\n"); + log(" -mapping_prep\n"); + log(" after the file is written, prepare the module for reintegration of\n"); + log(" a mapping in a subsequent command. all cells which are not blackboxed nor\n"); + log(" whiteboxed are removed from the design as well as all wires which only\n"); + log(" connect to removed cells\n"); + log(" (conflicts with -flatten)\n"); + log("\n"); + log(" -map2 \n"); + log(" write a map2 file which 'read_xaiger2 -sc_mapping' can read to\n"); + log(" reintegrate a mapping\n"); + log(" (conflicts with -flatten)\n"); log("\n"); } diff --git a/backends/blif/CMakeLists.txt b/backends/blif/CMakeLists.txt new file mode 100644 index 000000000..06b177513 --- /dev/null +++ b/backends/blif/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(blif + blif.cc +) diff --git a/backends/blif/Makefile.inc b/backends/blif/Makefile.inc deleted file mode 100644 index 517dabaf2..000000000 --- a/backends/blif/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/blif/blif.o - diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc index 85db8679e..ac2e4edde 100644 --- a/backends/blif/blif.cc +++ b/backends/blif/blif.cc @@ -24,7 +24,7 @@ #include "kernel/rtlil.h" #include "kernel/register.h" #include "kernel/sigtools.h" -#include "kernel/celltypes.h" +#include "kernel/newcelltypes.h" #include "kernel/log.h" #include @@ -61,7 +61,7 @@ struct BlifDumper RTLIL::Module *module; RTLIL::Design *design; BlifDumperConfig *config; - CellTypes ct; + NewCellTypes ct; SigMap sigmap; dict init_bits; @@ -91,7 +91,7 @@ struct BlifDumper const std::string str(RTLIL::IdString id) { - std::string str = RTLIL::unescape_id(id); + std::string str = id.unescape(); for (size_t i = 0; i < str.size(); i++) if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>') str[i] = '?'; @@ -108,7 +108,7 @@ struct BlifDumper return config->undef_type == "-" || config->undef_type == "+" ? config->undef_out.c_str() : "$undef"; } - std::string str = RTLIL::unescape_id(sig.wire->name); + std::string str = sig.wire->name.unescape(); for (size_t i = 0; i < str.size(); i++) if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>') str[i] = '?'; @@ -150,7 +150,7 @@ struct BlifDumper void dump_params(const char *command, dict ¶ms) { for (auto ¶m : params) { - f << stringf("%s %s ", command, log_id(param.first)); + f << stringf("%s %s ", command, param.first.unescape()); if (param.second.flags & RTLIL::CONST_FLAG_STRING) { std::string str = param.second.decode_string(); f << stringf("\""); @@ -678,9 +678,9 @@ struct BlifBackend : public Backend { 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)); + log_error("Found unmapped processes in module %s: unmapped processes are not supported in BLIF backend!\n", module->name.unescape()); 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)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", module->name.unescape()); if (module->name == RTLIL::escape_id(top_module_name)) { BlifDumper::dump(*f, module, design, config); diff --git a/backends/btor/CMakeLists.txt b/backends/btor/CMakeLists.txt new file mode 100644 index 000000000..ca40d538e --- /dev/null +++ b/backends/btor/CMakeLists.txt @@ -0,0 +1,7 @@ +yosys_backend(btor + btor.cc + REQUIRES + bmuxmap + demuxmap + bwmuxmap +) diff --git a/backends/btor/Makefile.inc b/backends/btor/Makefile.inc deleted file mode 100644 index af7ab14dc..000000000 --- a/backends/btor/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/btor/btor.o - diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index ca7cf8a7f..497ecc954 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -119,7 +119,7 @@ struct BtorWorker template string getinfo(T *obj, bool srcsym = false) { - string infostr = log_id(obj); + string infostr = obj->name.unescape(); if (!srcsym && !print_internal_names && infostr[0] == '$') return ""; if (obj->attributes.count(ID::src)) { string src = obj->attributes.at(ID::src).decode_string().c_str(); @@ -243,12 +243,12 @@ struct BtorWorker if (cell_recursion_guard.count(cell)) { string cell_list; for (auto c : cell_recursion_guard) - cell_list += stringf("\n %s", log_id(c)); - log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list); + cell_list += stringf("\n %s", c); + log_error("Found topological loop while processing cell %s. Active cells:%s\n", cell, cell_list); } cell_recursion_guard.insert(cell); - btorf_push(log_id(cell)); + btorf_push(cell->name.unescape()); if (cell->type.in(ID($add), ID($sub), ID($mul), ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($sshl), ID($shr), ID($sshr), ID($shift), ID($shiftx), ID($concat), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_))) @@ -726,7 +726,7 @@ struct BtorWorker if (symbol.empty() || (!print_internal_names && symbol[0] == '$')) btorf("%d state %d\n", nid, sid); else - btorf("%d state %d %s\n", nid, sid, log_id(symbol)); + btorf("%d state %d %s\n", nid, sid, symbol.unescape()); 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 @@ -804,12 +804,12 @@ struct BtorWorker if (asyncwr && syncwr) log_error("Memory %s.%s has mixed async/sync write ports.\n", - log_id(module), log_id(mem->memid)); + module, mem->memid.unescape()); for (auto &port : mem->rd_ports) { if (port.clk_enable) log_error("Memory %s.%s has sync read ports. Please use memory_nordff to convert them first.\n", - log_id(module), log_id(mem->memid)); + module, mem->memid.unescape()); } int data_sid = get_bv_sid(mem->width); @@ -871,7 +871,7 @@ struct BtorWorker if (mem->memid[0] == '$') btorf("%d state %d\n", nid, sid); else - btorf("%d state %d %s\n", nid, sid, log_id(mem->memid)); + btorf("%d state %d %s\n", nid, sid, mem->memid.unescape()); ywmap_state(cell); @@ -948,21 +948,20 @@ struct BtorWorker 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_btor`.\n", - log_id(cell->type), log_id(module), log_id(cell)); + cell->type.unescape(), module, 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_btor`.\n", - log_id(cell->type), log_id(module), log_id(cell)); + cell->type.unescape(), module, 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_btor`.\n", - log_id(cell->type), log_id(module), log_id(cell)); + cell->type.unescape(), module, cell); } log_error("Unsupported cell type %s for cell %s.%s.\n", - log_id(cell->type), log_id(module), log_id(cell)); - + cell->type.unescape(), module, cell); okay: - btorf_pop(log_id(cell)); + btorf_pop(cell->name.unescape()); cell_recursion_guard.erase(cell); } @@ -1167,7 +1166,7 @@ struct BtorWorker f(f), sigmap(module), module(module), verbose(verbose), single_bad(single_bad), cover_mode(cover_mode), print_internal_names(print_internal_names), info_filename(info_filename) { if (!info_filename.empty()) - infof("name %s\n", log_id(module)); + infof("name %s\n", module); if (!ywmap_filename.empty()) ywmap_json.write_to_file(ywmap_filename); @@ -1257,19 +1256,19 @@ struct BtorWorker if (!wire->port_id || !wire->port_output) continue; - btorf_push(stringf("output %s", log_id(wire))); + btorf_push(stringf("output %s", wire)); int nid = get_sig_nid(wire); btorf("%d output %d%s\n", next_nid++, nid, getinfo(wire)); - btorf_pop(stringf("output %s", log_id(wire))); + btorf_pop(stringf("output %s", wire)); } for (auto cell : module->cells()) { if (cell->type == ID($assume)) { - btorf_push(log_id(cell)); + btorf_push(cell->name.unescape()); int sid = get_bv_sid(1); int nid_a = get_sig_nid(cell->getPort(ID::A)); @@ -1284,12 +1283,12 @@ struct BtorWorker if (ywmap_json.active()) ywmap_assumes.emplace_back(cell); - btorf_pop(log_id(cell)); + btorf_pop(cell->name.unescape()); } if (cell->type == ID($assert)) { - btorf_push(log_id(cell)); + btorf_push(cell->name.unescape()); int sid = get_bv_sid(1); int nid_a = get_sig_nid(cell->getPort(ID::A)); @@ -1313,12 +1312,12 @@ struct BtorWorker } } - btorf_pop(log_id(cell)); + btorf_pop(cell->name.unescape()); } if (cell->type == ID($cover) && cover_mode) { - btorf_push(log_id(cell)); + btorf_push(cell->name.unescape()); int sid = get_bv_sid(1); int nid_a = get_sig_nid(cell->getPort(ID::A)); @@ -1334,7 +1333,7 @@ struct BtorWorker btorf("%d bad %d%s\n", nid, nid_en_and_a, getinfo(cell, true)); } - btorf_pop(log_id(cell)); + btorf_pop(cell->name.unescape()); } } @@ -1343,7 +1342,7 @@ struct BtorWorker if (wire->port_id || wire->name[0] == '$') continue; - btorf_push(stringf("wire %s", log_id(wire))); + btorf_push(stringf("wire %s", wire)); int sid = get_bv_sid(GetSize(wire)); int nid = get_sig_nid(sigmap(wire)); @@ -1356,7 +1355,7 @@ struct BtorWorker if (info_clocks.count(nid)) info_clocks[this_nid] |= info_clocks[nid]; - btorf_pop(stringf("wire %s", log_id(wire))); + btorf_pop(stringf("wire %s", wire)); continue; } @@ -1370,14 +1369,14 @@ struct BtorWorker int nid = it.first; Cell *cell = it.second; - btorf_push(stringf("next %s", log_id(cell))); + btorf_push(stringf("next %s", cell)); SigSpec sig = sigmap(cell->getPort(ID::D)); int nid_q = get_sig_nid(sig); int sid = get_bv_sid(GetSize(sig)); btorf("%d next %d %d %d%s\n", next_nid++, sid, nid, nid_q, getinfo(cell)); - btorf_pop(stringf("next %s", log_id(cell))); + btorf_pop(stringf("next %s", cell)); } vector> mtodo; @@ -1388,7 +1387,7 @@ struct BtorWorker int nid = it.first; Mem *mem = it.second; - btorf_push(stringf("next %s", log_id(mem->memid))); + btorf_push(stringf("next %s", mem->memid.unescape())); int abits = ceil_log2(mem->size); @@ -1436,7 +1435,7 @@ struct BtorWorker int nid2 = next_nid++; btorf("%d next %d %d %d%s\n", nid2, sid, nid, nid_head, (mem->cell ? getinfo(mem->cell) : getinfo(mem->mem))); - btorf_pop(stringf("next %s", log_id(mem->memid))); + btorf_pop(stringf("next %s", mem->memid.unescape())); } } @@ -1630,7 +1629,7 @@ struct BtorBackend : public Backend { log_cmd_error("No top module found.\n"); *f << stringf("; BTOR description generated by %s for module %s.\n", - yosys_maybe_version(), log_id(topmod)); + yosys_maybe_version(), topmod); BtorWorker(*f, topmod, verbose, single_bad, cover_mode, print_internal_names, info_filename, ywmap_filename); diff --git a/backends/cxxrtl/CMakeLists.txt b/backends/cxxrtl/CMakeLists.txt new file mode 100644 index 000000000..f5d10539a --- /dev/null +++ b/backends/cxxrtl/CMakeLists.txt @@ -0,0 +1,19 @@ +yosys_backend(cxxrtl + cxxrtl_backend.cc + DATA_DIR + include/backends/cxxrtl + DATA_FILES + runtime/README.txt + runtime/cxxrtl/cxxrtl.h + runtime/cxxrtl/cxxrtl_vcd.h + runtime/cxxrtl/cxxrtl_time.h + runtime/cxxrtl/cxxrtl_replay.h + runtime/cxxrtl/capi/cxxrtl_capi.cc + runtime/cxxrtl/capi/cxxrtl_capi.h + runtime/cxxrtl/capi/cxxrtl_capi_vcd.cc + runtime/cxxrtl/capi/cxxrtl_capi_vcd.h + REQUIRES + hierarchy + flatten + proc +) diff --git a/backends/cxxrtl/Makefile.inc b/backends/cxxrtl/Makefile.inc deleted file mode 100644 index dd77d2ad3..000000000 --- a/backends/cxxrtl/Makefile.inc +++ /dev/null @@ -1,11 +0,0 @@ - -OBJS += backends/cxxrtl/cxxrtl_backend.o - -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/cxxrtl.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/cxxrtl_time.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/cxxrtl_replay.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/capi/cxxrtl_capi.cc)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/capi/cxxrtl_capi.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/capi/cxxrtl_capi_vcd.cc)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/capi/cxxrtl_capi_vcd.h)) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 71913d2db..ac69bda27 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -251,7 +251,7 @@ CxxrtlPortType cxxrtl_port_type(RTLIL::Module *module, RTLIL::IdString port) 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)); + module, log_signal(output_wire)); else if (is_comb) return CxxrtlPortType::COMB; else if (is_sync) @@ -851,7 +851,7 @@ struct CxxrtlWorker { 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)); + log_cmd_error("Attribute `cxxrtl_template' of module `%s' is not a string.\n", module); std::vector param_names = split_by(module->get_string_attribute(ID(cxxrtl_template)), " \t"); for (const auto ¶m_name : param_names) { @@ -861,7 +861,7 @@ struct CxxrtlWorker { 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()); + module, param_name.c_str()); } return param_names; } @@ -907,12 +907,12 @@ struct CxxrtlWorker { 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)); + cell->module, cell, param_name.c_str(), 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)); + param_name.c_str(), cell->module, cell, cell_module); params += std::to_string(cell->getParam(id_param_name).as_int()); } params += ">"; @@ -2576,7 +2576,7 @@ struct CxxrtlWorker { } dec_indent(); - log_debug("Debug information statistics for module `%s':\n", log_id(module)); + log_debug("Debug information statistics for module `%s':\n", module); log_debug(" Scopes: %zu", count_scopes); log_debug(" Public wires: %zu, of which:\n", count_public_wires); log_debug(" Member wires: %zu, of which:\n", count_member_wires); @@ -2776,7 +2776,8 @@ struct CxxrtlWorker { { RTLIL::Module *top_module = nullptr; std::vector modules; - TopoSort topo_design; + using Order = IdString::compare_ptr_by_name; + TopoSort topo_design; for (auto module : design->modules()) { if (!design->selected_module(module)) continue; @@ -2939,7 +2940,7 @@ struct CxxrtlWorker { 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)); + module, log_signal(wire)); std::string edges = wire->get_string_attribute(ID(cxxrtl_edge)); for (int i = 0; i < GetSize(wire); i++) { @@ -2952,7 +2953,7 @@ struct CxxrtlWorker { 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)); + module, log_signal(wire)); } } } @@ -2977,7 +2978,7 @@ struct CxxrtlWorker { for (auto cell : module->cells()) { if (!cell->known()) - log_cmd_error("Unknown cell `%s'.\n", log_id(cell->type)); + log_cmd_error("Unknown cell `%s'.\n", cell->type.unescape()); if (cell->is_mem_cell()) continue; @@ -2986,7 +2987,7 @@ struct CxxrtlWorker { 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)); + log_cmd_error("External blackbox cell `%s' is not marked as a CXXRTL blackbox.\n", cell->type.unescape()); if (cell_module && cell_module->get_bool_attribute(ID(cxxrtl_blackbox)) && @@ -3115,9 +3116,9 @@ struct CxxrtlWorker { } if (!feedback_wires.empty()) { has_feedback_arcs = true; - log("Module `%s' contains feedback arcs through wires:\n", log_id(module)); + log("Module `%s' contains feedback arcs through wires:\n", module); for (auto wire : feedback_wires) - log(" %s\n", log_id(wire)); + log(" %s\n", wire); } // Conservatively assign wire types. Assignment of types BUFFERED and MEMBER is final, but assignment @@ -3188,7 +3189,7 @@ struct CxxrtlWorker { 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_cmd_error("Wire %s.%s has multiple drivers!\n", module, wire); log_assert(flow.wire_comb_defs[wire].size() == 1); FlowGraph::Node *node = *flow.wire_comb_defs[wire].begin(); switch (node->type) { @@ -3236,9 +3237,9 @@ struct CxxrtlWorker { 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)); + log("Module `%s' contains buffered combinatorial wires:\n", module); for (auto wire : buffered_comb_wires) - log(" %s\n", log_id(wire)); + log(" %s\n", wire); } // Record whether eval() requires only one delta cycle in this module. @@ -3419,7 +3420,7 @@ struct CxxrtlWorker { 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)); + log_cmd_error("Can't handle partially selected module `%s'!\n", module); if (!design->selected_module(module)) continue; diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index fbbe2373f..521cce4b0 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -614,7 +614,7 @@ struct value : public expr_base> { int64_t divisor_shift = divisor.ctlz() - dividend.ctlz(); assert(divisor_shift >= 0); divisor = divisor.shl(value{(chunk::type) divisor_shift}); - for (size_t step = 0; step <= divisor_shift; step++) { + for (size_t step = 0; step <= (uint64_t) divisor_shift; step++) { quotient = quotient.shl(value{1u}); if (!dividend.ucmp(divisor)) { dividend = dividend.sub(divisor); @@ -1119,7 +1119,7 @@ struct fmt_part { case STRING: { buf.reserve(Bits/8); - for (int i = 0; i < Bits; i += 8) { + for (size_t i = 0; i < Bits; i += 8) { char ch = 0; for (int j = 0; j < 8 && i + j < int(Bits); j++) if (val.bit(i + j)) diff --git a/backends/edif/CMakeLists.txt b/backends/edif/CMakeLists.txt new file mode 100644 index 000000000..126d09f07 --- /dev/null +++ b/backends/edif/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(edif + edif.cc +) diff --git a/backends/edif/Makefile.inc b/backends/edif/Makefile.inc deleted file mode 100644 index 93de0e24f..000000000 --- a/backends/edif/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/edif/edif.o - diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index 61d6ee254..9d3392e99 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -23,16 +23,18 @@ #include "kernel/rtlil.h" #include "kernel/register.h" #include "kernel/sigtools.h" -#include "kernel/celltypes.h" +#include "kernel/newcelltypes.h" #include "kernel/log.h" #include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true) -#define EDIF_DEFR(_id, _ren, _bl, _br) edif_names(RTLIL::unescape_id(_id), true, _ren, _bl, _br) -#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false) +#define EDIF_DEF(_id) edif_names(_id.unescape(), true) +#define EDIF_DEFR(_id, _ren, _bl, _br) edif_names(_id.unescape(), true, _ren, _bl, _br) +#define EDIF_REF(_id) edif_names(_id.unescape(), false) +#define EDIF_DEF_STR(_id) edif_names(RTLIL::unescape_id(_id), true) +#define EDIF_REF_STR(_id) edif_names(RTLIL::unescape_id(_id), false) struct EdifNames { @@ -138,7 +140,7 @@ struct EdifBackend : public Backend { bool lsbidx = false; std::map> lib_cell_ports; bool nogndvcc = false, gndvccy = false, keepmode = false; - CellTypes ct(design); + NewCellTypes ct(design); EdifNames edif_names; size_t argidx; @@ -207,9 +209,9 @@ struct EdifBackend : public Backend { 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)); + log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", module->name.unescape()); 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)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", module->name.unescape()); for (auto cell : module->cells()) { @@ -227,7 +229,7 @@ struct EdifBackend : public Backend { 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("(edif %s\n", EDIF_DEF_STR(top_module_name)); *f << stringf(" (edifVersion 2 0 0)\n"); *f << stringf(" (edifLevel 0)\n"); *f << stringf(" (keywordMap (keywordLevel 0))\n"); @@ -317,12 +319,12 @@ struct EdifBackend : public Backend { 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)); + // log("Next in topological sort: %s\n", it.first->name.unescape()); 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)); + log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", module_deps.begin()->first->name.unescape()); while (sorted_modules_idx < sorted_modules.size()) module_deps.erase(sorted_modules.at(sorted_modules_idx++)); } @@ -486,7 +488,7 @@ struct EdifBackend : public Backend { 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])); + i, module, cell, p.first.unescape(), log_signal(sig[i])); else { int member_idx = lsbidx ? i : GetSize(sig)-i-1; auto m = design->module(cell->type); @@ -534,7 +536,7 @@ struct EdifBackend : public Backend { if (netname[i] == ' ' || netname[i] == '\\') netname.erase(netname.begin() + i--); } - *f << stringf(" (net %s (joined\n", EDIF_DEF(netname)); + *f << stringf(" (net %s (joined\n", EDIF_DEF_STR(netname)); for (auto &ref : it.second) *f << stringf(" %s\n", ref.first); if (sig.wire == NULL) { @@ -572,7 +574,7 @@ struct EdifBackend : public Backend { if (keepmode) { - *f << stringf(" (net %s (joined\n", EDIF_DEF(netname)); + *f << stringf(" (net %s (joined\n", EDIF_DEF_STR(netname)); auto &refs = net_join_db.at(mapped_sig); for (auto &ref : refs) @@ -588,7 +590,7 @@ struct EdifBackend : public Backend { } else { - log_warning("Ignoring conflicting 'keep' property on net %s. Use -keep to generate the extra net nevertheless.\n", EDIF_DEF(netname)); + log_warning("Ignoring conflicting 'keep' property on net %s. Use -keep to generate the extra net nevertheless.\n", EDIF_DEF_STR(netname)); } } } @@ -599,8 +601,8 @@ struct EdifBackend : public Backend { } *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(" (design %s\n", EDIF_DEF_STR(top_module_name)); + *f << stringf(" (cellRef %s (libraryRef DESIGN))\n", EDIF_REF_STR(top_module_name)); *f << stringf(" )\n"); *f << stringf(")\n"); diff --git a/backends/firrtl/CMakeLists.txt b/backends/firrtl/CMakeLists.txt new file mode 100644 index 000000000..2f38cd208 --- /dev/null +++ b/backends/firrtl/CMakeLists.txt @@ -0,0 +1,8 @@ +yosys_backend(firrtl + firrtl.cc + REQUIRES + pmuxtree + bmuxmap + demuxmap + bwmuxmap +) diff --git a/backends/firrtl/Makefile.inc b/backends/firrtl/Makefile.inc deleted file mode 100644 index fdf100d34..000000000 --- a/backends/firrtl/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/firrtl/firrtl.o - diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 577d95ad7..db5036552 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -82,7 +82,7 @@ const char *make_id(IdString id) if (namecache.count(id) != 0) return namecache.at(id).c_str(); - string new_id = log_id(id); + string new_id = id.unescape(); for (int i = 0; i < GetSize(new_id); i++) { @@ -263,7 +263,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream if (wire->port_input && wire->port_output) { - log_error("Module port %s.%s is inout!\n", log_id(mod_instance), log_id(wire)); + log_error("Module port %s.%s is inout!\n", mod_instance, wire); } const std::string portDecl = stringf("%s%s %s: UInt<%d> %s\n", @@ -559,12 +559,12 @@ struct FirrtlWorker 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)); + module, 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)); + log_error("Module port %s.%s is inout!\n", module, wire); port_decls.push_back(stringf("%s%s %s: UInt<%d> %s\n", indent, wire->port_input ? "input" : "output", wireName, wire->width, wireFileinfo.c_str())); } @@ -833,7 +833,7 @@ struct FirrtlWorker 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)); + log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, module, cell); } b_expr = std::to_string(shiftAmount); firrtl_width = a_width + shiftAmount; @@ -844,7 +844,7 @@ struct FirrtlWorker firrtl_width = a_width + (1 << b_width) - 1; } } else { - log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell)); + log_error("Non power 2: %s.%s\n", module, cell); } } @@ -905,7 +905,7 @@ struct FirrtlWorker { 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)); + log_error("Negative edge clock on FF %s.%s.\n", module, cell); int width = cell->parameters.at(ID::WIDTH).as_int(); string expr = make_expr(cell->getPort(ID::D)); @@ -983,7 +983,7 @@ struct FirrtlWorker if (cell->type == ID($scopeinfo)) continue; - log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); + log_error("Cell type not supported: %s (%s.%s)\n", cell->type.unescape(), module, cell); } for (auto &mem : memories) { @@ -991,10 +991,10 @@ struct FirrtlWorker 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)); + log_error("Memory with initialization data: %s.%s\n", module, mem.memid.unescape()); if (mem.start_offset != 0) - log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(mem.memid)); + log_error("Memory with nonzero offset: %s.%s\n", module, mem.memid.unescape()); for (int i = 0; i < GetSize(mem.rd_ports); i++) { @@ -1002,7 +1002,7 @@ struct FirrtlWorker string port_name(stringf("%s.r%d", mem_id, i)); if (port.clk_enable) - log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid)); + log_error("Clocked read port %d on memory %s.%s.\n", i, module, mem.memid.unescape()); std::ostringstream rpe; @@ -1023,12 +1023,12 @@ struct FirrtlWorker string port_name(stringf("%s.w%d", mem_id, i)); if (!port.clk_enable) - log_error("Unclocked write port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid)); + log_error("Unclocked write port %d on memory %s.%s.\n", i, module, mem.memid.unescape()); if (!port.clk_polarity) - log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(mem.memid)); + log_error("Negedge write port %d on memory %s.%s.\n", i, module, mem.memid.unescape()); 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)); + log_error("Complex write enable on port %d on memory %s.%s.\n", i, module, mem.memid.unescape()); std::ostringstream wpe; diff --git a/backends/functional/CMakeLists.txt b/backends/functional/CMakeLists.txt new file mode 100644 index 000000000..5e7a6e92f --- /dev/null +++ b/backends/functional/CMakeLists.txt @@ -0,0 +1,12 @@ +yosys_backend(functional_cxx + cxx.cc +) +yosys_backend(functional_smt2 + smtlib.cc +) +yosys_backend(functional_rosette + smtlib_rosette.cc +) +yosys_test_pass(generic + test_generic.cc +) diff --git a/backends/functional/Makefile.inc b/backends/functional/Makefile.inc deleted file mode 100644 index 16d1c0542..000000000 --- a/backends/functional/Makefile.inc +++ /dev/null @@ -1,4 +0,0 @@ -OBJS += backends/functional/cxx.o -OBJS += backends/functional/smtlib.o -OBJS += backends/functional/smtlib_rosette.o -OBJS += backends/functional/test_generic.o diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index 7f4ad1ea7..d67bc9143 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -89,7 +89,7 @@ struct CxxStruct { } f.print("\n\t\ttemplate void visit(T &&fn) {{\n"); for (auto p : types) { - f.print("\t\t\tfn(\"{}\", {});\n", RTLIL::unescape_id(p.first), scope(p.first, p.first)); + f.print("\t\t\tfn(\"{}\", {});\n", p.first.unescape(), scope(p.first, p.first)); } f.print("\t\t}}\n"); f.print("\t}};\n\n"); diff --git a/backends/functional/smtlib.cc b/backends/functional/smtlib.cc index 1504c8fba..0451af4c7 100644 --- a/backends/functional/smtlib.cc +++ b/backends/functional/smtlib.cc @@ -80,7 +80,7 @@ public: SmtStruct(std::string name, SmtScope &scope) : scope(scope), name(name) {} void insert(IdString field_name, SmtSort sort) { field_names(field_name); - auto accessor = scope.unique_name("\\" + name + "_" + RTLIL::unescape_id(field_name)); + auto accessor = scope.unique_name("\\" + name + "_" + field_name.unescape()); fields.emplace_back(Field{sort, accessor}); } void write_definition(SExprWriter &w) { @@ -99,7 +99,7 @@ public: w.open(list(name)); for(auto field_name : field_names) { w << fn(field_name); - w.comment(RTLIL::unescape_id(field_name), true); + w.comment(field_name.unescape(), true); } w.close(); } diff --git a/backends/functional/smtlib_rosette.cc b/backends/functional/smtlib_rosette.cc index 73e1b48c6..b37f948b6 100644 --- a/backends/functional/smtlib_rosette.cc +++ b/backends/functional/smtlib_rosette.cc @@ -106,7 +106,7 @@ public: w.open(list(name)); for(auto field_name : field_names) { w << fn(field_name); - w.comment(RTLIL::unescape_id(field_name), true); + w.comment(field_name.unescape(), true); } w.close(); } @@ -281,7 +281,7 @@ struct SmtrModule { w.push(); w.open(list()); w.open(list("assoc-result")); - w << list("assoc", "\"" + RTLIL::unescape_id(input->name) + "\"", inputs_name); + w << list("assoc", "\"" + input->name.unescape() + "\"", inputs_name); w.pop(); w.open(list("if", "assoc-result")); w << list("cdr", "assoc-result"); @@ -298,7 +298,7 @@ struct SmtrModule { w << list(*output_helper_name, outputs_name); w.open(list("list")); for (auto output : ir.outputs()) { - w << list("cons", "\"" + RTLIL::unescape_id(output->name) + "\"", output_struct.access("outputs", output->name)); + w << list("cons", "\"" + output->name.unescape() + "\"", output_struct.access("outputs", output->name)); } w.pop(); } diff --git a/backends/functional/test_generic.cc b/backends/functional/test_generic.cc index c01649a0f..343fcfc0f 100644 --- a/backends/functional/test_generic.cc +++ b/backends/functional/test_generic.cc @@ -146,11 +146,11 @@ struct FunctionalTestGeneric : public Pass log("Dumping module `%s'.\n", module->name); auto fir = Functional::IR::from_module(module); for(auto node : fir) - std::cout << RTLIL::unescape_id(node.name()) << " = " << node.to_string([](auto n) { return RTLIL::unescape_id(n.name()); }) << "\n"; + std::cout << node.name().unescape() << " = " << node.to_string([](auto n) { return n.name().unescape(); }) << "\n"; for(auto output : fir.all_outputs()) - std::cout << RTLIL::unescape_id(output->kind) << " " << RTLIL::unescape_id(output->name) << " = " << RTLIL::unescape_id(output->value().name()) << "\n"; + std::cout << output->kind.unescape() << " " << output->name.unescape() << " = " << output->value().name().unescape() << "\n"; for(auto state : fir.all_states()) - std::cout << RTLIL::unescape_id(state->kind) << " " << RTLIL::unescape_id(state->name) << " = " << RTLIL::unescape_id(state->next_value().name()) << "\n"; + std::cout << state->kind.unescape() << " " << state->name.unescape() << " = " << state->next_value().name().unescape() << "\n"; } } } FunctionalCxxBackend; diff --git a/backends/intersynth/CMakeLists.txt b/backends/intersynth/CMakeLists.txt new file mode 100644 index 000000000..e34bab4e1 --- /dev/null +++ b/backends/intersynth/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(intersynth + intersynth.cc +) diff --git a/backends/intersynth/Makefile.inc b/backends/intersynth/Makefile.inc deleted file mode 100644 index 85df1b393..000000000 --- a/backends/intersynth/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/intersynth/intersynth.o - diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc index 78eab17da..1704ba429 100644 --- a/backends/intersynth/intersynth.cc +++ b/backends/intersynth/intersynth.cc @@ -20,7 +20,7 @@ #include "kernel/rtlil.h" #include "kernel/register.h" #include "kernel/sigtools.h" -#include "kernel/celltypes.h" +#include "kernel/newcelltypes.h" #include "kernel/log.h" #include @@ -41,7 +41,7 @@ static std::string netname(std::set &conntypes_code, std::setname); + return sig.as_wire()->name.unescape(); } struct IntersynthBackend : public Backend { @@ -117,7 +117,7 @@ struct IntersynthBackend : public Backend { std::set conntypes_code, celltypes_code; std::string netlists_code; - CellTypes ct(design); + NewCellTypes ct(design); for (auto lib : libs) ct.setup_design(lib); @@ -133,26 +133,26 @@ struct IntersynthBackend : public Backend { 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)); + log_cmd_error("Can't handle partially selected module %s!\n", module->name.unescape()); continue; } - log("Generating netlist %s.\n", log_id(module->name)); + log("Generating netlist %s.\n", module->name.unescape()); 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)); + netlists_code += stringf("# Netlist of module %s\n", module->name.unescape()); + netlists_code += stringf("netlist %s\n", module->name.unescape()); // 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), + wire->name.unescape(), wire->width, wire->port_input ? "*" : "", + wire->port_input ? "input" : "output", wire->name.unescape(), wire->width, wire->name.unescape())); + netlists_code += stringf("node %s %s PORT %s\n", wire->name.unescape(), wire->name.unescape(), netname(conntypes_code, celltypes_code, constcells_code, sigmap(wire)).c_str()); } } @@ -163,26 +163,26 @@ struct IntersynthBackend : public Backend { 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)); + log_error("Found unknown cell type %s in module!\n", cell->type.unescape()); - celltype_code = stringf("celltype %s", log_id(cell->type)); - node_code = stringf("node %s %s", log_id(cell->name), log_id(cell->type)); + celltype_code = stringf("celltype %s", cell->type.unescape()); + node_code = stringf("node %s %s", cell->name.unescape(), cell->type.unescape()); 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)); + celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", port.first.unescape()); + node_code += stringf(" %s %s", port.first.unescape(), netname(conntypes_code, celltypes_code, constcells_code, sig)); } } for (auto ¶m : cell->parameters) { - celltype_code += stringf(" cfg:%d %s", int(param.second.size()), log_id(param.first)); + celltype_code += stringf(" cfg:%d %s", int(param.second.size()), param.first.unescape()); if (param.second.size() != 32) { - node_code += stringf(" %s '", log_id(param.first)); + node_code += stringf(" %s '", param.first.unescape()); for (int i = param.second.size()-1; i >= 0; i--) node_code += param.second[i] == State::S1 ? "1" : "0"; } else - node_code += stringf(" %s 0x%x", log_id(param.first), param.second.as_int()); + node_code += stringf(" %s 0x%x", param.first.unescape(), param.second.as_int()); } celltypes_code.insert(celltype_code + "\n"); diff --git a/backends/jny/CMakeLists.txt b/backends/jny/CMakeLists.txt new file mode 100644 index 000000000..e76a74e97 --- /dev/null +++ b/backends/jny/CMakeLists.txt @@ -0,0 +1,5 @@ +yosys_backend(jny + jny.cc + PROVIDES + jny +) diff --git a/backends/jny/Makefile.inc b/backends/jny/Makefile.inc deleted file mode 100644 index 5e417128e..000000000 --- a/backends/jny/Makefile.inc +++ /dev/null @@ -1,2 +0,0 @@ - -OBJS += backends/jny/jny.o diff --git a/backends/jny/jny.cc b/backends/jny/jny.cc index ee0c0d14c..2f6899f4a 100644 --- a/backends/jny/jny.cc +++ b/backends/jny/jny.cc @@ -91,7 +91,7 @@ struct JnyWriter { _cells.clear(); for (auto cell : mod->cells()) { - const auto cell_type = escape_string(RTLIL::unescape_id(cell->type)); + const auto cell_type = escape_string(cell->type.unescape()); if (_cells.find(cell_type) == _cells.end()) _cells.emplace(cell_type, std::vector()); @@ -214,7 +214,7 @@ struct JnyWriter 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 << " \"name\": \"" << escape_string(sig.first.unescape()) << "\",\n"; f << _indent << " \"signals\": [\n"; write_sigspec(sig.second, indent_level + 2); @@ -232,7 +232,7 @@ struct JnyWriter const auto _indent = gen_indent(indent_level); f << _indent << "{\n"; - f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(RTLIL::unescape_id(mod->name))); + f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(mod->name.unescape())); f << _indent << " \"cell_sorts\": [\n"; bool first_sort{true}; @@ -275,12 +275,12 @@ struct JnyWriter const auto _indent = gen_indent(indent_level); bool first_port{true}; - for (auto con : port_cell->connections()) { + for (auto& con : port_cell->connections()) { if (!first_port) f << ",\n"; f << _indent << " {\n"; - f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(RTLIL::unescape_id(con.first))); + f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(con.first.unescape())); f << _indent << " \"direction\": \""; if (port_cell->input(con.first)) f << "i"; @@ -351,10 +351,10 @@ struct JnyWriter f << stringf(",\n"); const auto param_val = param.second; if (!param_val.empty()) { - f << stringf(" %s\"%s\": ", _indent, escape_string(RTLIL::unescape_id(param.first))); + f << stringf(" %s\"%s\": ", _indent, escape_string(param.first.unescape())); write_param_val(param_val); } else { - f << stringf(" %s\"%s\": true", _indent, escape_string(RTLIL::unescape_id(param.first))); + f << stringf(" %s\"%s\": true", _indent, escape_string(param.first.unescape())); } first_param = false; @@ -366,7 +366,7 @@ struct JnyWriter log_assert(cell != nullptr); f << _indent << " {\n"; - f << stringf(" %s\"name\": \"%s\"", _indent, escape_string(RTLIL::unescape_id(cell->name))); + f << stringf(" %s\"name\": \"%s\"", _indent, escape_string(cell->name.unescape())); if (_include_connections) { f << ",\n" << _indent << " \"connections\": [\n"; diff --git a/backends/json/CMakeLists.txt b/backends/json/CMakeLists.txt new file mode 100644 index 000000000..99c404d92 --- /dev/null +++ b/backends/json/CMakeLists.txt @@ -0,0 +1,5 @@ +yosys_backend(json + json.cc + PROVIDES + json +) diff --git a/backends/json/Makefile.inc b/backends/json/Makefile.inc deleted file mode 100644 index a463daf91..000000000 --- a/backends/json/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/json/json.o - diff --git a/backends/json/json.cc b/backends/json/json.cc index b04083622..23d18fb15 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -76,7 +76,7 @@ struct JsonWriter string get_name(IdString name) { - return get_string(RTLIL::unescape_id(name)); + return get_string(name.unescape()); } string get_bits(SigSpec sig) @@ -152,7 +152,7 @@ struct JsonWriter 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)); + log_error("Module %s contains processes, which are not supported by JSON backend (run `proc` first).\n", module); } f << stringf(" %s: {\n", get_name(module->name)); @@ -316,13 +316,13 @@ struct JsonWriter f << stringf(" /* %3d */ [ ", node_idx); if (node.portbit >= 0) f << stringf("\"%sport\", \"%s\", %d", node.inverter ? "n" : "", - log_id(node.portname), node.portbit); + node.portname.unescape(), 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(", \"%s\", %d", op.first.unescape(), op.second); f << stringf(" ]"); node_idx++; } diff --git a/backends/rtlil/CMakeLists.txt b/backends/rtlil/CMakeLists.txt new file mode 100644 index 000000000..40b3cffe0 --- /dev/null +++ b/backends/rtlil/CMakeLists.txt @@ -0,0 +1,11 @@ +yosys_backend(rtlil + rtlil_backend.cc + rtlil_backend.h + PROVIDES + dump + DATA_DIR + include/backends/rtlil + DATA_FILES + rtlil_backend.h + ESSENTIAL +) diff --git a/backends/rtlil/Makefile.inc b/backends/rtlil/Makefile.inc deleted file mode 100644 index f691282ca..000000000 --- a/backends/rtlil/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/rtlil/rtlil_backend.o - diff --git a/backends/simplec/CMakeLists.txt b/backends/simplec/CMakeLists.txt new file mode 100644 index 000000000..1a9feed9f --- /dev/null +++ b/backends/simplec/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(simplec + simplec.cc +) diff --git a/backends/simplec/Makefile.inc b/backends/simplec/Makefile.inc deleted file mode 100644 index fee1376c5..000000000 --- a/backends/simplec/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/simplec/simplec.o - diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc index 8ebc685f0..baf5aa006 100644 --- a/backends/simplec/simplec.cc +++ b/backends/simplec/simplec.cc @@ -78,7 +78,7 @@ struct HierDirtyFlags 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)); + prefix + cid(cell->name) + ".", log_prefix + "." + prefix + cell->name.unescape()); } } @@ -354,23 +354,23 @@ struct SimplecWorker 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), cid(w->name), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), 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), cid(w->name), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), 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), cid(w->name), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), 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), cid(c->name), log_id(c))); + struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type), cid(c->name), c)); struct_declarations.push_back(stringf("};")); struct_declarations.push_back("#endif"); @@ -391,7 +391,7 @@ struct SimplecWorker 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))); + stringf(" // %s (%s)", cell, cell->type.unescape())); work->set_dirty(y); return; @@ -418,7 +418,7 @@ struct SimplecWorker 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))); + stringf(" // %s (%s)", cell, cell->type.unescape())); work->set_dirty(y); return; @@ -441,7 +441,7 @@ struct SimplecWorker 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))); + stringf(" // %s (%s)", cell, cell->type.unescape())); work->set_dirty(y); return; @@ -466,7 +466,7 @@ struct SimplecWorker 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))); + stringf(" // %s (%s)", cell, cell->type.unescape())); work->set_dirty(y); return; @@ -490,13 +490,13 @@ struct SimplecWorker 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))); + stringf(" // %s (%s)", cell, cell->type.unescape())); work->set_dirty(y); return; } - log_error("No C model for %s available at the moment (FIXME).\n", log_id(cell->type)); + log_error("No C model for %s available at the moment (FIXME).\n", cell->type.unescape()); } void eval_dirty(HierDirtyFlags *work) @@ -517,7 +517,7 @@ struct SimplecWorker if (chunk.wire == nullptr) continue; if (verbose) - log(" Propagating %s.%s[%d:%d].\n", work->log_prefix, log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset); + log(" Propagating %s.%s[%d:%d].\n", work->log_prefix, chunk.wire, chunk.offset+chunk.width-1, chunk.offset); funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix, log_signal(chunk))); } @@ -539,8 +539,8 @@ struct SimplecWorker work->parent->set_dirty(parent_bit); if (verbose) - log(" Propagating %s.%s[%d] -> %s.%s[%d].\n", work->log_prefix, log_id(bit.wire), bit.offset, - work->parent->log_prefix.c_str(), log_id(parent_bit.wire), parent_bit.offset); + log(" Propagating %s.%s[%d] -> %s.%s[%d].\n", work->log_prefix, bit.wire, bit.offset, + work->parent->log_prefix.c_str(), parent_bit.wire, parent_bit.offset); } for (auto &port : bit2cell[work->module][bit]) @@ -556,12 +556,12 @@ struct SimplecWorker child->set_dirty(child_bit); if (verbose) - log(" Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", work->log_prefix, 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); + log(" Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", work->log_prefix, bit.wire, bit.offset, + work->log_prefix.c_str(), std::get<0>(port), child_bit.wire, child_bit.offset); } else { if (verbose) - log(" Marking cell %s.%s (via %s.%s[%d]).\n", work->log_prefix, log_id(std::get<0>(port)), - work->log_prefix.c_str(), log_id(bit.wire), bit.offset); + log(" Marking cell %s.%s (via %s.%s[%d]).\n", work->log_prefix, std::get<0>(port), + work->log_prefix.c_str(), bit.wire, bit.offset); work->set_dirty(std::get<0>(port)); } } @@ -576,10 +576,10 @@ struct SimplecWorker if (cell == nullptr || topoidx.at(cell) < topoidx.at(c)) cell = c; - string hiername = work->log_prefix + "." + log_id(cell); + string hiername = work->log_prefix + "." + cell->name.unescape(); if (verbose) - log(" Evaluating %s (%s, best of %d).\n", hiername, log_id(cell->type), GetSize(work->dirty_cells)); + log(" Evaluating %s (%s, best of %d).\n", hiername, cell->type.unescape(), GetSize(work->dirty_cells)); if (activated_cells.count(hiername)) reactivated_cells.insert(hiername); @@ -618,8 +618,8 @@ struct SimplecWorker 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->log_prefix.c_str(), canonical_bit.wire, canonical_bit.offset, + work->log_prefix.c_str(), bit.wire, bit.offset); } work->sticky_dirty_bits.clear(); @@ -716,7 +716,7 @@ struct SimplecWorker { create_module_struct(mod); - HierDirtyFlags work(mod, IdString(), nullptr, "state->", log_id(mod->name)); + HierDirtyFlags work(mod, IdString(), nullptr, "state->", mod->name.unescape()); make_init_func(&work); make_eval_func(&work); diff --git a/backends/smt2/CMakeLists.txt b/backends/smt2/CMakeLists.txt new file mode 100644 index 000000000..c60bace7b --- /dev/null +++ b/backends/smt2/CMakeLists.txt @@ -0,0 +1,20 @@ +yosys_backend(smt2 + smt2.cc + REQUIRES + json11 + DATA_DIR + python3 + DATA_FILES + smtio.py + ywio.py + REQUIRES + bmuxmap + demuxmap +) + +yosys_python_executable(yosys-smtbmc smtbmc.py + INSTALL_IF YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY +) +yosys_python_executable(yosys-witness witness.py + INSTALL_IF YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY +) diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc deleted file mode 100644 index 3afe990e7..000000000 --- a/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/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index d80622029..a9030e18a 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -20,7 +20,7 @@ #include "kernel/rtlil.h" #include "kernel/register.h" #include "kernel/sigtools.h" -#include "kernel/celltypes.h" +#include "kernel/newcelltypes.h" #include "kernel/log.h" #include "kernel/mem.h" #include "libs/json11/json11.hpp" @@ -32,7 +32,7 @@ PRIVATE_NAMESPACE_BEGIN struct Smt2Worker { - CellTypes ct; + NewCellTypes ct; SigMap sigmap; RTLIL::Module *module; bool bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode; @@ -60,7 +60,7 @@ struct Smt2Worker const char *get_id(IdString n) { if (ids.count(n) == 0) { - std::string str = log_id(n); + std::string str = n.unescape(); for (int i = 0; i < GetSize(str); i++) { if (str[i] == '\\') str[i] = '/'; @@ -207,7 +207,7 @@ struct Smt2Worker } else if (is_output || !is_input) log_error("Unsupported or unknown directionality on port %s of cell %s.%s (%s).\n", - log_id(conn.first), log_id(module), log_id(cell), log_id(cell->type)); + conn.first.unescape(), module, cell, cell->type.unescape()); if (cell->type.in(ID($dff), ID($_DFF_P_), ID($_DFF_N_)) && conn.first.in(ID::CLK, ID::C)) { @@ -448,7 +448,7 @@ struct Smt2Worker } if (verbose) - log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); + log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", cell); decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(bit))); @@ -498,7 +498,7 @@ struct Smt2Worker processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr); if (verbose) - log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); + log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", cell); if (type == 'b') { decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", @@ -529,7 +529,7 @@ struct Smt2Worker processed_expr += ch; if (verbose) - log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); + log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", cell); decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n", get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y))); @@ -541,7 +541,7 @@ struct Smt2Worker { if (verbose) log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "", - log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new"); + cell, cell->type.unescape(), exported_cells.count(cell) ? "old" : "new"); if (recursive_cells.count(cell)) log_error("Found logic loop in module %s! See cell %s.\n", get_id(module), get_id(cell)); @@ -750,7 +750,7 @@ struct Smt2Worker get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str()); if (verbose) - log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell)); + log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", cell); RTLIL::SigSpec sig = sigmap(cell->getPort(ID::Y)); decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", @@ -786,9 +786,9 @@ struct Smt2Worker has_async_wr = true; } if (has_async_wr && has_sync_wr) - log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", log_id(cell), log_id(module)); + log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", cell, module); - decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", get_id(mem->memid), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync")); + decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", mem->memid.unescape(), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync")); decls.push_back(witness_memory(get_id(mem->memid), cell, mem)); string memstate; @@ -813,7 +813,7 @@ struct Smt2Worker if (port.clk_enable) log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! " - "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(port.data), log_id(mem->memid), log_id(module)); + "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(port.data), mem->memid.unescape(), module); decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", get_id(module), i, get_id(mem->memid), get_id(module), abits, addr.c_str(), log_signal(addr_sig))); @@ -857,7 +857,7 @@ struct Smt2Worker if (port.clk_enable) log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! " - "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(port.data), log_id(mem->memid), log_id(module)); + "Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(port.data), mem->memid.unescape(), module); decls.push_back(stringf("(define-fun |%s_m:R%dA %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n", get_id(module), i, get_id(mem->memid), get_id(module), abits, addr.c_str(), log_signal(addr_sig))); @@ -928,30 +928,30 @@ struct Smt2Worker 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_smt2`.\n", - log_id(cell->type), log_id(module), log_id(cell)); + cell->type.unescape(), module, 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_smt2`.\n", - log_id(cell->type), log_id(module), log_id(cell)); + cell->type.unescape(), module, 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_smt2`.\n", - log_id(cell->type), log_id(module), log_id(cell)); + cell->type, module, cell); } log_error("Unsupported cell type %s for cell %s.%s.\n", - log_id(cell->type), log_id(module), log_id(cell)); + cell->type, module, cell); } void verify_smtlib2_module() { if (!module->get_blackbox_attribute()) - log_error("Module %s with smtlib2_module attribute must also have blackbox attribute.\n", log_id(module)); + log_error("Module %s with smtlib2_module attribute must also have blackbox attribute.\n", module); if (module->cells().size() > 0) - log_error("Module %s with smtlib2_module attribute must not have any cells inside it.\n", log_id(module)); + log_error("Module %s with smtlib2_module attribute must not have any cells inside it.\n", module); for (auto wire : module->wires()) if (!wire->port_id) - log_error("Wire %s.%s must be input or output since module has smtlib2_module attribute.\n", log_id(module), - log_id(wire)); + log_error("Wire %s.%s must be input or output since module has smtlib2_module attribute.\n", module, + wire); } void run() @@ -991,8 +991,8 @@ struct Smt2Worker } bool is_smtlib2_comb_expr = wire->has_attribute(ID::smtlib2_comb_expr); if (is_smtlib2_comb_expr && !is_smtlib2_module) - log_error("smtlib2_comb_expr is only valid in a module with the smtlib2_module attribute: wire %s.%s", log_id(module), - log_id(wire)); + log_error("smtlib2_comb_expr is only valid in a module with the smtlib2_module attribute: wire %s.%s", module, + wire); if (wire->port_id || is_register || contains_clock || wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) { RTLIL::SigSpec sig = sigmap(wire); std::vector comments; @@ -1023,10 +1023,10 @@ struct Smt2Worker smtlib2_comb_expr = "(let (\n" + smtlib2_inputs + ")\n" + wire->get_string_attribute(ID::smtlib2_comb_expr) + "\n)"; if (wire->port_input || !wire->port_output) - log_error("smtlib2_comb_expr is only valid on output: wire %s.%s", log_id(module), log_id(wire)); + log_error("smtlib2_comb_expr is only valid on output: wire %s.%s", module, wire); if (!bvmode && GetSize(sig) > 1) log_error("smtlib2_comb_expr is unsupported on multi-bit wires when -nobv is specified: wire %s.%s", - log_id(module), log_id(wire)); + module, wire); comments.push_back(witness_signal("blackbox", wire->width, 0, get_id(wire), -1, wire)); } @@ -1075,7 +1075,7 @@ struct Smt2Worker if (wire->attributes.count(ID::init)) { if (is_smtlib2_module) log_error("init attribute not allowed on wires in module with smtlib2_module attribute: wire %s.%s", - log_id(module), log_id(wire)); + module, wire); RTLIL::SigSpec sig = sigmap(wire); Const val = wire->attributes.at(ID::init); @@ -1381,7 +1381,7 @@ struct Smt2Worker } } - if (verbose) log("=> finalizing SMT2 representation of %s.\n", log_id(module)); + if (verbose) log("=> finalizing SMT2 representation of %s.\n", module); for (auto c : hiercells) { assert_list.push_back(stringf("(|%s_a| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name))); @@ -1867,12 +1867,12 @@ struct Smt2Backend : public Backend { 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)); + // log("Next in topological sort: %s\n", it.first->name.unescape()); 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)); + log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", module_deps.begin()->first->name.unescape()); while (sorted_modules_idx < sorted_modules.size()) module_deps.erase(sorted_modules.at(sorted_modules_idx++)); } @@ -1902,7 +1902,7 @@ struct Smt2Backend : public Backend { if (module->has_processes_warn()) continue; - log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module)); + log("Creating SMT-LIBv2 representation of module %s.\n", module); Smt2Worker worker(module, bvmode, memmode, wiresmode, verbose, statebv, statedt, forallmode, mod_stbv_width, mod_clk_cache); worker.run(); diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py old mode 100644 new mode 100755 index 9dfbd2a25..60fa97e36 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!@PYTHON_SHEBANG@ # # yosys -- Yosys Open SYnthesis Suite # @@ -18,7 +18,7 @@ # import os, sys, getopt, re, bisect, json -##yosys-sys-path## +sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/@YOSYS_PROGRAM_PREFIX@yosys/python3"]] from smtio import SmtIo, SmtOpts, MkVcd from ywio import ReadWitness, WriteWitness, WitnessValues from collections import defaultdict diff --git a/backends/smt2/witness.py b/backends/smt2/witness.py old mode 100644 new mode 100755 index b7e25851c..83416c695 --- a/backends/smt2/witness.py +++ b/backends/smt2/witness.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!@PYTHON_SHEBANG@ # # yosys -- Yosys Open SYnthesis Suite # @@ -18,7 +18,7 @@ # import os, sys, itertools, re -##yosys-sys-path## +sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/@YOSYS_PROGRAM_PREFIX@yosys/python3"]] import json import click diff --git a/backends/smv/CMakeLists.txt b/backends/smv/CMakeLists.txt new file mode 100644 index 000000000..ea9e85f28 --- /dev/null +++ b/backends/smv/CMakeLists.txt @@ -0,0 +1,7 @@ +yosys_backend(smv + smv.cc + REQUIRES + bmuxmap + demuxmap + bwmuxmap +) diff --git a/backends/smv/Makefile.inc b/backends/smv/Makefile.inc deleted file mode 100644 index 66c192d80..000000000 --- a/backends/smv/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/smv/smv.o - diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc index a6ccbf27f..01f95ef45 100644 --- a/backends/smv/smv.cc +++ b/backends/smv/smv.cc @@ -20,7 +20,7 @@ #include "kernel/rtlil.h" #include "kernel/register.h" #include "kernel/sigtools.h" -#include "kernel/celltypes.h" +#include "kernel/newcelltypes.h" #include "kernel/log.h" #include @@ -29,7 +29,7 @@ PRIVATE_NAMESPACE_BEGIN struct SmvWorker { - CellTypes ct; + NewCellTypes ct; SigMap sigmap; RTLIL::Module *module; std::ostream &f; @@ -217,7 +217,7 @@ struct SmvWorker 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))); + inputvars.push_back(stringf("%s : unsigned word[%d]; -- %s", cid(wire->name), wire->width, wire)); if (wire->attributes.count(ID::init)) assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at(ID::init)))); @@ -579,18 +579,18 @@ struct SmvWorker 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)); + cell->type.unescape(), module, 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)); + cell->type.unescape(), module, 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)); + cell->type.unescape(), module, cell); } log_error("Unsupported cell type %s for cell %s.%s.\n", - log_id(cell->type), log_id(module), log_id(cell)); + cell->type.unescape(), module, cell); } // f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type)); @@ -799,7 +799,7 @@ struct SmvBackend : public Backend { *f << stringf("-- SMV description generated by %s\n", yosys_maybe_version()); - log("Creating SMV representation of module %s.\n", log_id(module)); + log("Creating SMV representation of module %s.\n", module); SmvWorker worker(module, verbose, *f); worker.run(); @@ -819,7 +819,7 @@ struct SmvBackend : public Backend { *f << stringf("-- SMV description generated by %s\n", yosys_maybe_version()); for (auto module : modules) { - log("Creating SMV representation of module %s.\n", log_id(module)); + log("Creating SMV representation of module %s.\n", module); SmvWorker worker(module, verbose, *f); worker.run(); } diff --git a/backends/spice/CMakeLists.txt b/backends/spice/CMakeLists.txt new file mode 100644 index 000000000..efbfc84d0 --- /dev/null +++ b/backends/spice/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(spice + spice.cc +) diff --git a/backends/spice/Makefile.inc b/backends/spice/Makefile.inc deleted file mode 100644 index 9c8530cb2..000000000 --- a/backends/spice/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/spice/spice.o - diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc index 16458d647..5f14a2a66 100644 --- a/backends/spice/spice.cc +++ b/backends/spice/spice.cc @@ -30,7 +30,7 @@ PRIVATE_NAMESPACE_BEGIN static string spice_id2str(IdString id) { static const char *escape_chars = "$\\[]()<>="; - string s = RTLIL::unescape_id(id); + string s = id.unescape(); for (auto &ch : s) if (strchr(escape_chars, ch) != nullptr) ch = '_'; @@ -82,7 +82,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De 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)); + cell->type.unescape(), module, cell); for (auto &conn : cell->connections()) { RTLIL::SigSpec sig = sigmap(conn.second); port_sigs.push_back(sig); @@ -224,9 +224,9 @@ struct SpiceBackend : public Backend { 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)); + log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", 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)); + log_error("Found unmapped memories in module %s: unmapped memories are not supported in SPICE backend!\n", module); if (module->name == RTLIL::escape_id(top_module_name)) { top_module = module; diff --git a/backends/table/CMakeLists.txt b/backends/table/CMakeLists.txt new file mode 100644 index 000000000..371d1e8f0 --- /dev/null +++ b/backends/table/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(table + table.cc +) diff --git a/backends/table/Makefile.inc b/backends/table/Makefile.inc deleted file mode 100644 index 8cd1dc619..000000000 --- a/backends/table/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/table/table.o - diff --git a/backends/table/table.cc b/backends/table/table.cc index 2bf64e7b1..bbb533965 100644 --- a/backends/table/table.cc +++ b/backends/table/table.cc @@ -77,8 +77,8 @@ struct TableBackend : public Backend { if (wire->port_id == 0) continue; - *f << log_id(module) << "\t"; - *f << log_id(wire) << "\t"; + *f << module->name.unescape() << "\t"; + *f << wire->name.unescape() << "\t"; *f << "-" << "\t"; *f << "-" << "\t"; @@ -97,10 +97,10 @@ struct TableBackend : public Backend { 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"; + *f << module->name.unescape() << "\t"; + *f << cell->name.unescape() << "\t"; + *f << cell->type.unescape() << "\t"; + *f << conn.first.unescape() << "\t"; if (cell->input(conn.first) && cell->output(conn.first)) *f << "inout" << "\t"; diff --git a/backends/verilog/CMakeLists.txt b/backends/verilog/CMakeLists.txt new file mode 100644 index 000000000..6de8dd1f6 --- /dev/null +++ b/backends/verilog/CMakeLists.txt @@ -0,0 +1,8 @@ +yosys_backend(verilog + verilog_backend.cc + verilog_backend.h + REQUIRES + bmuxmap + demuxmap + clean_zerowidth +) diff --git a/backends/verilog/Makefile.inc b/backends/verilog/Makefile.inc deleted file mode 100644 index c2dffef7a..000000000 --- a/backends/verilog/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/verilog/verilog_backend.o - diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 8e05a59a9..0dcf0611e 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -38,7 +38,7 @@ USING_YOSYS_NAMESPACE using namespace VERILOG_BACKEND; -const pool VERILOG_BACKEND::verilog_keywords() { +const pool &VERILOG_BACKEND::verilog_keywords() { static const pool res = { // IEEE 1800-2017 Annex B "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before", @@ -2406,7 +2406,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) log_warning("Module %s contains RTLIL processes with sync rules. Such RTLIL " "processes can't always be mapped directly to Verilog always blocks. " "unintended changes in simulation behavior are possible! Use \"proc\" " - "to convert processes to logic networks and registers.\n", log_id(module)); + "to convert processes to logic networks and registers.\n", module); f << stringf("\n"); for (auto it = module->processes.begin(); it != module->processes.end(); ++it) @@ -2740,7 +2740,7 @@ struct VerilogBackend : public Backend { 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)); + log_cmd_error("Can't handle partially selected module %s!\n", module->name.unescape()); continue; } log("Dumping module `%s'.\n", module->name); diff --git a/backends/verilog/verilog_backend.h b/backends/verilog/verilog_backend.h index 7e550a37c..affad995b 100644 --- a/backends/verilog/verilog_backend.h +++ b/backends/verilog/verilog_backend.h @@ -29,7 +29,7 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_BACKEND { - const pool verilog_keywords(); + const pool &verilog_keywords(); bool char_is_verilog_escaped(char c); bool id_is_verilog_escaped(const std::string &str); diff --git a/cmake/CheckLibcFeatures.cmake b/cmake/CheckLibcFeatures.cmake new file mode 100644 index 000000000..3fc32afe3 --- /dev/null +++ b/cmake/CheckLibcFeatures.cmake @@ -0,0 +1,40 @@ +include(CMakePushCheckState) +include(CheckSourceCompiles) +include(CheckCXXSymbolExists) + +function(check_glob) + check_cxx_symbol_exists(glob "glob.h" HAVE_GLOB) + return (PROPAGATE HAVE_BLOB) +endfunction() + +function(check_pthread_create) + if (Threads_FOUND) + # On WASI, `pthread_create()` is always available, but always fails on triples without threading + # support. Probe for it while requesting the stub implementation to be hidden, otherwise we will + # end up always crashing at runtime on thread creation. + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_DEFINITIONS -D_WASI_STRICT_PTHREAD) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) + check_source_compiles(CXX [[ + #include + int main() { + pthread_create(0, 0, 0, 0); + } + ]] HAVE_PTHREAD_CREATE) + cmake_pop_check_state() + endif() + return (PROPAGATE HAVE_PTHREAD_CREATE) +endfunction() + +function(check_system) + check_cxx_symbol_exists(system "stdlib.h" HAVE_SYSTEM) +endfunction() + +function(check_popen) + check_cxx_symbol_exists(popen "stdio.h" HAVE_POPEN) + if (NOT HAVE_POPEN) + unset(HAVE_POPEN CACHE) + # https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/popen-wpopen + check_cxx_symbol_exists(_popen "stdio.h" HAVE_POPEN) + endif() +endfunction() diff --git a/cmake/Condition.cmake b/cmake/Condition.cmake new file mode 100644 index 000000000..6ef400a32 --- /dev/null +++ b/cmake/Condition.cmake @@ -0,0 +1,35 @@ +# Syntax: +# +# condition( ...) +# +# If `...` is truthful (evaluated as in `if()`) then assigns 1 to ``, else assigns 0. +# The assigned value is `0`/`1` rather than `TRUE`/`FALSE` for ease of use in generator expressions. +# Note that `...` *must* be unquoted. +# +# To understand how a certain outcome is reached, reconfigure the project with `--log-level VERBOSE`. +# +# Believe it or not, CMake doesn't have this built in! +# +macro(condition var) + if (${ARGN}) + set(${var} 1) + else() + set(${var} 0) + endif() + + set(_debug_expr) + foreach (token ${ARGN}) + if (DEFINED ${token}) + if (${${token}}) + list(APPEND _debug_expr "${token}:1") + else() + list(APPEND _debug_expr "${token}:0") + endif() + else() + list(APPEND _debug_expr "${token}") + endif() + endforeach() + string(JOIN " " _debug_expr ${_debug_expr}) + message(VERBOSE " ${var} = ${${var}} (${_debug_expr})") + unset(_debug_expr) +endmacro() diff --git a/cmake/FindDlfcn.cmake b/cmake/FindDlfcn.cmake new file mode 100644 index 000000000..201745a3f --- /dev/null +++ b/cmake/FindDlfcn.cmake @@ -0,0 +1,24 @@ +include(CMakePushCheckState) +include(CheckCXXSymbolExists) +include(FindPackageHandleStandardArgs) + +if (WIN32 OR MSYS) + # Windows; dlopen is available via a polyfill `libs/dlfcn-win32`. + set(Dlfcn_LIBRARIES dlfcn) +else() + # Unix and Wasm; dlopen may or may not be available depending on platform. + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS}) + check_cxx_symbol_exists(dlopen "dlfcn.h" HAVE_DLOPEN) + cmake_pop_check_state() + + if (HAVE_DLOPEN) + add_library(dlfcn INTERFACE) + target_link_libraries(dlfcn INTERFACE ${CMAKE_DL_LIBS}) + set(Dlfcn_LIBRARIES dlfcn) + endif() +endif() + +find_package_handle_standard_args(Dlfcn + REQUIRED_VARS Dlfcn_LIBRARIES +) diff --git a/cmake/FindPyosysEnv.cmake b/cmake/FindPyosysEnv.cmake new file mode 100644 index 000000000..59fd386fc --- /dev/null +++ b/cmake/FindPyosysEnv.cmake @@ -0,0 +1,44 @@ +# We need a *third* `FindPython`-style call in this codebase because the host +# `Python3_EXECUTABLE` may not have pybind11 and cxxheaderparser installed, +# and installing it can be onerous. To work around this problem we try to detect +# whether the host interpreter has the necessary dependencies first, and if it +# does not, fall back to using `uv`. + +foreach (strategy virtualenv host uv fail) + if (strategy STREQUAL "virtualenv") + set(PyosysEnv_PYTHON $ENV{VIRTUAL_ENV}/bin/python) + elseif (strategy STREQUAL "host") + set(PyosysEnv_PYTHON ${Python3_EXECUTABLE}) + elseif (strategy STREQUAL "uv") + set(PyosysEnv_PYTHON uv run --no-project --with pybind11>3,<4 --with cxxheaderparser python) + else() + set(PyosysEnv_PYTHON) + break() + endif() + + execute_process( + COMMAND ${PyosysEnv_PYTHON} -m pybind11 --includes + RESULT_VARIABLE result + OUTPUT_VARIABLE output + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + if (result EQUAL 0) + string(REGEX REPLACE " ?-I" ";" pybind11_INCLUDE_DIR "${output}") + list(FILTER pybind11_INCLUDE_DIR INCLUDE REGEX "/pybind11/") + + execute_process( + COMMAND ${PyosysEnv_PYTHON} ${CMAKE_SOURCE_DIR}/pyosys/generator.py --help + RESULT_VARIABLE result + OUTPUT_QUIET + ERROR_QUIET + ) + if (result EQUAL 0) + break() + endif() + endif() +endforeach() + +find_package_handle_standard_args(PyosysEnv + REQUIRED_VARS PyosysEnv_PYTHON pybind11_INCLUDE_DIR +) diff --git a/cmake/FindPython3Devel.cmake b/cmake/FindPython3Devel.cmake new file mode 100644 index 000000000..b3589a96d --- /dev/null +++ b/cmake/FindPython3Devel.cmake @@ -0,0 +1,28 @@ +# Wrapper to improve behavior of `FindPython3` during cross-compilation. +# Does not entirely fix the problem; CMake 4.0 introduces `Python_ARTIFACTS_PREFIX`, which will. + +# Stash the package found status +get_property(packages_found GLOBAL PROPERTY PACKAGES_FOUND) +get_property(packages_not_found GLOBAL PROPERTY PACKAGES_NOT_FOUND) +get_property(required_version GLOBAL PROPERTY _CMAKE_Python3_REQUIRED_VERSION) + +# A hack to make pyosys buildable in wheel-only environments. +# `Interpreter` is a part of the component set to ensure that a Python implementation without +# an interpreter that's earlier in the search order won't be selected instead of the desired one. +# (This is awful and should be removed once CMake 4.0 is here.) +if (YOSYS_BUILD_PYTHON_ONLY) + set(components Interpreter Development.Module) +else() + set(components Interpreter Development) +endif() + +# The `EXACT` specifier prevents the situation of `FindPython3` discovering a newer libpython-dev +# than the interpreter found in the past, rejecting it because it is too new, and giving up. +find_package(Python3 EXACT ${Python3_VERSION} COMPONENTS ${components}) +if (Python3_Development.Embed_FOUND OR Python3_Development.Module_FOUND) + set(Python3Devel_FOUND YES) +endif() + +set_property(GLOBAL PROPERTY PACKAGES_FOUND "${packages_found}") +set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND "${packages_not_found}") +set_property(GLOBAL PROPERTY _CMAKE_Python3_REQUIRED_VERSION "${required_version}") diff --git a/cmake/GetPyosysVersion.cmake b/cmake/GetPyosysVersion.cmake new file mode 100644 index 000000000..ae5122d23 --- /dev/null +++ b/cmake/GetPyosysVersion.cmake @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.27) +set(CMAKE_MESSAGE_LOG_LEVEL ERROR) +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +include(YosysVersion) + +yosys_extract_version() +if (YOSYS_VERSION_COMMIT EQUAL "0") + set(yosys_version "${YOSYS_VERSION_MAJOR}.${YOSYS_VERSION_MINOR}") +elseif (YOSYS_VERSION_COMMIT STREQUAL "") + set(yosys_version "${YOSYS_VERSION_MAJOR}.${YOSYS_VERSION_MINOR}.post9999") +else() + set(yosys_version "${YOSYS_VERSION_MAJOR}.${YOSYS_VERSION_MINOR}.post${YOSYS_VERSION_COMMIT}") +endif() +execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${yosys_version}") diff --git a/cmake/PkgConfig.cmake b/cmake/PkgConfig.cmake new file mode 100644 index 000000000..b37d74622 --- /dev/null +++ b/cmake/PkgConfig.cmake @@ -0,0 +1,43 @@ +# Syntax: +# +# pkg_config_import() +# +# To use this command, `find_package(PkgConfig)` must be used beforehand, but it does +# not have to succeed. If the `PkgConfig` package is not found, all imports silently fail. +# +# Imports `` as a CMake `IMPORTED` target `PkgConfig::`. +# Updates the global `PACKAGES_FOUND` and `PACKAGES_NOT_FOUND` properties and defines +# the `_FOUND` variable. +# +function(pkg_config_import arg_PREFIX) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "MODULES") + if (NOT arg_MODULES) + set(arg_MODULES ${arg_PREFIX}) + endif() + + if (PkgConfig_FOUND) + # Once CMake 4.1 is available, this call should be replaced with `cmake_pkg_config()`. + pkg_check_modules(${arg_PREFIX} IMPORTED_TARGET ${arg_MODULES}) + if (${arg_PREFIX}_FOUND) + # We found the pkgconfig file, but is it actually a usable package? + # The main cause of failure here would be cross-compiling, which pkg-config does not + # handle very well (especially pre-`cmake_pkg_config()`). + try_compile(is_usable + SOURCE_FROM_CONTENT "main.cc" "int main() {}" + LINK_LIBRARIES PkgConfig::${arg_PREFIX} + LOG_DESCRIPTION "Checking if PkgConfig::${arg_PREFIX} is usable" + ) + if (NOT is_usable) + message(STATUS "Modules '${arg_MODULES}' unusable (bad \$PKG_CONFIG_LIBDIR?)") + set(${arg_PREFIX}_FOUND 0) + endif() + endif() + endif() + + if (${arg_PREFIX}_FOUND) + set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND ${arg_PREFIX}) + else() + set_property(GLOBAL APPEND PROPERTY PACKAGES_NOT_FOUND ${arg_PREFIX}) + endif() + return (PROPAGATE ${arg_PREFIX}_FOUND) +endfunction() diff --git a/cmake/PmgenCommand.cmake b/cmake/PmgenCommand.cmake new file mode 100644 index 000000000..889d7653e --- /dev/null +++ b/cmake/PmgenCommand.cmake @@ -0,0 +1,60 @@ +# Syntax: +# +# pmgen_command( +# [...] +# [PREFIX ] +# [DEBUG] +# ) +# +# Builds `_pm.h` in the current binary directory from pmgen source files ``, which must have +# the `*.pmg` extension. If `...` contains more than one file, `` must be provided. +# +# Defines the following variables: +# - `PMGEN__DEFINED`: Boolean indicating whether this command was successfully invoked. +# - `PMGEN__OUTPUT`: The header file generated by `pmgen`. +# +# Usage example: +# +# pmgen_command(my_dsp +# my_dsp.pmg +# ) +# yosys_pass(my_dsp +# my_dsp.cc +# ${PMGEN_my_dsp_OUTPUT} +# ) +# +# Usage example with multiple files: +# +# pmgen_command(my_dsp +# my_dsp_macc.pmg +# my_dsp_carry.pmg +# PREFIX +# my_dsp +# ) +# +function(pmgen_command arg_NAME) + cmake_parse_arguments(PARSE_ARGV 1 arg "DEBUG" "PREFIX" "") + set(arg_INPUTS ${arg_UNPARSED_ARGUMENTS}) + + set(pmgen_script ${CMAKE_SOURCE_DIR}/passes/pmgen/pmgen.py) + set(pmgen_output ${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}_pm.h) + cmake_path(RELATIVE_PATH pmgen_output BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE pmgen_output_rel) + add_custom_command( + DEPENDS ${pmgen_script} ${arg_INPUTS} + OUTPUT ${pmgen_output} + COMMAND ${Python3_EXECUTABLE} + ${pmgen_script} + "$<$:-g>" + "$<$:-p;${arg_PREFIX}>" + -o ${pmgen_output} + ${arg_INPUTS} + COMMAND_EXPAND_LISTS + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM + COMMENT "Compiling pattern matcher ${pmgen_output_rel}" + ) + + # The usage of this command is somewhat inspired by `flex_target()` and `bison_target()`. + set(PMGEN_${arg_NAME}_DEFINED TRUE) + set(PMGEN_${arg_NAME}_OUTPUT ${pmgen_output} PARENT_SCOPE) +endfunction() diff --git a/cmake/YosysAbc.cmake b/cmake/YosysAbc.cmake new file mode 100644 index 000000000..3b2267504 --- /dev/null +++ b/cmake/YosysAbc.cmake @@ -0,0 +1,96 @@ +include(CheckCompilerFlag) + +define_property(TARGET PROPERTY YOSYS_IS_ABC) + +function(target_safe_compile_options target scope) + foreach (lang C CXX) + foreach (flag ${ARGN}) + check_compiler_flag(${lang} ${flag} HAVE_${lang}_${flag}) + if (HAVE_${lang}_${flag}) + target_compile_options(${target} ${scope} $<$:${flag}>) + endif() + endforeach() + endforeach() +endfunction() + +function(_yosys_abc_extract_makefile result vardecl filename) + # Parse a Makefile fragment and extracts the first matching variable assignment into + # a list of values. + file(READ ${filename} contents) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filename}) + if ("${contents}" MATCHES "${vardecl}(\\\\\n|[ \t])*(([^\\\\\n]|\\\\\n)+)") + string(REGEX REPLACE "(\\\\\n|[ \t])+" ";" ${result} "${CMAKE_MATCH_2}") + endif() + return (PROPAGATE ${result}) +endfunction() + +function(yosys_abc_target arg_LIBNAME arg_EXENAME) + cmake_parse_arguments(PARSE_ARGV 2 arg "" "INSTALL_IF" "") + + # Instead of using either the ABC Make or CMake build system, we parse the source + # of truth: ABC's `module.make` files. This turns out to be quite trivial. + # This way, no assumptions about the environment are made, and Yosys can be compiled + # on Windows without MSYS as a result (while benefitting other platforms as well). + set(all_sources) + _yosys_abc_extract_makefile(module_files "MODULES :=" ${CMAKE_SOURCE_DIR}/abc/Makefile) + _yosys_abc_extract_makefile(module_files_cudd "MODULES \\+=" ${CMAKE_SOURCE_DIR}/abc/Makefile) + list(REMOVE_ITEM module_files "$(wildcard" "src/ext*)") + foreach (module_file ${module_files} ${module_files_cudd}) + _yosys_abc_extract_makefile(module_sources "SRC \\+=" ${CMAKE_SOURCE_DIR}/abc/${module_file}/module.make) + list(APPEND all_sources ${module_sources}) + endforeach() + list(TRANSFORM all_sources PREPEND abc/) + + # Required to get `-DABC_NAMESPACE` below to work consistently. + set_source_files_properties(${all_sources} PROPERTIES LANGUAGE CXX) + + set(main_source abc/src/base/main/main.c) + list(REMOVE_ITEM all_sources ${main_source}) + + find_package(Threads) + yosys_cxx_library(${arg_LIBNAME} STATIC + OUTPUT_NAME ${arg_LIBNAME} + ) + target_sources(${arg_LIBNAME} PRIVATE ${all_sources}) + target_include_directories(${arg_LIBNAME} PRIVATE abc/src) + target_compile_definitions(${arg_LIBNAME} PUBLIC + WIN32_NO_DLL + ABC_NAMESPACE=abc + ABC_USE_STDINT_H=1 + ABC_USE_CUDD=1 + ABC_NO_DYNAMIC_LINKING + $<${YOSYS_ENABLE_THREADS}:ABC_USE_PTHREADS> + $<${YOSYS_ENABLE_READLINE}:ABC_USE_READLINE> + ABC_NO_RLIMIT + ) + target_safe_compile_options(${arg_LIBNAME} PRIVATE + -fpermissive + -fno-exceptions + -Wno-write-strings + -Wno-changes-meaning + -Wno-attributes + -Wno-deprecated-declarations + -Wno-deprecated-comma-subscript + -Wno-format + -Wno-constant-logical-operand + ) + target_link_libraries(${arg_LIBNAME} PUBLIC + $<${YOSYS_ENABLE_THREADS}:Threads::Threads> + $<${YOSYS_ENABLE_READLINE}:PkgConfig::readline> + $<$:-lshlwapi> + ) + set_target_properties(${arg_LIBNAME} PROPERTIES + YOSYS_IS_ABC ON + ) + + yosys_cxx_executable(${arg_EXENAME} + OUTPUT_NAME ${arg_EXENAME} + INSTALL_IF "${arg_INSTALL_IF}" + ) + target_sources(${arg_EXENAME} PRIVATE ${main_source}) + target_include_directories(${arg_EXENAME} PRIVATE abc/src) + target_link_libraries(${arg_EXENAME} PRIVATE ${arg_LIBNAME}) + set_target_properties(${arg_EXENAME} PROPERTIES + YOSYS_IS_ABC ON + ) +endfunction() diff --git a/cmake/YosysAbcSubmodule.cmake b/cmake/YosysAbcSubmodule.cmake new file mode 100644 index 000000000..ee0dcb4c3 --- /dev/null +++ b/cmake/YosysAbcSubmodule.cmake @@ -0,0 +1,64 @@ +# depends on YosysVersion.cmake + +function(yosys_check_abc_submodule) + yosys_call_git(status) + set(yosys_status "tarball") + if (git_result EQUAL 0) + set(yosys_status "git") + endif() + + yosys_call_git(submodule status abc) + set(git_commit) + if (EXISTS "${CMAKE_SOURCE_DIR}/abc/.gitcommit") + file(READ "${CMAKE_SOURCE_DIR}/abc/.gitcommit" git_commit) + string(STRIP "${git_commit}" git_commit) + endif() + set(abc_status "none") + if (git_result EQUAL 0 AND git_output MATCHES "^ ") + set(abc_status "git") + elseif (git_result EQUAL 0 AND git_output MATCHES "^\\+") + set(abc_status "git-changed") + elseif (git_result EQUAL 0 AND git_output MATCHES "^U") + set(abc_status "git-conflict") + elseif (git_commit MATCHES "^[0-9a-fA-F]+$") + set(abc_status "tarball") + elseif (git_commit MATCHES "\\$Format:%[hH]\\$") + set(abc_status "unknown") + endif() + + if (abc_status STREQUAL "git" OR abc_status STREQUAL "tarball") + # Normal submodule or a tarball. + elseif (abc_status STREQUAL "git-changed") + message(FATAL_ERROR + "'abc' submodule does not match expected commit.\n" + "Run 'git submodule update' to check out the correct version.\n" + "Note: If testing a different version of ABC, call 'git commit abc' " + "in the Yosys source directory to update the expected commit.\n" + ) + elseif (abc_status STREQUAL "git-conflict") + message(FATAL_ERROR + "'abc' submodule has merge conflicts.\n" + "Please resolve merge conflicts before continuing.\n" + ) + elseif (abc_status STREQUAL "unknown") # OK + message(FATAL_ERROR + "Error: 'abc' is not configured as a git submodule.\n" + "To resolve this:\n" + "1. Back up your changes: Save any modifications from the 'abc' directory to another location.\n" + "2. Remove the existing 'abc' directory: Delete the 'abc' directory and all its contents.\n" + "3. Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule.\n" + "4. Reapply your changes: Move your saved changes back to the 'abc' directory, if necessary.\n" + ) + elseif (yosys_status STREQUAL "git") # OK + message(FATAL_ERROR + "Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule.\n" + ) + else() # + message(FATAL_ERROR + "${CMAKE_SOURCE_DIR} is not configured as a git repository, and 'abc' folder is missing.\n" + "If you already have ABC, set 'YOSYS_ABC_EXECUTABLE' CMake variable to point to ABC executable.\n" + "Otherwise, download release archive 'yosys.tar.gz' from https://github.com/YosysHQ/yosys/releases.\n" + " ('Source code' archive does not contain submodules.)\n" + ) + endif() +endfunction() diff --git a/cmake/YosysComponent.cmake b/cmake/YosysComponent.cmake new file mode 100644 index 000000000..9786ba156 --- /dev/null +++ b/cmake/YosysComponent.cmake @@ -0,0 +1,321 @@ +set(namespace "yosys") + +# Properties internal to the component system. +define_property(TARGET PROPERTY YOSYS_COMPONENT) +define_property(TARGET PROPERTY YOSYS_PROVIDES) +define_property(TARGET PROPERTY YOSYS_REQUIRES) +define_property(TARGET PROPERTY YOSYS_DATA_FILES) +define_property(TARGET PROPERTY YOSYS_ENABLE_IF) + +# Syntax: +# +# yosys_component( [INTERFACE] +# [...] +# [DEFINITIONS ...] +# [INCLUDE_DIRS ...] +# [LIBRARIES ...] +# [PROVIDES ...] +# [REQUIRES ...] +# [DATA_DIR ] +# [DATA_FILES ...] +# [DATA_EXPLICIT [ ]...] +# [ESSENTIAL] +# [ENABLE_IF ""] +# ) +# +# Creates a target `yosys_` (if `` is empty) or `yosys__` (if `` is not empty). +# This target is an library target with some Yosys-specific behavior that simplifies partitioning the compiler +# into small pieces with explicitly defined compile-time and run-time dependency metadata. Circular dependencies +# between compilation units in different components are allowed. +# +# Parameter description: +# - `INTERFACE` should be specified for header-only libraries. +# - `...` is a shortcut for `target_sources(PRIVATE)`. +# - `DEFINITIONS ...` is a shortcut for `target_compile_definitions(PRIVATE)`. +# - `INCLUDE_DIRS ...` is a shortcut for `target_include_directories(PRIVATE)`. +# - `LIBRARIES ...` is a shortcut for `target_link_libraries(PRIVATE)`. +# - `PROVIDES ...` creates aliases to each `` component name. +# - `REQUIRES ...` ensures that if this target is linked into the Yosys binary, then every +# `` component is also linked in. +# - `DATA_DIR ` configures a base directory for installing data files; this directory +# is (relative to the root build directory or the installation prefix) `share/` if +# `DATA_DIR` is provided, and `share` if not. +# - `DATA_FILES ...` installs each of `` as `share///`, +# where `` is the directory name of `` and `` is the filename of ``. +# - `DATA_EXPLICIT [ ]...` installs each `` as `share//`. +# Where possible, `DATA_FILES` should be used instead. +# - `ESSENTIAL` ensures that this target is always linked into the Yosys binary. +# - `ENABLE_IF ""` marks the component as available only when `if()` would run. +# +# Avoid using this function directly. Instead, use one of the wrappers below as follows: +# - to define a normal pass, use `yosys_pass()` to add a component called ``. +# - to define a test pass, use `yosys_test_pass()` to add a component called `test_`. +# - to define a frontend, use `yosys_frontend()` to add a component called `read_`. +# - to define a backend, use `yosys_backend()` to add a component called `write_`. +# - if the component sources define more than one pass, use `PROVIDES` with names of the other passes. +# - if the component uses `Pass::call()`, `Frontend::frontend_call()`, `Backend::backend_call()`, or other +# similar functions, use `REQUIRES` with names of all possibly needed passes. +# - if the component needs an essential pass, add the latter to `REQUIRES` anyway for completeness. +# - if the component subclasses a `ScriptPass`, build Yosys, then run `misc/script_pass_depends.py ` +# to extract the names of all referenced passes. +# - in general, component names should be the same as corresponding pass names (as used in the REPL), +# but this is not a hard requirement and any suitable name can be used if desired. +# +function(yosys_component arg_PREFIX arg_NAME) + cmake_parse_arguments(PARSE_ARGV 2 arg + "INTERFACE;ESSENTIAL;BOOTSTRAP" + "DATA_DIR;ENABLE_IF" + "DEFINITIONS;INCLUDE_DIRS;LIBRARIES;DATA_FILES;DATA_EXPLICIT;PROVIDES;REQUIRES" + ) + set(arg_SOURCES ${arg_UNPARSED_ARGUMENTS}) + if ("${arg_ENABLE_IF}" STREQUAL "") + set(arg_ENABLE_IF TRUE) + endif() + + if (arg_PREFIX STREQUAL "") + set(component "${arg_NAME}") + else() + set(component "${arg_PREFIX}_${arg_NAME}") + endif() + set(target "${namespace}_${component}") + list(TRANSFORM arg_PROVIDES PREPEND ${namespace}_ OUTPUT_VARIABLE provides_targets) + + # An OBJECT library is used to allow for circular symbol dependencies between any source files. + # Unfortunately, public dependencies between OBJECT libraries aren't handled correctly, so we have + # to do it ourselves. + if (arg_SOURCES AND NOT arg_INTERFACE) + add_library(${target} EXCLUDE_FROM_ALL OBJECT) + target_sources(${target} PRIVATE ${arg_SOURCES}) + target_include_directories(${target} PRIVATE ${arg_INCLUDE_DIRS}) + target_compile_definitions(${target} PRIVATE ${arg_DEFINITIONS}) + target_link_libraries(${target} PUBLIC yosys_common ${arg_LIBRARIES}) + foreach (alias ${provides_targets}) + add_library(${alias} ALIAS ${target}) + endforeach() + else() + add_library(${target} EXCLUDE_FROM_ALL INTERFACE) + endif() + set_target_properties(${target} PROPERTIES + YOSYS_COMPONENT YES + YOSYS_PROVIDES "${arg_PROVIDES}" + YOSYS_REQUIRES "${arg_REQUIRES}" + YOSYS_DATA_FILES "" + YOSYS_ENABLE_IF "${arg_ENABLE_IF}" + ) + + set(share_file_pairs) + foreach (share_file ${arg_DATA_FILES}) + list(APPEND share_file_pairs ${share_file} ${share_file}) + endforeach() + list(APPEND share_file_pairs ${arg_DATA_EXPLICIT}) + if (share_file_pairs) + set(data_depends) + set(share_root ${CMAKE_BINARY_DIR}/share) + while (share_file_pairs) + list(LENGTH share_file_pairs share_file_unpaired) + if (share_file_unpaired EQUAL 1) + message(FATAL_ERROR "Unpaired DATA_EXPLICIT argument: ${share_file_pairs}") + endif() + list(POP_FRONT share_file_pairs dst_file src_file) + cmake_path(ABSOLUTE_PATH src_file BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + set(out_dir ${arg_DATA_DIR}) + cmake_path(GET dst_file PARENT_PATH dst_parent) + cmake_path(APPEND out_dir ${dst_parent}) + cmake_path(GET dst_file FILENAME dst_filename) + cmake_path(APPEND out_dir ${dst_filename} OUTPUT_VARIABLE out_file) + file(MAKE_DIRECTORY ${share_root}/${out_dir}) + add_custom_command( + DEPENDS ${src_file} + OUTPUT ${share_root}/${out_file} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${share_root}/${out_file} + VERBATIM + COMMENT "Copying share/${out_file}" + ) + set_property(TARGET ${target} APPEND PROPERTY YOSYS_DATA_FILES ${out_file}) + list(APPEND data_depends ${share_root}/${out_file}) + endwhile() + add_custom_target(${target}-data DEPENDS ${data_depends}) + add_dependencies(${target} ${target}-data) + endif() + + if (NOT arg_BOOTSTRAP) + set_property(TARGET yosys_everything APPEND PROPERTY YOSYS_REQUIRES ${component}) + if (arg_ESSENTIAL) + set_property(TARGET yosys_essentials APPEND PROPERTY YOSYS_REQUIRES ${component}) + endif() + endif() +endfunction() + +# Syntax: +# +# yosys_core( [