3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-12-12 14:46:23 +00:00

Merge remote-tracking branch 'origin/main' into gussmith23-rosette-backend-updates

This commit is contained in:
Gus Smith 2025-11-29 14:20:36 -08:00
commit 6fe35fa46c
694 changed files with 33466 additions and 17901 deletions

View file

@ -11,6 +11,10 @@ indent_style = space
indent_size = 2 indent_size = 2
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.rst]
indent_style = space
indent_size = 3
[*.yml] [*.yml]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

View file

@ -6,15 +6,14 @@ body:
attributes: attributes:
value: > value: >
If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area If you have a general question, please ask it on the [Discourse forum](https://yosyshq.discourse.group/).
or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA).
If you have a feature request, please fill out the appropriate issue form, this form is for bugs and/or regressions. If you have a feature request, please fill out the appropriate issue form, this form is for bugs and/or regressions.
Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need
commercial support for Yosys. commercial support or work done for Yosys.
- type: input - type: input
id: yosys_version id: yosys_version

View file

@ -1,11 +1,8 @@
contact_links: contact_links:
- name: Discussions - name: Discourse
url: https://github.com/YosysHQ/yosys/discussions url: https://yosyshq.discourse.group
about: "Have a question? Ask it on our discussions page!" about: "Have a question? Ask it on our Discourse group!"
- name: Community Slack
url: https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA
about: "Yosys Community Slack"
- name: IRC Channel - name: IRC Channel
url: https://web.libera.chat/#yosys url: https://web.libera.chat/#yosys
about: "#yosys on irc.libera.chat" about: "#yosys on irc.libera.chat"

View file

@ -6,8 +6,7 @@ body:
attributes: attributes:
value: > value: >
If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area If you have a general question, please ask it on the [Discourse forum](https://yosyshq.discourse.group/).
or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA).
If you have found a bug in Yosys, or in building the documentation, If you have found a bug in Yosys, or in building the documentation,

View file

@ -1,18 +1,17 @@
name: Feature Request name: Feature Request
description: "Submit a feature request for Yosys" description: "Submit a feature request for Yosys"
labels: ["feature-request"] labels: ["feature-request"]
body: body:
- type: markdown - type: markdown
attributes: attributes:
value: > value: >
If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area If you have a general question, please ask it on the [Discourse forum](https://yosyshq.discourse.group/).
or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA).
If you have a bug report, please fill out the appropriate issue form, this form is for feature requests. If you have a bug report, please fill out the appropriate issue form, this form is for feature requests.
Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need
commercial support or work done for Yosys. commercial support or work done for Yosys.

View file

@ -1,5 +1,9 @@
_If your work is part of a larger effort, please discuss your general plans on [Discourse](https://yosyshq.discourse.group/) first to align your vision with maintainers._
_What are the reasons/motivation for this change?_ _What are the reasons/motivation for this change?_
_Explain how this is achieved._ _Explain how this is achieved._
_If applicable, please suggest to reviewers how they can test the change._ _Make sure your change comes with tests. If not possible, share how a reviewer might evaluate it._
_These template prompts can be deleted when you're done responding to them._

View file

@ -1,21 +1,71 @@
name: Build environment setup name: Build environment setup
description: Configure build env for Yosys builds description: Configure build env for Yosys builds
inputs:
runs-on:
required: true
type: string
get-build-deps:
description: 'Install Yosys build dependencies'
default: false
required: false
type: boolean
get-docs-deps:
description: 'Install Yosys docs dependencies'
default: false
required: false
type: boolean
get-test-deps:
description: 'Install Yosys test dependencies'
default: false
required: false
type: boolean
get-iverilog:
description: 'Install iverilog'
default: false
required: false
type: boolean
runs: runs:
using: composite using: composite
steps: steps:
- name: Install Linux Dependencies # if updating common/build/docs dependencies, make sure to update README.md
# and docs/source/getting_started/installation.rst to match.
- name: Linux common dependencies
if: runner.os == 'Linux' if: runner.os == 'Linux'
shell: bash uses: awalsh128/cache-apt-pkgs-action@v1.6.0
run: | with:
sudo apt-get update packages: gawk git make python3
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev version: ${{ inputs.runs-on }}-commonys
- name: Linux build dependencies
if: runner.os == 'Linux' && inputs.get-build-deps == 'true'
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: bison clang flex libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev
version: ${{ inputs.runs-on }}-buildys
- name: Linux docs dependencies
if: runner.os == 'Linux' && inputs.get-docs-deps == 'true'
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: graphviz xdot
version: ${{ inputs.runs-on }}-docsys
# if updating test dependencies, make sure to update
# docs/source/yosys_internals/extending_yosys/test_suites.rst to match.
- name: Linux test dependencies
if: runner.os == 'Linux' && inputs.get-test-deps == 'true'
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: libgtest-dev
version: ${{ inputs.runs-on }}-testys
- name: Install macOS Dependencies - name: Install macOS Dependencies
if: runner.os == 'macOS' if: runner.os == 'macOS'
shell: bash shell: bash
run: | run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew update brew bundle
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf llvm lld || true
- name: Linux runtime environment - name: Linux runtime environment
if: runner.os == 'Linux' if: runner.os == 'Linux'
@ -29,7 +79,13 @@ runs:
shell: bash shell: bash
run: | run: |
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH
echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH
echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH
echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV
- name: Setup iverilog
if: inputs.get-iverilog == 'true'
uses: ./.github/actions/setup-iverilog
with:
runs-on: ${{ inputs.runs-on }}

View file

@ -0,0 +1,70 @@
name: iverilog setup
description: Cached build and install of iverilog
inputs:
runs-on:
required: true
type: string
runs:
using: composite
steps:
- name: iverilog Linux deps
if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'Linux'
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: autoconf gperf make gcc g++ bison flex libbz2-dev
version: ${{ inputs.runs-on }}-iverilog
- name: iverilog macOS deps
if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS'
shell: bash
run: |
brew install autoconf
- name: Get iverilog
id: get-iverilog
shell: bash
run: |
git clone https://github.com/steveicarus/iverilog.git
cd iverilog
echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
- name: Get vcd2fst
shell: bash
run: |
git clone https://github.com/mmicko/libwave.git
mkdir -p ${{ github.workspace }}/.local/
cd libwave
cmake . -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.local
make -j$procs
make install
- uses: actions/cache/restore@v4
id: restore-iverilog
with:
path: .local/
key: ${{ inputs.runs-on }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }}
- name: Build iverilog
if: steps.restore-iverilog.outputs.cache-hit != 'true'
shell: bash
run: |
mkdir -p ${{ github.workspace }}/.local/
cd iverilog
autoconf
CC=gcc CXX=g++ ./configure --prefix=${{ github.workspace }}/.local
make -j$procs
make install
- name: Check iverilog
shell: bash
run: |
iverilog -V
- uses: actions/cache/save@v4
id: save-iverilog
if: steps.restore-iverilog.outputs.cache-hit != 'true'
with:
path: .local/
key: ${{ steps.restore-iverilog.outputs.cache-primary-key }}

View file

@ -10,15 +10,18 @@ jobs:
name: Analyze name: Analyze
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install deps
run: sudo apt-get install bison flex libreadline-dev tcl-dev libffi-dev
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: true submodules: true
persist-credentials: false persist-credentials: false
- name: Setup environment
uses: ./.github/actions/setup-build-env
with:
runs-on: ubuntu-latest
get-build-deps: true
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v3
with: with:

View file

@ -1,6 +1,14 @@
name: Test extra build flows name: Test extra build flows
on: [push, pull_request] on:
# always test main
push:
branches:
- main
# test PRs
pull_request:
# allow triggering tests, ignores skip check
workflow_dispatch:
jobs: jobs:
pre_job: pre_job:
@ -11,11 +19,11 @@ jobs:
- id: skip_check - id: skip_check
uses: fkirc/skip-duplicate-actions@v5 uses: fkirc/skip-duplicate-actions@v5
with: with:
# don't run on documentation changes
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
# cancel previous builds if a new commit is pushed # cancel previous builds if a new commit is pushed
cancel_others: 'true' # but never cancel main
# only run on push *or* pull_request, not both cancel_others: ${{ github.ref != 'refs/heads/main' }}
concurrent_skipping: 'same_content_newer'
vs-prep: vs-prep:
name: Prepare Visual Studio build name: Prepare Visual Studio build
@ -27,19 +35,20 @@ jobs:
with: with:
submodules: true submodules: true
persist-credentials: false persist-credentials: false
- run: sudo apt-get install libfl-dev
- name: Build - name: Build
run: make vcxsrc YOSYS_VER=latest run: make vcxsrc YOSYS_VER=latest
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: vcxsrc name: vcxsrc
path: yosys-win32-vcxsrc-latest.zip path: yosys-win32-vcxsrc-latest.zip
vs-build: vs-build:
name: Visual Studio build name: Visual Studio build
runs-on: windows-2019 runs-on: windows-latest
needs: [vs-prep, pre_job] needs: [vs-prep, pre_job]
if: needs.pre_job.outputs.should_skip != 'true' if: needs.pre_job.outputs.should_skip != 'true'
steps: steps:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
name: vcxsrc name: vcxsrc
@ -50,7 +59,7 @@ jobs:
uses: microsoft/setup-msbuild@v2 uses: microsoft/setup-msbuild@v2
- name: MSBuild - name: MSBuild
working-directory: yosys-win32-vcxsrc-latest working-directory: yosys-win32-vcxsrc-latest
run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.17763.0 run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.26100.0
wasi-build: wasi-build:
name: WASI build name: WASI build
@ -64,13 +73,24 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Build - name: Build
run: | run: |
WASI_SDK=wasi-sdk-19.0 WASI_SDK=wasi-sdk-27.0-x86_64-linux
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-27/wasi-sdk-27.0-x86_64-linux.tar.gz
if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi
FLEX_VER=2.6.4
FLEX=flex-${FLEX_VER}
FLEX_URL=https://github.com/westes/flex/releases/download/v${FLEX_VER}/${FLEX}.tar.gz
if ! [ -d ${FLEX} ]; then curl -L ${FLEX_URL} | tar xzf -; fi
mkdir -p flex-build
(cd flex-build &&
../${FLEX}/configure --prefix=$(pwd)/../flex-prefix &&
make &&
make install)
mkdir -p build mkdir -p build
cat > build/Makefile.conf <<END cat > build/Makefile.conf <<END
export PATH := $(pwd)/${WASI_SDK}/bin:${PATH} export PATH := $(pwd)/${WASI_SDK}/bin:$(pwd)/flex-prefix/bin:${PATH}
WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot
CONFIG := wasi CONFIG := wasi
@ -80,6 +100,8 @@ jobs:
ENABLE_READLINE := 0 ENABLE_READLINE := 0
ENABLE_PLUGINS := 0 ENABLE_PLUGINS := 0
ENABLE_ZLIB := 0 ENABLE_ZLIB := 0
CXXFLAGS += -I$(pwd)/flex-prefix/include
END END
make -C build -f ../Makefile CXX=clang -j$(nproc) make -C build -f ../Makefile CXX=clang -j$(nproc)
@ -98,7 +120,7 @@ jobs:
with: with:
submodules: true submodules: true
persist-credentials: false persist-credentials: false
- uses: cachix/install-nix-action@v26 - uses: cachix/install-nix-action@v31
with: with:
install_url: https://releases.nixos.org/nix/nix-2.18.1/install install_url: https://releases.nixos.org/nix/nix-2.30.0/install
- run: nix build .?submodules=1 -L - run: nix build .?submodules=1 -L

View file

@ -26,7 +26,7 @@ jobs:
# docs builds are needed for anything on main, any tagged versions, and any tag # docs builds are needed for anything on main, any tagged versions, and any tag
# or branch starting with docs-preview # or branch starting with docs-preview
needs: check_docs_rebuild needs: check_docs_rebuild
if: ${{ needs.check_docs_rebuild.outputs.should_skip != 'true' }} if: ${{ needs.check_docs_rebuild.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }}
runs-on: [self-hosted, linux, x64, fast] runs-on: [self-hosted, linux, x64, fast]
steps: steps:
- name: Checkout Yosys - name: Checkout Yosys
@ -47,7 +47,8 @@ jobs:
echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf
echo "ENABLE_CCACHE := 1" >> Makefile.conf echo "ENABLE_CCACHE := 1" >> Makefile.conf
make -j$procs ENABLE_LTO=1 echo "ENABLE_HELP_SOURCE := 1" >> Makefile.conf
make -j$procs
- name: Prepare docs - name: Prepare docs
shell: bash shell: bash
@ -59,7 +60,6 @@ jobs:
with: with:
name: cmd-ref-${{ github.sha }} name: cmd-ref-${{ github.sha }}
path: | path: |
docs/source/cmd
docs/source/generated docs/source/generated
docs/source/_images docs/source/_images
docs/source/code_examples docs/source/code_examples

View file

@ -1,6 +1,14 @@
name: Build and run tests name: Build and run tests
on: [push, pull_request] on:
# always test main
push:
branches:
- main
# test PRs
pull_request:
# allow triggering tests, ignores skip check
workflow_dispatch:
jobs: jobs:
pre_job: pre_job:
@ -11,11 +19,12 @@ jobs:
- id: skip_check - id: skip_check
uses: fkirc/skip-duplicate-actions@v5 uses: fkirc/skip-duplicate-actions@v5
with: with:
# don't run on documentation changes
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
# cancel previous builds if a new commit is pushed # cancel previous builds if a new commit is pushed
cancel_others: 'true' # but never cancel main
# only run on push *or* pull_request, not both cancel_others: ${{ github.ref != 'refs/heads/main' }}
concurrent_skipping: 'same_content_newer'
pre_docs_job: pre_docs_job:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
@ -24,15 +33,16 @@ jobs:
- id: skip_check - id: skip_check
uses: fkirc/skip-duplicate-actions@v5 uses: fkirc/skip-duplicate-actions@v5
with: with:
# don't run on readme changes
paths_ignore: '["**/README.md"]' paths_ignore: '["**/README.md"]'
# cancel previous builds if a new commit is pushed # cancel previous builds if a new commit is pushed
cancel_others: 'true' # but never cancel main
# only run on push *or* pull_request, not both cancel_others: ${{ github.ref != 'refs/heads/main' }}
concurrent_skipping: 'same_content_newer'
build-yosys: build-yosys:
name: Reusable build name: Reusable build
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
# pre_job is a subset of pre_docs_job, so we can always build for pre_docs_job
needs: pre_docs_job needs: pre_docs_job
if: needs.pre_docs_job.outputs.should_skip != 'true' if: needs.pre_docs_job.outputs.should_skip != 'true'
env: env:
@ -50,6 +60,9 @@ jobs:
- name: Setup environment - name: Setup environment
uses: ./.github/actions/setup-build-env uses: ./.github/actions/setup-build-env
with:
runs-on: ${{ matrix.os }}
get-build-deps: true
- name: Build - name: Build
shell: bash shell: bash
@ -57,8 +70,7 @@ jobs:
mkdir build mkdir build
cd build cd build
make -f ../Makefile config-$CC make -f ../Makefile config-$CC
echo 'SANITIZER = undefined' >> Makefile.conf make -f ../Makefile -j$procs
make -f ../Makefile -j$procs ENABLE_LTO=1
- name: Log yosys-config output - name: Log yosys-config output
run: | run: |
@ -84,7 +96,6 @@ jobs:
if: needs.pre_job.outputs.should_skip != 'true' if: needs.pre_job.outputs.should_skip != 'true'
env: env:
CC: clang CC: clang
UBSAN_OPTIONS: halt_on_error=1
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
@ -97,41 +108,10 @@ jobs:
- name: Setup environment - name: Setup environment
uses: ./.github/actions/setup-build-env uses: ./.github/actions/setup-build-env
- name: Get iverilog
shell: bash
run: |
git clone https://github.com/steveicarus/iverilog.git
cd iverilog
echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV
- name: Get vcd2fst
shell: bash
run: |
git clone https://github.com/mmicko/libwave.git
mkdir -p ${{ github.workspace }}/.local/
cd libwave
cmake . -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.local
make -j$procs
make install
- name: Cache iverilog
id: cache-iverilog
uses: actions/cache@v4
with: with:
path: .local/ runs-on: ${{ matrix.os }}
key: ${{ matrix.os }}-${IVERILOG_GIT} get-test-deps: true
get-iverilog: true
- name: Build iverilog
if: steps.cache-iverilog.outputs.cache-hit != 'true'
shell: bash
run: |
mkdir -p ${{ github.workspace }}/.local/
cd iverilog
autoconf
CC=gcc CXX=g++ ./configure --prefix=${{ github.workspace }}/.local
make -j$procs
make install
- name: Download build artifact - name: Download build artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -158,6 +138,45 @@ jobs:
run: | run: |
find tests/**/*.err -print -exec cat {} \; find tests/**/*.err -print -exec cat {} \;
test-cells:
name: Run test_cell
runs-on: ${{ matrix.os }}
needs: [build-yosys, pre_job]
if: needs.pre_job.outputs.should_skip != 'true'
env:
CC: clang
strategy:
matrix:
os: [ubuntu-latest]
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup environment
uses: ./.github/actions/setup-build-env
with:
runs-on: ${{ matrix.os }}
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: build-${{ matrix.os }}
- name: Uncompress build
shell: bash
run:
tar -xvf build.tar
- name: test_cell
shell: bash
run: |
./yosys -p 'test_cell -n 20 -s 1 all'
./yosys -p 'test_cell -n 20 -s 1 -nosat -aigmap $pow $pmux'
./yosys -p 'test_cell -n 20 -s 1 -nosat -aigmap $eqx $nex $bweqx'
./yosys -p 'test_cell -n 20 -s 1 -aigmap $buf'
test-docs: test-docs:
name: Run docs tests name: Run docs tests
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@ -177,6 +196,10 @@ jobs:
- name: Setup environment - name: Setup environment
uses: ./.github/actions/setup-build-env uses: ./.github/actions/setup-build-env
with:
runs-on: ${{ matrix.os }}
get-build-deps: true
get-docs-deps: true
- name: Download build artifact - name: Download build artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -201,7 +224,7 @@ jobs:
name: Try build docs name: Try build docs
runs-on: [self-hosted, linux, x64, fast] runs-on: [self-hosted, linux, x64, fast]
needs: [pre_docs_job] needs: [pre_docs_job]
if: needs.pre_docs_job.outputs.should_skip != 'true' if: ${{ needs.pre_docs_job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }}
strategy: strategy:
matrix: matrix:
docs-target: [html, latexpdf] docs-target: [html, latexpdf]
@ -221,6 +244,7 @@ jobs:
run: | run: |
make config-clang make config-clang
echo "ENABLE_CCACHE := 1" >> Makefile.conf echo "ENABLE_CCACHE := 1" >> Makefile.conf
echo "ENABLE_HELP_SOURCE := 1" >> Makefile.conf
make -j$procs make -j$procs
- name: Install doc prereqs - name: Install doc prereqs

View file

@ -1,6 +1,14 @@
name: Compiler testing name: Compiler testing
on: [push, pull_request] on:
# always test main
push:
branches:
- main
# test PRs
pull_request:
# allow triggering tests, ignores skip check
workflow_dispatch:
jobs: jobs:
pre_job: pre_job:
@ -11,11 +19,11 @@ jobs:
- id: skip_check - id: skip_check
uses: fkirc/skip-duplicate-actions@v5 uses: fkirc/skip-duplicate-actions@v5
with: with:
# don't run on documentation changes
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
# cancel previous builds if a new commit is pushed # cancel previous builds if a new commit is pushed
cancel_others: 'true' # but never cancel main
# only run on push *or* pull_request, not both cancel_others: ${{ github.ref != 'refs/heads/main' }}
concurrent_skipping: 'same_content_newer'
test-compile: test-compile:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@ -34,11 +42,14 @@ jobs:
- 'gcc-10' - 'gcc-10'
# newest, make sure to update maximum standard step to match # newest, make sure to update maximum standard step to match
- 'clang-19' - 'clang-19'
- 'gcc-13' - 'gcc-14'
include: include:
# macOS # macOS x86
- os: macos-13 - os: macos-15-intel
compiler: 'clang' compiler: 'clang-19'
# macOS arm
- os: macos-latest
compiler: 'clang-19'
fail-fast: false fail-fast: false
steps: steps:
- name: Checkout Yosys - name: Checkout Yosys
@ -49,6 +60,9 @@ jobs:
- name: Setup environment - name: Setup environment
uses: ./.github/actions/setup-build-env uses: ./.github/actions/setup-build-env
with:
runs-on: ${{ matrix.os }}
get-build-deps: true
- name: Setup Cpp - name: Setup Cpp
uses: aminya/setup-cpp@v1 uses: aminya/setup-cpp@v1
@ -70,7 +84,7 @@ jobs:
# maximum standard, only on newest compilers # maximum standard, only on newest compilers
- name: Build C++20 - name: Build C++20
if: ${{ matrix.compiler == 'clang-19' || matrix.compiler == 'gcc-13' }} if: ${{ matrix.compiler == 'clang-19' || matrix.compiler == 'gcc-14' }}
shell: bash shell: bash
run: | run: |
make config-$CC_SHORT make config-$CC_SHORT

78
.github/workflows/test-sanitizers.yml vendored Normal file
View file

@ -0,0 +1,78 @@
name: Check clang sanitizers
on:
# always test main
push:
branches:
- main
# ignore PRs due to time needed
# allow triggering tests, ignores skip check
workflow_dispatch:
jobs:
pre_job:
runs-on: ubuntu-latest
outputs:
should_skip: ${{ steps.skip_check.outputs.should_skip }}
steps:
- id: skip_check
uses: fkirc/skip-duplicate-actions@v5
with:
# don't run on documentation changes
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
run_san:
name: Build and run tests
runs-on: ${{ matrix.os }}
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
env:
CC: clang
ASAN_OPTIONS: halt_on_error=1
UBSAN_OPTIONS: halt_on_error=1
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
sanitizer: ['undefined,address']
fail-fast: false
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
submodules: true
persist-credentials: false
- name: Setup environment
uses: ./.github/actions/setup-build-env
with:
runs-on: ${{ matrix.os }}
get-build-deps: true
get-test-deps: true
get-iverilog: true
- name: Build
shell: bash
run: |
make config-$CC
echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf
make -j$procs
- name: Log yosys-config output
run: |
./yosys-config || true
- name: Run tests
shell: bash
run: |
make -j$procs test TARGETS= EXTRA_TARGETS=
- name: Report errors
if: ${{ failure() }}
shell: bash
run: |
find tests/**/*.err -print -exec cat {} \;
- name: Run unit tests
shell: bash
run: |
make -j$procs unit-test ENABLE_LIBYOSYS=1

View file

@ -1,6 +1,14 @@
name: Build and run tests with Verific (Linux) name: Build and run tests with Verific (Linux)
on: [push, pull_request] on:
# always test main
push:
branches:
- main
# test PRs
pull_request:
# allow triggering tests, ignores skip check
workflow_dispatch:
jobs: jobs:
pre-job: pre-job:
@ -11,15 +19,15 @@ jobs:
- id: skip_check - id: skip_check
uses: fkirc/skip-duplicate-actions@v5 uses: fkirc/skip-duplicate-actions@v5
with: with:
# don't run on documentation changes
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
# cancel previous builds if a new commit is pushed # cancel previous builds if a new commit is pushed
cancel_others: 'true' # but never cancel main
# only run on push *or* pull_request, not both cancel_others: ${{ github.ref != 'refs/heads/main' }}
concurrent_skipping: 'same_content_newer'
test-verific: test-verific:
needs: pre-job needs: pre-job
if: needs.pre-job.outputs.should_skip != 'true' if: ${{ needs.pre-job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }}
runs-on: [self-hosted, linux, x64, fast] runs-on: [self-hosted, linux, x64, fast]
steps: steps:
- name: Checkout Yosys - name: Checkout Yosys
@ -70,3 +78,47 @@ jobs:
if: ${{ github.ref == 'refs/heads/main' }} if: ${{ github.ref == 'refs/heads/main' }}
run: | run: |
make -C sby run_ci make -C sby run_ci
- name: Run unit tests
shell: bash
run: |
make -j$procs unit-test ENABLE_LTO=1 ENABLE_LIBYOSYS=1
test-pyosys:
needs: pre-job
if: ${{ needs.pre-job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }}
runs-on: [self-hosted, linux, x64, fast]
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
persist-credentials: false
submodules: true
- name: Install UV
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Runtime environment
run: |
echo "procs=$(nproc)" >> $GITHUB_ENV
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
- 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
- name: Install pyosys
run: |
make install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX=
- name: Run pyosys tests
run: |
export PYTHONPATH=${GITHUB_WORKSPACE}/.local/usr/lib/python3/site-packages:$PYTHONPATH
python3 tests/pyosys/run_tests.py

View file

@ -6,6 +6,7 @@ on:
jobs: jobs:
lockfile: lockfile:
if: github.repository == 'YosysHQ/Yosys'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository

View file

@ -7,6 +7,7 @@ on:
jobs: jobs:
bump-version: bump-version:
if: github.repository == 'YosysHQ/Yosys'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
@ -18,11 +19,8 @@ jobs:
- name: Take last commit - name: Take last commit
id: log id: log
run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT
- name: Take repository
id: repo
run: echo "message=$GITHUB_REPOSITORY" >> $GITHUB_OUTPUT
- name: Bump version - name: Bump version
if: "!contains(steps.log.outputs.message, 'Bump version') && contains(steps.repo.outputs.message, 'YosysHQ/yosys')" if: ${{ !contains(steps.log.outputs.message, 'Bump version') }}
run: | run: |
make bumpversion make bumpversion
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
@ -30,7 +28,7 @@ jobs:
git add Makefile git add Makefile
git commit -m "Bump version" git commit -m "Bump version"
- name: Push changes # push the output folder to your repo - name: Push changes # push the output folder to your repo
if: "!contains(steps.log.outputs.message, 'Bump version') && contains(steps.repo.outputs.message, 'YosysHQ/yosys')" if: ${{ !contains(steps.log.outputs.message, 'Bump version') }}
uses: ad-m/github-push-action@master uses: ad-m/github-push-action@master
with: with:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}

View file

@ -4,7 +4,7 @@ name: Build Wheels for PyPI
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: '0 10 * * 0' - cron: "0 10 * * 0"
jobs: jobs:
build_wheels: build_wheels:
@ -25,15 +25,15 @@ jobs:
archs: "aarch64", archs: "aarch64",
}, },
{ {
name: "macOS 13", name: "macOS 15 x64",
family: "macos", family: "macos",
runner: "macos-13", runner: "macos-15-intel",
archs: "x86_64", archs: "x86_64",
}, },
{ {
name: "macOS 14", name: "macOS 15 arm64",
family: "macos", family: "macos",
runner: "macos-14", runner: "macos-15",
archs: "arm64", archs: "arm64",
}, },
## Windows is disabled because of an issue with compiling FFI as ## Windows is disabled because of an issue with compiling FFI as
@ -54,28 +54,25 @@ jobs:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
persist-credentials: false persist-credentials: false
- if: ${{ matrix.os.family == 'linux' }}
name: "[Linux] Set up QEMU"
uses: docker/setup-qemu-action@v3
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
- name: Get Boost Source
shell: bash
run: |
mkdir -p boost
curl -L https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-b2-nodocs.tar.gz | tar --strip-components=1 -xzC boost
- name: Get FFI - name: Get FFI
shell: bash shell: bash
run: | run: |
mkdir -p ffi mkdir -p ffi
curl -L https://github.com/libffi/libffi/releases/download/v3.4.6/libffi-3.4.6.tar.gz | tar --strip-components=1 -xzC ffi curl -L https://github.com/libffi/libffi/releases/download/v3.4.8/libffi-3.4.8.tar.gz | tar --strip-components=1 -xzC ffi
- if: ${{ matrix.os.family == 'linux' }}
name: "[Linux] Bison 3.8.2"
shell: bash
run: |
mkdir -p bison
curl -L https://ftpmirror.gnu.org/gnu/bison/bison-3.8.2.tar.gz | tar --strip-components=1 -xzC bison
## Software installed by default in GitHub Action Runner VMs: ## Software installed by default in GitHub Action Runner VMs:
## https://github.com/actions/runner-images ## https://github.com/actions/runner-images
- if: ${{ matrix.os.family == 'macos' }} - if: ${{ matrix.os.family == 'macos' }}
name: "[macOS] Flex/Bison" name: "[macOS] Flex/Bison"
run: | run: |
brew install flex bison brew install flex bison
echo "PATH=$(brew --prefix flex)/bin:$PATH" >> $GITHUB_ENV echo "PATH=$(brew --prefix flex)/bin:$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV
echo "PATH=$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV
- if: ${{ matrix.os.family == 'windows' }} - if: ${{ matrix.os.family == 'windows' }}
name: "[Windows] Flex/Bison" name: "[Windows] Flex/Bison"
run: | run: |
@ -100,25 +97,30 @@ jobs:
CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh
CIBW_ENVIRONMENT: > CIBW_ENVIRONMENT: >
CXXFLAGS=-I./boost/pfx/include OPTFLAGS=-O3
LINKFLAGS=-L./boost/pfx/lib
PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig
makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a' PATH="$PWD/bison/src:$PATH"
CIBW_ENVIRONMENT_MACOS: > CIBW_ENVIRONMENT_MACOS: >
CXXFLAGS=-I./boost/pfx/include OPTFLAGS=-O3
LINKFLAGS=-L./boost/pfx/lib
PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig
MACOSX_DEPLOYMENT_TARGET=11 MACOSX_DEPLOYMENT_TARGET=11
makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang' makeFlags='CONFIG=clang'
PATH="$PWD/bison/src:$PATH"
CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh
CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py CIBW_TEST_COMMAND: python3 {project}/tests/pyosys/run_tests.py
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: python-wheels-${{ matrix.os.runner }} name: python-wheels-${{ matrix.os.runner }}
path: ./wheelhouse/*.whl path: ./wheelhouse/*.whl
upload_wheels: upload_wheels:
name: Upload Wheels name: Upload Wheels
if: (github.repository == 'YosysHQ/Yosys') && (github.event_name == 'workflow_dispatch')
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Specifying a GitHub environment is optional, but strongly encouraged
environment: pypi
permissions:
# IMPORTANT: this permission is mandatory for Trusted Publishing
id-token: write
needs: build_wheels needs: build_wheels
steps: steps:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
@ -132,6 +134,3 @@ jobs:
mv *.whl ./dist mv *.whl ./dist
- name: Publish - name: Publish
uses: pypa/gh-action-pypi-publish@release/v1 uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_TOKEN }}
repository-url: ${{ vars.PYPI_INDEX || 'https://upload.pypi.org/legacy/' }}

View file

@ -20,11 +20,19 @@ import os
import yaml import yaml
import platform import platform
import subprocess import subprocess
from pathlib import Path
__dir__ = os.path.dirname(os.path.abspath(__file__)) __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)
workflow = yaml.safe_load(open(os.path.join(os.path.dirname(__dir__), "wheels.yml"))) with open(__yosys_root__ / ".github" / "workflows" / "wheels.yml") as f:
workflow = yaml.safe_load(f)
env = os.environ.copy() env = os.environ.copy()
@ -40,5 +48,5 @@ for key, value in cibw_step["env"].items():
continue continue
env[key] = value env[key] = value
env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS") or platform.machine() env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS", platform.machine())
subprocess.check_call(["cibuildwheel"], env=env) subprocess.check_call(["cibuildwheel"], env=env)

View file

@ -1,23 +1,37 @@
set -e #!/bin/bash
set -x set -e -x
# Build-time dependencies # Build-time dependencies
## Linux Docker Images ## Linux Docker Images
if command -v yum &> /dev/null; then if command -v yum &> /dev/null; then
yum install -y flex bison yum install -y flex # manylinux's bison versions are hopelessly out of date
fi fi
if command -v apk &> /dev/null; then if command -v apk &> /dev/null; then
apk add flex bison apk add flex bison
fi fi
if ! printf '%s\n' '%require "3.8"' '%%' 'start: ;' | bison -o /dev/null /dev/stdin ; then
(
set -e -x
cd bison
./configure
make clean
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)
)
fi
## macOS/Windows -- installed in GitHub Action itself, not container ## macOS/Windows -- installed in GitHub Action itself, not container
# Build Static FFI (platform-dependent but not Python version dependent) # Runtime Dependencies
cd ffi ## Build Static FFI (platform-dependent but not Python version dependent)
## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries (
CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx set -e -x
## Without this, SHELL has a space in its path which breaks the makefile cd ffi
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu) ## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries
## Forces static library to be used in all situations CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx
sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc make clean
make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)
## Forces static library to be used in all situations
sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc
)

View file

@ -1,8 +1,8 @@
set -e set -e
set -x set -x
# Don't use objects from previous compiles on Windows/macOS # Don't use Python objects from previous compiles
make clean make clean-py
# DEBUG: show python3 and python3-config outputs # DEBUG: show python3 and python3-config outputs
if [ "$(uname)" != "Linux" ]; then if [ "$(uname)" != "Linux" ]; then
@ -11,24 +11,3 @@ if [ "$(uname)" != "Linux" ]; then
fi fi
python3 --version python3 --version
python3-config --includes python3-config --includes
# Build boost
cd ./boost
## Delete the artefacts from previous builds (if any)
rm -rf ./pfx
## Bootstrap bjam
./bootstrap.sh --prefix=./pfx
## Build Boost against current version of Python, only for
## static linkage (Boost is statically linked because system boost packages
## wildly vary in versions, including the libboost_python3 version)
./b2\
-j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)\
--prefix=./pfx\
--with-filesystem\
--with-system\
--with-python\
cxxflags="$(python3-config --includes) -std=c++17 -fPIC"\
cflags="$(python3-config --includes) -fPIC"\
link=static\
variant=release\
install

81
.gitignore vendored
View file

@ -1,26 +1,29 @@
## user config
/Makefile.conf
## homebrew
/Brewfile.lock.json
## build artifacts
/.git-abc-submodule-hash
# compiler intermediate files
*.o *.o
*.d *.d
*.dwo *.dwo
.*.swp
*.gch *.gch
*.gcda *.gcda
*.gcno *.gcno
*~ *.so.dSYM/
__pycache__
/.cache ## test artifacts
/.cproject **/run-test.mk
/.project *.err
/.settings *.log
/qtcreator.files *.tmp
/qtcreator.includes
/qtcreator.config # compiler output files
/qtcreator.creator /kernel/version_*.cc
/qtcreator.creator.user /share
/compile_commands.json
/coverage.info
/coverage_html
/Makefile.conf
/viz.js
/yosys /yosys
/yosys.exe /yosys.exe
/yosys.js /yosys.js
@ -36,22 +39,50 @@ __pycache__
/yosys-witness-script.py /yosys-witness-script.py
/yosys-filterlib /yosys-filterlib
/yosys-filterlib.exe /yosys-filterlib.exe
/kernel/*.pyh
/kernel/python_wrappers.cc
/kernel/version_*.cc
/share
/yosys-win32-mxebin-* /yosys-win32-mxebin-*
/yosys-win32-vcxsrc-* /yosys-win32-vcxsrc-*
/yosysjs-* /yosysjs-*
/libyosys.so /libyosys.so
# build directories
/tests/unit/bintest/ /tests/unit/bintest/
/tests/unit/objtest/ /tests/unit/objtest/
/tests/ystests /tests/ystests
/build
/result /result
/dist /dist
/*.egg-info
/build # pyosys
/venv /kernel/*.pyh
/boost /kernel/python_wrappers.cc
/ffi /ffi
/bison
/venv
/*.whl /*.whl
/*.egg-info
# yosysjs dependency
/viz.js
# other
/coverage.info
/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
__pycache__
*~
.*.swp
/.cache
/.vscode
/.cproject
/.project
/.settings
/qtcreator.files
/qtcreator.includes
/qtcreator.config
/qtcreator.creator
/qtcreator.creator.user
/compile_commands.json

View file

@ -6,9 +6,9 @@ brew "git"
brew "graphviz" brew "graphviz"
brew "pkg-config" brew "pkg-config"
brew "python3" brew "python3"
brew "tcl-tk" brew "uv"
brew "xdot" brew "xdot"
brew "bash" brew "bash"
brew "boost-python3" brew "llvm@20"
brew "llvm"
brew "lld" brew "lld"
brew "googletest"

View file

@ -2,9 +2,101 @@
List of major changes and improvements between releases List of major changes and improvements between releases
======================================================= =======================================================
Yosys 0.53 .. Yosys 0.54-dev Yosys 0.59 .. Yosys 0.60-dev
-------------------------- --------------------------
Yosys 0.58 .. Yosys 0.59
--------------------------
* Various
- Pyosys is rewritten using pybind11.
- alumacc: merge independent of sign.
- write_btor: Include $assert and $assume cells in -ywmap output.
- RTLIL parser rewritten for efficiency.
- Wildcards enabled for Liberty file consuming.
- timeest: Add top ports launching/sampling.
* New commands and options
- Added "-apply_derived_type" option to "box_derive" pass.
- Added "-publish_icells" option to "chtype" pass.
- Added "-width" option to "sim" pass.
- Added "sort" pass for sorting the design objects.
- Merged "synth_ecp5" and "synth_nexus" into "synth_lattice" pass.
- Added "-strict-gw5a-dffs" and "-setundef" options to "synth_gowin" pass.
Yosys 0.57 .. Yosys 0.58
--------------------------
* Various
- Run ABC passes in parallel.
- Extending support for buffer normalization.
- Overhaul of logging APIs.
- read_blif: Represent sequential elements with gate cells.
- Support multiple lib files in abc9_exe.
* New commands and options
- Added "-wireshape" option to "show" command to allow
control the shape of wire nodes.
- Added "-relativeshare" option to "read_verilog", "synth"
and "techmap" pass for synthesis reproducibility testing.
- "write_rtlil" pass no longer sorts design, added "-sort"
option to match old behavior
- Added "-sva-continue-on-err" to "verific" pass to allow
processing designs that includes unsupported SVA.
Yosys 0.56 .. Yosys 0.57
--------------------------
* New commands and options
- Added "-initstates" option to "abstract" pass.
- Added "-set-assumes" option to "equiv_induct"
and "equiv_simple" passes.
- Added "-always" option to "raise_error" pass.
- Added "-hierarchy" option to "stat" pass.
- Added "-noflatten" option to "synth_quicklogic" pass.
* Various
- smtbmc: Support skipping steps in cover mode.
- write_btor: support $buf.
- read_verilog: support package import.
Yosys 0.55 .. Yosys 0.56
--------------------------
* New commands and options
- Added "-unescape" option to "rename" pass.
- Added "-assert2cover" option to "chformal" pass.
- Added "linecoverage" pass to generate lcov report from selection.
- Added "opt_hier" pass to enable hierarchical optimization.
- Added "-hieropt" option to "synth" pass.
- Added "-expect-return", "-err-grep" and "-suffix" options
to "bugpoint" pass.
- Added "raise_error" dev pass.
* Various
- Added groups to command reference documentation.
- Added bugpoint guide to documentation.
- verific: correctly reset Verific flags after import.
Yosys 0.54 .. Yosys 0.55
--------------------------
* Various
- read_verilog: Implemented SystemVerilog unique/priority if.
- "attrmap" pass is able to alter memory attributes.
- verific: Support SVA followed-by operator in cover mode.
Yosys 0.53 .. Yosys 0.54
--------------------------
* New commands and options
- Added "-genlib" option to "abc_new" and "abc9_exe" passes.
- Added "-verbose" and "-quiet" options to "libcache" pass.
- Added "-no-sort" option to "write_aiger" pass.
* Various
- Added "muldiv_c" peepopt.
- Accept (and ignore) SystemVerilog unique/priority if.
- "read_verilog" copy inout ports in and out of functions/tasks.
- Enable single-bit vector wires in RTLIL.
* Xilinx support
- Single-port URAM mapping to support memories 2048 x 144b
Yosys 0.52 .. Yosys 0.53 Yosys 0.52 .. Yosys 0.53
-------------------------- --------------------------
* New commands and options * New commands and options

View file

@ -20,6 +20,7 @@ passes/opt/opt_lut.cc @whitequark
passes/techmap/abc9*.cc @eddiehung @Ravenslofty passes/techmap/abc9*.cc @eddiehung @Ravenslofty
backends/aiger/xaiger.cc @eddiehung backends/aiger/xaiger.cc @eddiehung
docs/ @KrystalDelusion docs/ @KrystalDelusion
docs/source/using_yosys/synthesis/abc.rst @KrystalDelusion @Ravenslofty
.github/workflows/*.yml @mmicko .github/workflows/*.yml @mmicko
## External Contributors ## External Contributors
@ -29,15 +30,16 @@ docs/ @KrystalDelusion
# These still override previous lines, so be careful not to # These still override previous lines, so be careful not to
# accidentally disable any of the above rules. # accidentally disable any of the above rules.
frontends/verilog/ @zachjs frontends/verilog/ @widlarizer
frontends/ast/ @zachjs frontends/ast/ @widlarizer
techlibs/intel_alm/ @Ravenslofty techlibs/intel_alm/ @Ravenslofty
techlibs/gowin/ @pepijndevos techlibs/gowin/ @pepijndevos
techlibs/gatemate/ @pu-cc techlibs/gatemate/ @pu-cc
# pyosys # pyosys
misc/*.py @btut pyosys/* @donn
setup.py @donn
backends/firrtl @ucbjrl @azidar backends/firrtl @ucbjrl @azidar

View file

@ -19,14 +19,14 @@ much easier for someone to respond and help.
### Bug reports ### Bug reports
Before you submit an issue, please have a search of the existing issues in case Before you submit an issue, please check out the [how-to guide for
one already exists. Making sure that you have a minimal, complete and `bugpoint`](https://yosys.readthedocs.io/en/latest/using_yosys/bugpoint.html).
verifiable example (MVCE) is a great way to quickly check an existing issue This guide will take you through the process of using the [`bugpoint`
against a new one. Stack overflow has a guide on [how to create an command](https://yosys.readthedocs.io/en/latest/cmd/bugpoint.html) in Yosys to
MVCE](https://stackoverflow.com/help/minimal-reproducible-example). The produce a [minimal, complete and verifiable
[`bugpoint` example](https://stackoverflow.com/help/minimal-reproducible-example) (MVCE).
command](https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/bugpoint.html) Providing an MVCE with your bug report drastically increases the likelihood that
in Yosys can be helpful for this process. someone will be able to help resolve your issue.
# Using pull requests # Using pull requests
@ -60,14 +60,11 @@ merge; please do not use these labels if you are not a maintainer.
# Asking questions # Asking questions
If you have a question about how to use Yosys, please ask on our [discussions If you have a question about how to use Yosys, please ask on our [Discourse forum](https://yosyshq.discourse.group/) or in our [discussions
page](https://github.com/YosysHQ/yosys/discussions) or in our [community page](https://github.com/YosysHQ/yosys/discussions).
slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA). The Discourse is also a great place to ask questions about developing or
The slack is also a great place to ask questions about developing or
contributing to Yosys. contributing to Yosys.
We have open dev 'jour fixe' (JF) meetings where developers from YosysHQ and the 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 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. Please join the place to talk to us about how to implement larger PRs.
community slack if you would like to join the next meeting, the link is
available in the description of the #devel-discuss channel.

210
Makefile
View file

@ -23,10 +23,13 @@ ENABLE_VERIFIC_EDIF := 0
ENABLE_VERIFIC_LIBERTY := 0 ENABLE_VERIFIC_LIBERTY := 0
ENABLE_COVER := 1 ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0 ENABLE_LIBYOSYS := 0
ENABLE_LIBYOSYS_STATIC := 0
ENABLE_ZLIB := 1 ENABLE_ZLIB := 1
ENABLE_HELP_SOURCE := 0
# python wrappers # python wrappers
ENABLE_PYOSYS := 0 ENABLE_PYOSYS := 0
PYOSYS_USE_UV := 1
# other configuration flags # other configuration flags
ENABLE_GCOV := 0 ENABLE_GCOV := 0
@ -43,7 +46,12 @@ LINK_ABC := 0
# Needed for environments that can't run executables (i.e. emscripten, wasm) # Needed for environments that can't run executables (i.e. emscripten, wasm)
DISABLE_SPAWN := 0 DISABLE_SPAWN := 0
# Needed for environments that don't have proper thread support (i.e. emscripten, wasm--for now) # 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 DISABLE_ABC_THREADS := 0
else
DISABLE_ABC_THREADS := 1
endif
# clang sanitizers # clang sanitizers
SANITIZER = SANITIZER =
@ -88,15 +96,15 @@ TARGETS = $(PROGRAM_PREFIX)yosys$(EXE) $(PROGRAM_PREFIX)yosys-config
PRETTY = 1 PRETTY = 1
SMALL = 0 SMALL = 0
# Unit test
UNITESTPATH := tests/unit
all: top-all all: top-all
YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST)))
VPATH := $(YOSYS_SRC) VPATH := $(YOSYS_SRC)
CXXSTD ?= c++17 # 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 CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include
LIBS := $(LIBS) -lstdc++ -lm LIBS := $(LIBS) -lstdc++ -lm
PLUGIN_LINKFLAGS := PLUGIN_LINKFLAGS :=
@ -109,18 +117,16 @@ PLUGIN_LINKFLAGS += -L"$(LIBDIR)"
PLUGIN_LIBS := -lyosys_exe PLUGIN_LIBS := -lyosys_exe
endif endif
ifeq ($(ENABLE_HELP_SOURCE),1)
CXXFLAGS += -DYOSYS_ENABLE_HELP_SOURCE
endif
PKG_CONFIG ?= pkg-config PKG_CONFIG ?= pkg-config
SED ?= sed SED ?= sed
BISON ?= bison BISON ?= bison
STRIP ?= strip STRIP ?= strip
AWK ?= awk AWK ?= awk
ifneq ($(shell :; command -v rsync),)
RSYNC_CP ?= rsync -rc
else
RSYNC_CP ?= cp -ru
endif
ifeq ($(OS), Darwin) ifeq ($(OS), Darwin)
PLUGIN_LINKFLAGS += -undefined dynamic_lookup PLUGIN_LINKFLAGS += -undefined dynamic_lookup
LINKFLAGS += -rdynamic LINKFLAGS += -rdynamic
@ -129,12 +135,8 @@ LINKFLAGS += -rdynamic
ifneq ($(shell :; command -v brew),) ifneq ($(shell :; command -v brew),)
BREW_PREFIX := $(shell brew --prefix)/opt BREW_PREFIX := $(shell brew --prefix)/opt
$(info $$BREW_PREFIX is [${BREW_PREFIX}]) $(info $$BREW_PREFIX is [${BREW_PREFIX}])
ifeq ($(ENABLE_PYOSYS),1) CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include
CXXFLAGS += -I$(BREW_PREFIX)/boost/include LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib
LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib
endif
CXXFLAGS += -I$(BREW_PREFIX)/readline/include
LINKFLAGS += -L$(BREW_PREFIX)/readline/lib
PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)
@ -160,7 +162,7 @@ ifeq ($(OS), Haiku)
CXXFLAGS += -D_DEFAULT_SOURCE CXXFLAGS += -D_DEFAULT_SOURCE
endif endif
YOSYS_VER := 0.53+39 YOSYS_VER := 0.59+134
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
@ -183,7 +185,7 @@ endif
OBJS = kernel/version_$(GIT_REV).o OBJS = kernel/version_$(GIT_REV).o
bumpversion: bumpversion:
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 53c22ab.. | wc -l`/;" Makefile sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 03eb220.. | wc -l`/;" Makefile
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
@ -282,12 +284,11 @@ ifeq ($(WASI_SDK),)
CXX = clang++ CXX = clang++
AR = llvm-ar AR = llvm-ar
RANLIB = llvm-ranlib RANLIB = llvm-ranlib
WASIFLAGS := -target wasm32-wasi --sysroot $(WASI_SYSROOT) $(WASIFLAGS) WASIFLAGS := -target wasm32-wasi $(WASIFLAGS)
else else
CXX = $(WASI_SDK)/bin/clang++ CXX = $(WASI_SDK)/bin/clang++
AR = $(WASI_SDK)/bin/ar AR = $(WASI_SDK)/bin/ar
RANLIB = $(WASI_SDK)/bin/ranlib RANLIB = $(WASI_SDK)/bin/ranlib
WASIFLAGS := --sysroot $(WASI_SDK)/share/wasi-sysroot $(WASIFLAGS)
endif endif
CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) $(OPT_LEVEL) -D_WASI_EMULATED_PROCESS_CLOCKS $(filter-out -fPIC,$(CXXFLAGS)) 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)) LINKFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LINKFLAGS))
@ -301,6 +302,7 @@ DISABLE_SPAWN := 1
ifeq ($(ENABLE_ABC),1) ifeq ($(ENABLE_ABC),1)
LINK_ABC := 1 LINK_ABC := 1
ENABLE_THREADS := 0
DISABLE_ABC_THREADS := 1 DISABLE_ABC_THREADS := 1
endif endif
@ -341,33 +343,35 @@ endif
ifeq ($(ENABLE_LIBYOSYS),1) ifeq ($(ENABLE_LIBYOSYS),1)
TARGETS += libyosys.so TARGETS += libyosys.so
ifeq ($(ENABLE_LIBYOSYS_STATIC),1)
TARGETS += libyosys.a
endif 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) ifeq ($(ENABLE_PYOSYS),1)
# python-config --ldflags includes -l and -L, but LINKFLAGS is only -L # 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)) LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags))
LIBS += $(shell $(PYTHON_CONFIG) --libs) LIBS += $(shell $(PYTHON_CONFIG) --libs)
EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs)) EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs))
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON 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
# Detect name of boost_python library. Some distros use boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
CHECK_BOOST_PYTHON = (echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(LINKFLAGS) $(EXE_LIBS) $(LIBS) -l$(1) - > /dev/null 2>&1 && echo "-l$(1)")
BOOST_PYTHON_LIB ?= $(shell \
$(call CHECK_BOOST_PYTHON,boost_python-py$(subst .,,$(PYTHON_VERSION))) || \
$(call CHECK_BOOST_PYTHON,boost_python-py$(PYTHON_MAJOR_VERSION)) || \
$(call CHECK_BOOST_PYTHON,boost_python$(subst .,,$(PYTHON_VERSION))) || \
$(call CHECK_BOOST_PYTHON,boost_python$(PYTHON_MAJOR_VERSION)) \
)
ifeq ($(BOOST_PYTHON_LIB),)
$(error BOOST_PYTHON_LIB could not be detected. Please define manually)
endif
LIBS += $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
PY_WRAPPER_FILE = kernel/python_wrappers
OBJS += $(PY_WRAPPER_FILE).o OBJS += $(PY_WRAPPER_FILE).o
PY_GEN_SCRIPT= py_wrap_generator PY_GEN_SCRIPT = $(YOSYS_SRC)/pyosys/generator.py
PY_WRAP_INCLUDES := $(shell $(PYTHON_EXECUTABLE) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()") PY_WRAP_INCLUDES := $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes)
endif # ENABLE_PYOSYS endif # ENABLE_PYOSYS
ifeq ($(ENABLE_READLINE),1) ifeq ($(ENABLE_READLINE),1)
@ -455,6 +459,12 @@ endif
ifeq ($(ENABLE_DEBUG),1) ifeq ($(ENABLE_DEBUG),1)
CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS)) CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS))
STRIP :=
endif
ifeq ($(ENABLE_THREADS),1)
CXXFLAGS += -DYOSYS_ENABLE_THREADS
LIBS += -lpthread
endif endif
ifeq ($(ENABLE_ABC),1) ifeq ($(ENABLE_ABC),1)
@ -468,6 +478,9 @@ else
ifeq ($(ABCEXTERNAL),) ifeq ($(ABCEXTERNAL),)
TARGETS := $(PROGRAM_PREFIX)yosys-abc$(EXE) $(TARGETS) TARGETS := $(PROGRAM_PREFIX)yosys-abc$(EXE) $(TARGETS)
endif endif
ifeq ($(DISABLE_SPAWN),1)
$(error ENABLE_ABC=1 requires either LINK_ABC=1 or DISABLE_SPAWN=0)
endif
endif endif
endif endif
@ -519,8 +532,12 @@ ifeq ($(ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS),1)
VERIFIC_COMPONENTS += extensions VERIFIC_COMPONENTS += extensions
CXXFLAGS += -DYOSYSHQ_VERIFIC_EXTENSIONS CXXFLAGS += -DYOSYSHQ_VERIFIC_EXTENSIONS
else 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),) ifneq ($(wildcard $(VERIFIC_DIR)/extensions),)
VERIFIC_COMPONENTS += extensions VERIFIC_COMPONENTS += extensions
OBJS += kernel/log_compat.o
endif endif
endif endif
CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
@ -531,7 +548,6 @@ LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VE
endif endif
endif endif
ifeq ($(ENABLE_COVER),1) ifeq ($(ENABLE_COVER),1)
CXXFLAGS += -DYOSYS_ENABLE_COVER CXXFLAGS += -DYOSYS_ENABLE_COVER
endif endif
@ -551,6 +567,13 @@ $(subst //,/,$(1)/$(notdir $(2))): $(2)
$$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(notdir $(2))) $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(notdir $(2)))
endef 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 define add_gen_share_file
EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2)))
$(subst //,/,$(1)/$(notdir $(2))): $(2) $(subst //,/,$(1)/$(notdir $(2))): $(2)
@ -613,6 +636,7 @@ $(eval $(call add_include_file,kernel/satgen.h))
$(eval $(call add_include_file,kernel/scopeinfo.h)) $(eval $(call add_include_file,kernel/scopeinfo.h))
$(eval $(call add_include_file,kernel/sexpr.h)) $(eval $(call add_include_file,kernel/sexpr.h))
$(eval $(call add_include_file,kernel/sigtools.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/timinginfo.h))
$(eval $(call add_include_file,kernel/utils.h)) $(eval $(call add_include_file,kernel/utils.h))
$(eval $(call add_include_file,kernel/yosys.h)) $(eval $(call add_include_file,kernel/yosys.h))
@ -626,15 +650,21 @@ endif
$(eval $(call add_include_file,libs/sha1/sha1.h)) $(eval $(call add_include_file,libs/sha1/sha1.h))
$(eval $(call add_include_file,libs/json11/json11.hpp)) $(eval $(call add_include_file,libs/json11/json11.hpp))
$(eval $(call add_include_file,passes/fsm/fsmdata.h)) $(eval $(call add_include_file,passes/fsm/fsmdata.h))
$(eval $(call add_include_file,passes/techmap/libparse.h))
$(eval $(call add_include_file,frontends/ast/ast.h)) $(eval $(call add_include_file,frontends/ast/ast.h))
$(eval $(call add_include_file,frontends/ast/ast_binding.h)) $(eval $(call add_include_file,frontends/ast/ast_binding.h))
$(eval $(call add_include_file,frontends/blif/blifparse.h)) $(eval $(call add_include_file,frontends/blif/blifparse.h))
$(eval $(call add_include_file,backends/rtlil/rtlil_backend.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/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/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/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 OBJS += kernel/drivertools.o kernel/functional.o kernel/threading.o
ifeq ($(ENABLE_ZLIB),1) ifeq ($(ENABLE_ZLIB),1)
OBJS += kernel/fstdata.o OBJS += kernel/fstdata.o
endif endif
@ -744,11 +774,14 @@ $(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
ifeq ($(OS), Darwin) ifeq ($(OS), Darwin)
$(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) $(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
else else
$(P) $(CXX) -o libyosys.so -shared -Wl,-soname,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) $(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
endif endif
libyosys.a: $(filter-out kernel/driver.o,$(OBJS))
$(P) $(AR) rcs $@ $^
%.o: %.cc %.o: %.cc
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
@ -758,9 +791,9 @@ endif
$(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(CXX) $(CXXFLAGS) -x c++ -o $@ -E -P - $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(CXX) $(CXXFLAGS) -x c++ -o $@ -E -P -
ifeq ($(ENABLE_PYOSYS),1) ifeq ($(ENABLE_PYOSYS),1)
$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT) pyosys/wrappers_tpl.cc $(PY_WRAP_INCLUDES) pyosys/hashlib.h
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
$(P) $(PYTHON_EXECUTABLE) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")" $(P) $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) $(PY_WRAPPER_FILE).cc
endif endif
%.o: %.cpp %.o: %.cpp
@ -828,7 +861,17 @@ check-git-abc:
exit 1; \ exit 1; \
fi fi
abc/abc$(EXE) abc/libabc.a: | check-git-abc .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) $(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) $(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)
@ -866,12 +909,15 @@ MK_TEST_DIRS += tests/arch/nexus
MK_TEST_DIRS += tests/arch/quicklogic/pp3 MK_TEST_DIRS += tests/arch/quicklogic/pp3
MK_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f MK_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f
MK_TEST_DIRS += tests/arch/xilinx MK_TEST_DIRS += tests/arch/xilinx
MK_TEST_DIRS += tests/bugpoint
MK_TEST_DIRS += tests/opt MK_TEST_DIRS += tests/opt
MK_TEST_DIRS += tests/sat MK_TEST_DIRS += tests/sat
MK_TEST_DIRS += tests/sdc
MK_TEST_DIRS += tests/sim MK_TEST_DIRS += tests/sim
MK_TEST_DIRS += tests/svtypes MK_TEST_DIRS += tests/svtypes
MK_TEST_DIRS += tests/techmap MK_TEST_DIRS += tests/techmap
MK_TEST_DIRS += tests/various MK_TEST_DIRS += tests/various
MK_TEST_DIRS += tests/rtlil
ifeq ($(ENABLE_VERIFIC),1) ifeq ($(ENABLE_VERIFIC),1)
ifneq ($(YOSYS_NOVERIFIC),1) ifneq ($(YOSYS_NOVERIFIC),1)
MK_TEST_DIRS += tests/verific MK_TEST_DIRS += tests/verific
@ -979,32 +1025,41 @@ unit-test: libyosys.so
clean-unit-test: clean-unit-test:
@$(MAKE) -C $(UNITESTPATH) clean @$(MAKE) -C $(UNITESTPATH) 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: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR) $(INSTALL_SUDO) cp $(filter-out libyosys.so libyosys.a,$(TARGETS)) $(DESTDIR)$(BINDIR)
ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),) ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),)
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys; fi
endif endif
ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),) ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),)
$(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc; fi
endif endif
ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),) ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),)
$(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib; fi
endif endif
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1) ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/ $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so 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) ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys $(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 libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
$(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys $(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
ifeq ($(ENABLE_ABC),1) ifeq ($(ENABLE_ABC),1)
$(INSTALL_SUDO) cp yosys-abc $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc $(INSTALL_SUDO) cp yosys-abc $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc
endif endif
$(INSTALL_SUDO) cp misc/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/
endif endif
endif endif
ifeq ($(ENABLE_PLUGINS),1) ifeq ($(ENABLE_PLUGINS),1)
@ -1019,6 +1074,9 @@ uninstall:
$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR)
ifeq ($(ENABLE_LIBYOSYS),1) ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so $(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) 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/libyosys.so
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py $(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py
@ -1026,19 +1084,8 @@ ifeq ($(ENABLE_PYOSYS),1)
endif endif
endif endif
# also others, but so long as it doesn't fail this is enough to know we tried docs/source/generated/cmds.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS)
docs/source/cmd/abc.rst: $(TARGETS) $(EXTRA_TARGETS) $(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cmds-json $@'
$(Q) mkdir -p docs/source/cmd
$(Q) mkdir -p temp/docs/source/cmd
$(Q) cd temp && ./../$(PROGRAM_PREFIX)yosys -p 'help -write-rst-command-reference-manual'
$(Q) $(RSYNC_CP) temp/docs/source/cmd docs/source
$(Q) rm -rf temp
docs/source/cell/word_add.rst: $(TARGETS) $(EXTRA_TARGETS)
$(Q) mkdir -p docs/source/cell
$(Q) mkdir -p temp/docs/source/cell
$(Q) cd temp && ./../$(PROGRAM_PREFIX)yosys -p 'help -write-rst-cells-manual'
$(Q) $(RSYNC_CP) temp/docs/source/cell docs/source
$(Q) rm -rf temp
docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS)
$(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@' $(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@'
@ -1055,6 +1102,15 @@ docs/source/generated/functional/rosette.diff: backends/functional/smtlib.cc bac
PHONY: docs/gen/functional_ir PHONY: docs/gen/functional_ir
docs/gen/functional_ir: docs/source/generated/functional/smtlib.cc docs/source/generated/functional/rosette.diff 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 PHONY: docs/gen docs/usage docs/reqs
docs/gen: $(TARGETS) docs/gen: $(TARGETS)
$(Q) $(MAKE) -C docs gen $(Q) $(MAKE) -C docs gen
@ -1090,18 +1146,16 @@ docs/reqs:
$(Q) $(MAKE) -C docs reqs $(Q) $(MAKE) -C docs reqs
.PHONY: docs/prep .PHONY: docs/prep
docs/prep: docs/source/cmd/abc.rst docs/source/generated/cells.json docs/gen docs/usage docs/gen/functional_ir 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 DOC_TARGET ?= html
docs: docs/prep docs: docs/prep
$(Q) $(MAKE) -C docs $(DOC_TARGET) $(Q) $(MAKE) -C docs $(DOC_TARGET)
clean: clean: clean-py clean-unit-test
rm -rf share rm -rf share
rm -rf kernel/*.pyh rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc
rm -f kernel/version_*.o kernel/version_*.cc rm -f kernel/version_*.o kernel/version_*.cc
rm -f kernel/python_wrappers.o
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d 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/asicworld/*.out tests/asicworld/*.log
rm -rf tests/hana/*.out tests/hana/*.log rm -rf tests/hana/*.out tests/hana/*.log
@ -1113,14 +1167,20 @@ clean:
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/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 tests/tools/cmp_tbdata
rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS)) rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS))
-$(MAKE) -C docs clean -$(MAKE) -C $(YOSYS_SRC)/docs clean
rm -rf docs/source/cmd docs/util/__pycache__ rm -rf docs/util/__pycache__
rm -f *.whl
rm -f libyosys.so 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: clean-abc:
$(MAKE) -C abc DEP= clean $(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 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 mrproper: clean
git clean -xdf git clean -xdf
@ -1221,5 +1281,5 @@ echo-cxx:
FORCE: FORCE:
.PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc .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 .PHONY: config-clean config-clang config-gcc config-gcc-static config-gprof config-sudo

View file

@ -25,6 +25,9 @@ Web Site and Other Resources
More information and documentation can be found on the Yosys web site: More information and documentation can be found on the Yosys web site:
- https://yosyshq.net/yosys/ - https://yosyshq.net/yosys/
If you have any Yosys-related questions, please post them on the Discourse group:
- https://yosyshq.discourse.group
Documentation from this repository is automatically built and available on Read Documentation from this repository is automatically built and available on Read
the Docs: the Docs:
- https://yosyshq.readthedocs.io/projects/yosys - https://yosyshq.readthedocs.io/projects/yosys
@ -34,6 +37,9 @@ verification front-end for Yosys, SBY:
- https://yosyshq.readthedocs.io/projects/sby/ - https://yosyshq.readthedocs.io/projects/sby/
- https://github.com/YosysHQ/sby - https://github.com/YosysHQ/sby
The Yosys blog has news and articles from users:
- https://blog.yosyshq.com
Installation Installation
============ ============
@ -74,13 +80,13 @@ 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). TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
For example on Ubuntu Linux 16.04 LTS the following commands will install all For example on Ubuntu Linux 22.04 LTS the following commands will install all
prerequisites for building yosys: prerequisites for building yosys:
$ sudo apt-get install build-essential clang lld bison flex \ $ sudo apt-get install gawk git make python3 lld bison clang flex \
libreadline-dev gawk tcl-dev libffi-dev git \ libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev \
graphviz xdot pkg-config python3 libboost-system-dev \ graphviz xdot
libboost-python-dev libboost-filesystem-dev zlib1g-dev $ curl -LsSf https://astral.sh/uv/install.sh | sh
The environment variable `CXX` can be used to control the C++ compiler used, or The environment variable `CXX` can be used to control the C++ compiler used, or
run one of the following to override it: run one of the following to override it:
@ -242,7 +248,7 @@ Note that there is no need to build the manual if you just want to read it.
Simply visit https://yosys.readthedocs.io/en/latest/ instead. Simply visit https://yosys.readthedocs.io/en/latest/ instead.
In addition to those packages listed above for building Yosys from source, the In addition to those packages listed above for building Yosys from source, the
following are used for building the website: following are used for building the website:
$ sudo apt install pdf2svg faketime $ sudo apt install pdf2svg faketime
@ -258,7 +264,7 @@ build process for the website. Or, run the following:
Or for MacOS, using homebrew: Or for MacOS, using homebrew:
$ brew install basictex $ brew install basictex
$ sudo tlmgr update --self $ sudo tlmgr update --self
$ sudo tlmgr install collection-latexextra latexmk tex-gyre $ sudo tlmgr install collection-latexextra latexmk tex-gyre
The Python package, Sphinx, is needed along with those listed in The Python package, Sphinx, is needed along with those listed in
@ -268,5 +274,13 @@ The Python package, Sphinx, is needed along with those listed in
From the root of the repository, run `make docs`. This will build/rebuild yosys 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 as necessary before generating the website documentation from the yosys help
commands. To build for pdf instead of html, call commands. To build for pdf instead of html, call
`make docs DOC_TARGET=latexpdf`. `make docs DOC_TARGET=latexpdf`.
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.

2
abc

@ -1 +1 @@
Subproject commit e55d316cc9a7f72a84a76eda555aa6ec083c9d0d Subproject commit 1c5ed1ce378cc04beac30bb31abc4c37c8467042

View file

@ -132,7 +132,7 @@ struct AigerWriter
return a; return a;
} }
AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module) AigerWriter(Module *module, bool no_sort, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
{ {
pool<SigBit> undriven_bits; pool<SigBit> undriven_bits;
pool<SigBit> unused_bits; pool<SigBit> unused_bits;
@ -152,6 +152,37 @@ struct AigerWriter
if (wire->port_input) if (wire->port_input)
sigmap.add(wire); sigmap.add(wire);
// handle ports
// provided the input_bits and output_bits don't get sorted they
// will be returned in reverse order, so add them in reverse to
// match
for (auto riter = module->ports.rbegin(); riter != module->ports.rend(); ++riter) {
auto *wire = module->wire(*riter);
for (int i = 0; i < GetSize(wire); i++)
{
SigBit wirebit(wire, i);
SigBit bit = sigmap(wirebit);
if (bit.wire == nullptr) {
if (wire->port_output) {
aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
output_bits.insert(wirebit);
}
continue;
}
if (wire->port_input)
input_bits.insert(bit);
if (wire->port_output) {
if (bit != wirebit)
alias_map[wirebit] = bit;
output_bits.insert(wirebit);
}
}
}
// handle wires
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if (wire->attributes.count(ID::init)) { if (wire->attributes.count(ID::init)) {
@ -167,25 +198,13 @@ struct AigerWriter
SigBit wirebit(wire, i); SigBit wirebit(wire, i);
SigBit bit = sigmap(wirebit); SigBit bit = sigmap(wirebit);
if (bit.wire == nullptr) { if (bit.wire == nullptr)
if (wire->port_output) { continue;
aig_map[wirebit] = (bit == State::S1) ? 1 : 0; if (wire->port_input || wire->port_output)
output_bits.insert(wirebit);
}
continue; continue;
}
undriven_bits.insert(bit); undriven_bits.insert(bit);
unused_bits.insert(bit); unused_bits.insert(bit);
if (wire->port_input)
input_bits.insert(bit);
if (wire->port_output) {
if (bit != wirebit)
alias_map[wirebit] = bit;
output_bits.insert(wirebit);
}
} }
if (wire->width == 1) { if (wire->width == 1) {
@ -200,12 +219,6 @@ struct AigerWriter
} }
} }
for (auto bit : input_bits)
undriven_bits.erase(bit);
for (auto bit : output_bits)
unused_bits.erase(bit);
for (auto cell : module->cells()) for (auto cell : module->cells())
{ {
if (cell->type == ID($_NOT_)) if (cell->type == ID($_NOT_))
@ -343,8 +356,11 @@ struct AigerWriter
} }
init_map.sort(); init_map.sort();
input_bits.sort(); // we are relying here on unsorted pools iterating last-in-first-out
output_bits.sort(); if (!no_sort) {
input_bits.sort();
output_bits.sort();
}
not_map.sort(); not_map.sort();
ff_map.sort(); ff_map.sort();
and_map.sort(); and_map.sort();
@ -697,7 +713,7 @@ struct AigerWriter
} }
if (wire->port_output) { if (wire->port_output) {
int o = ordered_outputs.at(sig[i]); 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, log_id(wire));
} }
@ -901,6 +917,9 @@ struct AigerBackend : public Backend {
log(" -symbols\n"); log(" -symbols\n");
log(" include a symbol table in the generated AIGER file\n"); log(" include a symbol table in the generated AIGER file\n");
log("\n"); log("\n");
log(" -no-sort\n");
log(" don't sort input/output ports\n");
log("\n");
log(" -map <filename>\n"); log(" -map <filename>\n");
log(" write an extra file with port and latch symbols\n"); log(" write an extra file with port and latch symbols\n");
log("\n"); log("\n");
@ -925,6 +944,7 @@ struct AigerBackend : public Backend {
bool zinit_mode = false; bool zinit_mode = false;
bool miter_mode = false; bool miter_mode = false;
bool symbols_mode = false; bool symbols_mode = false;
bool no_sort = false;
bool verbose_map = false; bool verbose_map = false;
bool imode = false; bool imode = false;
bool omode = false; bool omode = false;
@ -955,6 +975,10 @@ struct AigerBackend : public Backend {
symbols_mode = true; symbols_mode = true;
continue; continue;
} }
if (args[argidx] == "-no-sort") {
no_sort = true;
continue;
}
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) { if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
map_filename = args[++argidx]; map_filename = args[++argidx];
continue; continue;
@ -1008,7 +1032,7 @@ struct AigerBackend : public Backend {
if (!top_module->memories.empty()) 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", log_id(top_module));
AigerWriter writer(top_module, zinit_mode, imode, omode, bmode, lmode); AigerWriter writer(top_module, no_sort, zinit_mode, imode, omode, bmode, lmode);
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
if (!map_filename.empty()) { if (!map_filename.empty()) {
@ -1016,7 +1040,7 @@ struct AigerBackend : public Backend {
std::ofstream mapf; std::ofstream mapf;
mapf.open(map_filename.c_str(), std::ofstream::trunc); mapf.open(map_filename.c_str(), std::ofstream::trunc);
if (mapf.fail()) if (mapf.fail())
log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); log_error("Can't open file `%s' for writing: %s\n", map_filename, strerror(errno));
writer.write_map(mapf, verbose_map, no_startoffset); writer.write_map(mapf, verbose_map, no_startoffset);
} }
@ -1027,7 +1051,7 @@ struct AigerBackend : public Backend {
PrettyJson json; PrettyJson json;
if (!json.write_to_file(yw_map_filename)) if (!json.write_to_file(yw_map_filename))
log_error("Can't open file `%s' for writing: %s\n", yw_map_filename.c_str(), strerror(errno)); log_error("Can't open file `%s' for writing: %s\n", yw_map_filename, strerror(errno));
writer.write_ywmap(json); writer.write_ywmap(json);
} }
} }

View file

@ -788,7 +788,7 @@ struct XAigerBackend : public Backend {
std::ofstream mapf; std::ofstream mapf;
mapf.open(map_filename.c_str(), std::ofstream::trunc); mapf.open(map_filename.c_str(), std::ofstream::trunc);
if (mapf.fail()) if (mapf.fail())
log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); log_error("Can't open file `%s' for writing: %s\n", map_filename, strerror(errno));
writer.write_map(mapf); writer.write_map(mapf);
} }
} }

View file

@ -91,7 +91,7 @@ struct Index {
int pos = index_wires(info, m); int pos = index_wires(info, m);
for (auto cell : m->cells()) { for (auto cell : m->cells()) {
if (cell->type.in(KNOWN_OPS) || cell->type.in(ID($scopeinfo), ID($specify2), ID($specify3))) if (cell->type.in(KNOWN_OPS) || cell->type.in(ID($scopeinfo), ID($specify2), ID($specify3), ID($input_port)))
continue; continue;
Module *submodule = m->design->module(cell->type); Module *submodule = m->design->module(cell->type);
@ -105,6 +105,13 @@ struct Index {
if (allow_blackboxes) { if (allow_blackboxes) {
info.found_blackboxes.insert(cell); info.found_blackboxes.insert(cell);
} else { } else {
// Even if we don't allow blackboxes these might still be
// present outside of any traversed input cones, so we
// can't bail at this point. If they are hit by a traversal
// (which can only really happen with $tribuf not
// $connect), we can still detect this as an error later.
if (cell->type == ID($connect) || (cell->type == ID($tribuf) && cell->has_attribute(ID(aiger2_zbuf))))
continue;
if (!submodule || submodule->get_blackbox_attribute()) if (!submodule || submodule->get_blackbox_attribute())
log_error("Unsupported cell type: %s (%s in %s)\n", log_error("Unsupported cell type: %s (%s in %s)\n",
log_id(cell->type), log_id(cell), log_id(m)); log_id(cell->type), log_id(cell), log_id(m));
@ -483,7 +490,8 @@ struct Index {
{ {
Design *design = index.design; Design *design = index.design;
auto &minfo = leaf_minfo(index); auto &minfo = leaf_minfo(index);
log_assert(minfo.suboffsets.count(cell)); 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));
Module *def = design->module(cell->type); Module *def = design->module(cell->type);
log_assert(def); log_assert(def);
levels.push_back(Level(index.modules.at(def), cell)); levels.push_back(Level(index.modules.at(def), cell));
@ -566,7 +574,7 @@ struct Index {
} }
Lit ret; Lit ret;
if (!bit.wire->port_input) { if (!bit.wire->port_input || bit.wire->port_output) {
// an output of a cell // an output of a cell
Cell *driver = bit.wire->driverCell(); Cell *driver = bit.wire->driverCell();
@ -618,7 +626,7 @@ struct Index {
if (!cursor) { if (!cursor) {
log_assert(bit.wire->module == top); log_assert(bit.wire->module == top);
log_assert(bit.wire->port_input); log_assert(bit.wire->port_input && !bit.wire->port_output);
return lits[top_minfo->windices[bit.wire] + bit.offset]; return lits[top_minfo->windices[bit.wire] + bit.offset];
} else { } else {
log_assert(bit.wire->module == cursor->leaf_module(*this)); log_assert(bit.wire->module == cursor->leaf_module(*this));
@ -723,7 +731,7 @@ struct AigerWriter : Index<AigerWriter, unsigned int, 0, 1> {
for (auto id : top->ports) { for (auto id : top->ports) {
Wire *w = top->wire(id); Wire *w = top->wire(id);
log_assert(w); log_assert(w);
if (w->port_input) if (w->port_input && !w->port_output)
for (int i = 0; i < w->width; i++) { for (int i = 0; i < w->width; i++) {
pi_literal(SigBit(w, i)) = lit_counter; pi_literal(SigBit(w, i)) = lit_counter;
inputs.push_back(SigBit(w, i)); inputs.push_back(SigBit(w, i));
@ -828,7 +836,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
{ {
log_assert(cursor.is_top()); // TOOD: fix analyzer to work with hierarchy log_assert(cursor.is_top()); // TOOD: fix analyzer to work with hierarchy
if (bit.wire->port_input) if (bit.wire->port_input && !bit.wire->port_output)
return false; return false;
Cell *driver = bit.wire->driverCell(); Cell *driver = bit.wire->driverCell();
@ -838,7 +846,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
int max = 1; int max = 1;
for (auto wire : mod->wires()) for (auto wire : mod->wires())
if (wire->port_input) if (wire->port_input && !wire->port_output)
for (int i = 0; i < wire->width; i++) { for (int i = 0; i < wire->width; i++) {
int ilevel = visit(cursor, driver->getPort(wire->name)[i]); int ilevel = visit(cursor, driver->getPort(wire->name)[i]);
max = std::max(max, ilevel + 1); max = std::max(max, ilevel + 1);
@ -858,7 +866,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
for (auto id : top->ports) { for (auto id : top->ports) {
Wire *w = top->wire(id); Wire *w = top->wire(id);
log_assert(w); log_assert(w);
if (w->port_input) if (w->port_input && !w->port_output)
for (int i = 0; i < w->width; i++) for (int i = 0; i < w->width; i++)
pi_literal(SigBit(w, i)) = 0; pi_literal(SigBit(w, i)) = 0;
} }
@ -868,7 +876,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
Module *def = design->module(box->type); Module *def = design->module(box->type);
if (!(def && def->has_attribute(ID::abc9_box_id))) if (!(def && def->has_attribute(ID::abc9_box_id)))
for (auto &conn : box->connections_) for (auto &conn : box->connections_)
if (box->output(conn.first)) if (box->port_dir(conn.first) != RTLIL::PD_INPUT)
for (auto bit : conn.second) for (auto bit : conn.second)
pi_literal(bit, &cursor) = 0; pi_literal(bit, &cursor) = 0;
} }
@ -883,7 +891,7 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
Module *def = design->module(box->type); Module *def = design->module(box->type);
if (!(def && def->has_attribute(ID::abc9_box_id))) if (!(def && def->has_attribute(ID::abc9_box_id)))
for (auto &conn : box->connections_) for (auto &conn : box->connections_)
if (box->input(conn.first)) if (box->port_dir(conn.first) == RTLIL::PD_INPUT)
for (auto bit : conn.second) for (auto bit : conn.second)
(void) eval_po(bit); (void) eval_po(bit);
} }
@ -903,6 +911,16 @@ struct XAigerWriter : AigerWriter {
typedef std::pair<SigBit, HierCursor> HierBit; typedef std::pair<SigBit, HierCursor> HierBit;
std::vector<HierBit> pos; std::vector<HierBit> pos;
std::vector<HierBit> pis; std::vector<HierBit> 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.
int proper_pos_counter = 0; int proper_pos_counter = 0;
pool<SigBit> driven_by_opaque_box; pool<SigBit> driven_by_opaque_box;
@ -937,15 +955,10 @@ struct XAigerWriter : AigerWriter {
lit_counter += 2; lit_counter += 2;
} }
void append_box_ports(Cell *box, HierCursor &cursor, bool inputs) void append_opaque_box_ports(Cell *box, HierCursor &cursor, bool inputs)
{ {
for (auto &conn : box->connections_) { for (auto &conn : box->connections_) {
bool is_input = box->input(conn.first); bool is_input = box->port_dir(conn.first) == RTLIL::PD_INPUT;
bool is_output = box->output(conn.first);
if (!(is_input || is_output) || (is_input && is_output))
log_error("Ambiguous port direction on %s/%s\n",
log_id(box->type), log_id(conn.first));
if (is_input && inputs) { if (is_input && inputs) {
int bitp = 0; int bitp = 0;
@ -955,13 +968,14 @@ struct XAigerWriter : AigerWriter {
continue; continue;
} }
// Inputs to opaque boxes are proper POs as far as abc is concerned
if (map_file.is_open()) { if (map_file.is_open()) {
log_assert(cursor.is_top()); log_assert(cursor.is_top());
map_file << "pseudopo " << proper_pos_counter++ << " " << bitp map_file << "pseudopo " << proper_pos_counter << " " << bitp
<< " " << box->name.c_str() << " " << box->name.c_str()
<< " " << conn.first.c_str() << "\n"; << " " << conn.first.c_str() << "\n";
} }
proper_pos_counter++;
pos.push_back(std::make_pair(bit, cursor)); pos.push_back(std::make_pair(bit, cursor));
if (mapping_prep) if (mapping_prep)
@ -969,10 +983,10 @@ struct XAigerWriter : AigerWriter {
bitp++; bitp++;
} }
} else if (is_output && !inputs) { } else if (!is_input && !inputs) {
for (auto &bit : conn.second) { for (auto &bit : conn.second) {
if (!bit.wire || bit.wire->port_input) if (!bit.wire || (bit.wire->port_input && !bit.wire->port_output))
log_error("Bad connection"); log_error("Bad connection %s/%s ~ %s\n", log_id(box), log_id(conn.first), log_signal(conn.second));
ensure_pi(bit, cursor); ensure_pi(bit, cursor);
@ -1011,8 +1025,8 @@ struct XAigerWriter : AigerWriter {
auto &minfo = cursor.leaf_minfo(*this); auto &minfo = cursor.leaf_minfo(*this);
for (auto box : minfo.found_blackboxes) { for (auto box : minfo.found_blackboxes) {
log_debug(" - %s.%s (type %s): ", cursor.path().c_str(), log_debug(" - %s.%s (type %s): ", cursor.path(),
RTLIL::unescape_id(box->name).c_str(), RTLIL::unescape_id(box->name),
log_id(box->type)); log_id(box->type));
Module *box_module = design->module(box->type), *box_derived; Module *box_module = design->module(box->type), *box_derived;
@ -1038,7 +1052,7 @@ struct XAigerWriter : AigerWriter {
}); });
for (auto [cursor, box, def] : opaque_boxes) for (auto [cursor, box, def] : opaque_boxes)
append_box_ports(box, cursor, false); append_opaque_box_ports(box, cursor, false);
holes_module = design->addModule(NEW_ID); holes_module = design->addModule(NEW_ID);
std::vector<RTLIL::Wire *> holes_pis; std::vector<RTLIL::Wire *> holes_pis;
@ -1086,6 +1100,8 @@ struct XAigerWriter : AigerWriter {
bit = RTLIL::Sx; bit = RTLIL::Sx;
} }
// Nonopaque box inputs come first and are not part of
// the PO numbering used by the mapping file.
pos.push_back(std::make_pair(bit, cursor)); pos.push_back(std::make_pair(bit, cursor));
} }
boxes_co_num += port->width; boxes_co_num += port->width;
@ -1106,7 +1122,7 @@ struct XAigerWriter : AigerWriter {
holes_pi_idx++; holes_pi_idx++;
} }
holes_wb->setPort(port_id, in_conn); holes_wb->setPort(port_id, in_conn);
} else if (port->port_output && !port->port_input) { } else if (port->port_output) {
// primary // primary
for (int i = 0; i < port->width; i++) { for (int i = 0; i < port->width; i++) {
SigBit bit; SigBit bit;
@ -1138,7 +1154,7 @@ struct XAigerWriter : AigerWriter {
} }
for (auto [cursor, box, def] : opaque_boxes) for (auto [cursor, box, def] : opaque_boxes)
append_box_ports(box, cursor, true); append_opaque_box_ports(box, cursor, true);
write_be32(h_buffer, 1); write_be32(h_buffer, 1);
write_be32(h_buffer, pis.size()); write_be32(h_buffer, pis.size());
@ -1159,7 +1175,7 @@ struct XAigerWriter : AigerWriter {
log_assert(port); log_assert(port);
if (port->port_input && !port->port_output) { if (port->port_input && !port->port_output) {
box_co_num += port->width; box_co_num += port->width;
} else if (port->port_output && !port->port_input) { } else if (port->port_output) {
box_ci_num += port->width; box_ci_num += port->width;
} else { } else {
log_abort(); log_abort();
@ -1182,7 +1198,7 @@ struct XAigerWriter : AigerWriter {
reset_counters(); reset_counters();
for (auto w : top->wires()) for (auto w : top->wires())
if (w->port_input) if (w->port_input && !w->port_output)
for (int i = 0; i < w->width; i++) for (int i = 0; i < w->width; i++)
ensure_pi(SigBit(w, i)); ensure_pi(SigBit(w, i));
@ -1195,10 +1211,14 @@ struct XAigerWriter : AigerWriter {
for (auto w : top->wires()) for (auto w : top->wires())
if (w->port_output) if (w->port_output)
for (int i = 0; i < w->width; i++) { 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))) { if (map_file.is_open() && !driven_by_opaque_box.count(SigBit(w, i))) {
map_file << "po " << proper_pos_counter++ << " " << i map_file << "po " << proper_pos_counter << " " << i
<< " " << w->name.c_str() << "\n"; << " " << w->name.c_str() << "\n";
} }
proper_pos_counter++;
pos.push_back(std::make_pair(SigBit(w, i), HierCursor{})); pos.push_back(std::make_pair(SigBit(w, i), HierCursor{}));
} }
@ -1446,7 +1466,7 @@ struct XAiger2Backend : Backend {
if (!map_filename.empty()) { if (!map_filename.empty()) {
writer.map_file.open(map_filename); writer.map_file.open(map_filename);
if (!writer.map_file) if (!writer.map_file)
log_cmd_error("Failed to open '%s' for writing\n", map_filename.c_str()); log_cmd_error("Failed to open '%s' for writing\n", map_filename);
} }
design->bufNormalize(true); design->bufNormalize(true);

View file

@ -157,14 +157,14 @@ struct BlifDumper
f << stringf("%c", ch); f << stringf("%c", ch);
f << stringf("\"\n"); f << stringf("\"\n");
} else } else
f << stringf("%s\n", param.second.as_string().c_str()); f << stringf("%s\n", param.second.as_string());
} }
} }
void dump() void dump()
{ {
f << stringf("\n"); f << stringf("\n");
f << stringf(".model %s\n", str(module->name).c_str()); f << stringf(".model %s\n", str(module->name));
std::map<int, RTLIL::Wire*> inputs, outputs; std::map<int, RTLIL::Wire*> inputs, outputs;
@ -179,7 +179,7 @@ struct BlifDumper
for (auto &it : inputs) { for (auto &it : inputs) {
RTLIL::Wire *wire = it.second; RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++) for (int i = 0; i < wire->width; i++)
f << stringf(" %s", str(RTLIL::SigSpec(wire, i)).c_str()); f << stringf(" %s", str(RTLIL::SigSpec(wire, i)));
} }
f << stringf("\n"); f << stringf("\n");
@ -187,7 +187,7 @@ struct BlifDumper
for (auto &it : outputs) { for (auto &it : outputs) {
RTLIL::Wire *wire = it.second; RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++) for (int i = 0; i < wire->width; i++)
f << stringf(" %s", str(RTLIL::SigSpec(wire, i)).c_str()); f << stringf(" %s", str(RTLIL::SigSpec(wire, i)));
} }
f << stringf("\n"); f << stringf("\n");
@ -200,7 +200,7 @@ struct BlifDumper
if (!config->impltf_mode) { if (!config->impltf_mode) {
if (!config->false_type.empty()) { if (!config->false_type.empty()) {
if (config->false_type == "+") if (config->false_type == "+")
f << stringf(".names %s\n", config->false_out.c_str()); f << stringf(".names %s\n", config->false_out);
else if (config->false_type != "-") else if (config->false_type != "-")
f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type), f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
config->false_type.c_str(), config->false_out.c_str()); config->false_type.c_str(), config->false_out.c_str());
@ -208,7 +208,7 @@ struct BlifDumper
f << stringf(".names $false\n"); f << stringf(".names $false\n");
if (!config->true_type.empty()) { if (!config->true_type.empty()) {
if (config->true_type == "+") if (config->true_type == "+")
f << stringf(".names %s\n1\n", config->true_out.c_str()); f << stringf(".names %s\n1\n", config->true_out);
else if (config->true_type != "-") else if (config->true_type != "-")
f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type), f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
config->true_type.c_str(), config->true_out.c_str()); config->true_type.c_str(), config->true_out.c_str());
@ -216,7 +216,7 @@ struct BlifDumper
f << stringf(".names $true\n1\n"); f << stringf(".names $true\n1\n");
if (!config->undef_type.empty()) { if (!config->undef_type.empty()) {
if (config->undef_type == "+") if (config->undef_type == "+")
f << stringf(".names %s\n", config->undef_out.c_str()); f << stringf(".names %s\n", config->undef_out);
else if (config->undef_type != "-") else if (config->undef_type != "-")
f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type), f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type),
config->undef_type.c_str(), config->undef_out.c_str()); config->undef_type.c_str(), config->undef_out.c_str());
@ -331,31 +331,31 @@ struct BlifDumper
} }
if (!config->icells_mode && cell->type == ID($_FF_)) { if (!config->icells_mode && cell->type == ID($_FF_)) {
f << stringf(".latch %s %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), f << stringf(".latch %s %s%s\n", str(cell->getPort(ID::D)), str(cell->getPort(ID::Q)),
str_init(cell->getPort(ID::Q)).c_str()); str_init(cell->getPort(ID::Q)).c_str());
goto internal_cell; goto internal_cell;
} }
if (!config->icells_mode && cell->type == ID($_DFF_N_)) { if (!config->icells_mode && cell->type == ID($_DFF_N_)) {
f << stringf(".latch %s %s fe %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), f << stringf(".latch %s %s fe %s%s\n", str(cell->getPort(ID::D)), str(cell->getPort(ID::Q)),
str(cell->getPort(ID::C)).c_str(), str_init(cell->getPort(ID::Q)).c_str()); str(cell->getPort(ID::C)).c_str(), str_init(cell->getPort(ID::Q)).c_str());
goto internal_cell; goto internal_cell;
} }
if (!config->icells_mode && cell->type == ID($_DFF_P_)) { if (!config->icells_mode && cell->type == ID($_DFF_P_)) {
f << stringf(".latch %s %s re %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), f << stringf(".latch %s %s re %s%s\n", str(cell->getPort(ID::D)), str(cell->getPort(ID::Q)),
str(cell->getPort(ID::C)).c_str(), str_init(cell->getPort(ID::Q)).c_str()); str(cell->getPort(ID::C)).c_str(), str_init(cell->getPort(ID::Q)).c_str());
goto internal_cell; goto internal_cell;
} }
if (!config->icells_mode && cell->type == ID($_DLATCH_N_)) { if (!config->icells_mode && cell->type == ID($_DLATCH_N_)) {
f << stringf(".latch %s %s al %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), f << stringf(".latch %s %s al %s%s\n", str(cell->getPort(ID::D)), str(cell->getPort(ID::Q)),
str(cell->getPort(ID::E)).c_str(), str_init(cell->getPort(ID::Q)).c_str()); str(cell->getPort(ID::E)).c_str(), str_init(cell->getPort(ID::Q)).c_str());
goto internal_cell; goto internal_cell;
} }
if (!config->icells_mode && cell->type == ID($_DLATCH_P_)) { if (!config->icells_mode && cell->type == ID($_DLATCH_P_)) {
f << stringf(".latch %s %s ah %s%s\n", str(cell->getPort(ID::D)).c_str(), str(cell->getPort(ID::Q)).c_str(), f << stringf(".latch %s %s ah %s%s\n", str(cell->getPort(ID::D)), str(cell->getPort(ID::Q)),
str(cell->getPort(ID::E)).c_str(), str_init(cell->getPort(ID::Q)).c_str()); str(cell->getPort(ID::E)).c_str(), str_init(cell->getPort(ID::Q)).c_str());
goto internal_cell; goto internal_cell;
} }
@ -366,10 +366,10 @@ struct BlifDumper
auto width = cell->parameters.at(ID::WIDTH).as_int(); auto width = cell->parameters.at(ID::WIDTH).as_int();
log_assert(inputs.size() == width); log_assert(inputs.size() == width);
for (int i = width-1; i >= 0; i--) for (int i = width-1; i >= 0; i--)
f << stringf(" %s", str(inputs.extract(i, 1)).c_str()); f << stringf(" %s", str(inputs.extract(i, 1)));
auto &output = cell->getPort(ID::Y); auto &output = cell->getPort(ID::Y);
log_assert(output.size() == 1); log_assert(output.size() == 1);
f << stringf(" %s", str(output).c_str()); f << stringf(" %s", str(output));
f << stringf("\n"); f << stringf("\n");
RTLIL::SigSpec mask = cell->parameters.at(ID::LUT); RTLIL::SigSpec mask = cell->parameters.at(ID::LUT);
for (int i = 0; i < (1 << width); i++) for (int i = 0; i < (1 << width); i++)
@ -392,10 +392,10 @@ struct BlifDumper
table.push_back(State::S0); table.push_back(State::S0);
log_assert(inputs.size() == width); log_assert(inputs.size() == width);
for (int i = 0; i < width; i++) for (int i = 0; i < width; i++)
f << stringf(" %s", str(inputs.extract(i, 1)).c_str()); f << stringf(" %s", str(inputs.extract(i, 1)));
auto &output = cell->getPort(ID::Y); auto &output = cell->getPort(ID::Y);
log_assert(output.size() == 1); log_assert(output.size() == 1);
f << stringf(" %s", str(output).c_str()); f << stringf(" %s", str(output));
f << stringf("\n"); f << stringf("\n");
for (int i = 0; i < depth; i++) { for (int i = 0; i < depth; i++) {
for (int j = 0; j < width; j++) { for (int j = 0; j < width; j++) {
@ -410,11 +410,11 @@ struct BlifDumper
goto internal_cell; goto internal_cell;
} }
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), str(cell->type).c_str()); f << stringf(".%s %s", subckt_or_gate(cell->type.str()), str(cell->type));
for (auto &conn : cell->connections()) for (auto &conn : cell->connections())
{ {
if (conn.second.size() == 1) { if (conn.second.size() == 1) {
f << stringf(" %s=%s", str(conn.first).c_str(), str(conn.second[0]).c_str()); f << stringf(" %s=%s", str(conn.first), str(conn.second[0]));
continue; continue;
} }
@ -423,11 +423,11 @@ struct BlifDumper
if (w == nullptr) { if (w == nullptr) {
for (int i = 0; i < GetSize(conn.second); i++) for (int i = 0; i < GetSize(conn.second); i++)
f << stringf(" %s[%d]=%s", str(conn.first).c_str(), i, str(conn.second[i]).c_str()); f << stringf(" %s[%d]=%s", str(conn.first), i, str(conn.second[i]));
} else { } else {
for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) { for (int i = 0; i < std::min(GetSize(conn.second), GetSize(w)); i++) {
SigBit sig(w, i); SigBit sig(w, i);
f << stringf(" %s[%d]=%s", str(conn.first).c_str(), sig.wire->upto ? f << stringf(" %s[%d]=%s", str(conn.first), sig.wire->upto ?
sig.wire->start_offset+sig.wire->width-sig.offset-1 : sig.wire->start_offset+sig.wire->width-sig.offset-1 :
sig.wire->start_offset+sig.offset, str(conn.second[i]).c_str()); sig.wire->start_offset+sig.offset, str(conn.second[i]).c_str());
} }
@ -436,7 +436,7 @@ struct BlifDumper
f << stringf("\n"); f << stringf("\n");
if (config->cname_mode) if (config->cname_mode)
f << stringf(".cname %s\n", str(cell->name).c_str()); f << stringf(".cname %s\n", str(cell->name));
if (config->attr_mode) if (config->attr_mode)
dump_params(".attr", cell->attributes); dump_params(".attr", cell->attributes);
if (config->param_mode) if (config->param_mode)
@ -445,7 +445,7 @@ struct BlifDumper
if (0) { if (0) {
internal_cell: internal_cell:
if (config->iname_mode) if (config->iname_mode)
f << stringf(".cname %s\n", str(cell->name).c_str()); f << stringf(".cname %s\n", str(cell->name));
if (config->iattr_mode) if (config->iattr_mode)
dump_params(".attr", cell->attributes); dump_params(".attr", cell->attributes);
} }
@ -461,12 +461,12 @@ struct BlifDumper
continue; continue;
if (config->conn_mode) if (config->conn_mode)
f << stringf(".conn %s %s\n", str(rhs_bit).c_str(), str(lhs_bit).c_str()); f << stringf(".conn %s %s\n", str(rhs_bit), str(lhs_bit));
else if (!config->buf_type.empty()) else if (!config->buf_type.empty())
f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type,
config->buf_in.c_str(), str(rhs_bit).c_str(), config->buf_out.c_str(), str(lhs_bit).c_str()); config->buf_in.c_str(), str(rhs_bit).c_str(), config->buf_out.c_str(), str(lhs_bit).c_str());
else else
f << stringf(".names %s %s\n1 1\n", str(rhs_bit).c_str(), str(lhs_bit).c_str()); f << stringf(".names %s %s\n1 1\n", str(rhs_bit), str(lhs_bit));
} }
f << stringf(".end\n"); f << stringf(".end\n");
@ -674,7 +674,7 @@ struct BlifBackend : public Backend {
} }
if (!top_module_name.empty()) if (!top_module_name.empty())
log_error("Can't find top module `%s'!\n", top_module_name.c_str()); log_error("Can't find top module `%s'!\n", top_module_name);
for (auto module : mod_list) for (auto module : mod_list)
BlifDumper::dump(*f, module, design, config); BlifDumper::dump(*f, module, design, config);

View file

@ -98,24 +98,22 @@ struct BtorWorker
vector<ywmap_btor_sig> ywmap_states; vector<ywmap_btor_sig> ywmap_states;
dict<SigBit, int> ywmap_clock_bits; dict<SigBit, int> ywmap_clock_bits;
dict<SigBit, int> ywmap_clock_inputs; dict<SigBit, int> ywmap_clock_inputs;
vector<Cell *> ywmap_asserts;
vector<Cell *> ywmap_assumes;
PrettyJson ywmap_json; PrettyJson ywmap_json;
void btorf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 2, 3)) template <typename... Args>
void btorf(FmtString<TypeIdentity<Args>...> fmt, const Args &... args)
{ {
va_list ap; f << indent << fmt.format(args...);
va_start(ap, fmt);
f << indent << vstringf(fmt, ap);
va_end(ap);
} }
void infof(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 2, 3)) template <typename... Args>
void infof(FmtString<TypeIdentity<Args>...> fmt, const Args &... args)
{ {
va_list ap; info_lines.push_back(fmt.format(args...));
va_start(ap, fmt);
info_lines.push_back(vstringf(fmt, ap));
va_end(ap);
} }
template<typename T> template<typename T>
@ -129,7 +127,7 @@ struct BtorWorker
std::replace(src.begin(), src.end(), ' ', '_'); std::replace(src.begin(), src.end(), ' ', '_');
if (srcsymbols.count(src) || module->count_id("\\" + src)) { if (srcsymbols.count(src) || module->count_id("\\" + src)) {
for (int i = 1;; i++) { for (int i = 1;; i++) {
string s = stringf("%s-%d", src.c_str(), i); string s = stringf("%s-%d", src, i);
if (!srcsymbols.count(s) && !module->count_id("\\" + s)) { if (!srcsymbols.count(s) && !module->count_id("\\" + s)) {
src = s; src = s;
break; break;
@ -192,7 +190,7 @@ struct BtorWorker
void btorf_push(const string &id) void btorf_push(const string &id)
{ {
if (verbose) { if (verbose) {
f << indent << stringf(" ; begin %s\n", id.c_str()); f << indent << stringf(" ; begin %s\n", id);
indent += " "; indent += " ";
} }
} }
@ -201,7 +199,7 @@ struct BtorWorker
{ {
if (verbose) { if (verbose) {
indent = indent.substr(4); indent = indent.substr(4);
f << indent << stringf(" ; end %s\n", id.c_str()); f << indent << stringf(" ; end %s\n", id);
} }
} }
@ -246,7 +244,7 @@ struct BtorWorker
string cell_list; string cell_list;
for (auto c : cell_recursion_guard) for (auto c : cell_recursion_guard)
cell_list += stringf("\n %s", log_id(c)); cell_list += stringf("\n %s", log_id(c));
log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list.c_str()); log_error("Found topological loop while processing cell %s. Active cells:%s\n", log_id(cell), cell_list);
} }
cell_recursion_guard.insert(cell); cell_recursion_guard.insert(cell);
@ -322,12 +320,12 @@ struct BtorWorker
btorf("%d slt %d %d %d\n", nid_b_ltz, sid_bit, nid_b, nid_zero); btorf("%d slt %d %d %d\n", nid_b_ltz, sid_bit, nid_b, nid_zero);
nid = next_nid++; nid = next_nid++;
btorf("%d ite %d %d %d %d%s\n", nid, sid, nid_b_ltz, nid_l, nid_r, getinfo(cell).c_str()); btorf("%d ite %d %d %d %d%s\n", nid, sid, nid_b_ltz, nid_l, nid_r, getinfo(cell));
} }
else else
{ {
nid = next_nid++; nid = next_nid++;
btorf("%d %s %d %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str()); btorf("%d %s %d %d %d%s\n", nid, btor_op, sid, nid_a, nid_b, getinfo(cell));
} }
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
@ -368,7 +366,7 @@ struct BtorWorker
int sid = get_bv_sid(width); int sid = get_bv_sid(width);
int nid = next_nid++; int nid = next_nid++;
btorf("%d %c%s %d %d %d%s\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str()); btorf("%d %c%s %d %d %d%s\n", nid, a_signed || b_signed ? 's' : 'u', btor_op, sid, nid_a, nid_b, getinfo(cell));
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
@ -394,12 +392,12 @@ struct BtorWorker
if (cell->type == ID($_ANDNOT_)) { if (cell->type == ID($_ANDNOT_)) {
btorf("%d not %d %d\n", nid1, sid, nid_b); btorf("%d not %d %d\n", nid1, sid, nid_b);
btorf("%d and %d %d %d%s\n", nid2, sid, nid_a, nid1, getinfo(cell).c_str()); btorf("%d and %d %d %d%s\n", nid2, sid, nid_a, nid1, getinfo(cell));
} }
if (cell->type == ID($_ORNOT_)) { if (cell->type == ID($_ORNOT_)) {
btorf("%d not %d %d\n", nid1, sid, nid_b); btorf("%d not %d %d\n", nid1, sid, nid_b);
btorf("%d or %d %d %d%s\n", nid2, sid, nid_a, nid1, getinfo(cell).c_str()); btorf("%d or %d %d %d%s\n", nid2, sid, nid_a, nid1, getinfo(cell));
} }
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
@ -421,13 +419,13 @@ struct BtorWorker
if (cell->type == ID($_OAI3_)) { if (cell->type == ID($_OAI3_)) {
btorf("%d or %d %d %d\n", nid1, sid, nid_a, nid_b); btorf("%d or %d %d %d\n", nid1, sid, nid_a, nid_b);
btorf("%d and %d %d %d\n", nid2, sid, nid1, nid_c); btorf("%d and %d %d %d\n", nid2, sid, nid1, nid_c);
btorf("%d not %d %d%s\n", nid3, sid, nid2, getinfo(cell).c_str()); btorf("%d not %d %d%s\n", nid3, sid, nid2, getinfo(cell));
} }
if (cell->type == ID($_AOI3_)) { if (cell->type == ID($_AOI3_)) {
btorf("%d and %d %d %d\n", nid1, sid, nid_a, nid_b); btorf("%d and %d %d %d\n", nid1, sid, nid_a, nid_b);
btorf("%d or %d %d %d\n", nid2, sid, nid1, nid_c); btorf("%d or %d %d %d\n", nid2, sid, nid1, nid_c);
btorf("%d not %d %d%s\n", nid3, sid, nid2, getinfo(cell).c_str()); btorf("%d not %d %d%s\n", nid3, sid, nid2, getinfo(cell));
} }
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
@ -452,14 +450,14 @@ struct BtorWorker
btorf("%d or %d %d %d\n", nid1, sid, nid_a, nid_b); btorf("%d or %d %d %d\n", nid1, sid, nid_a, nid_b);
btorf("%d or %d %d %d\n", nid2, sid, nid_c, nid_d); btorf("%d or %d %d %d\n", nid2, sid, nid_c, nid_d);
btorf("%d and %d %d %d\n", nid3, sid, nid1, nid2); btorf("%d and %d %d %d\n", nid3, sid, nid1, nid2);
btorf("%d not %d %d%s\n", nid4, sid, nid3, getinfo(cell).c_str()); btorf("%d not %d %d%s\n", nid4, sid, nid3, getinfo(cell));
} }
if (cell->type == ID($_AOI4_)) { if (cell->type == ID($_AOI4_)) {
btorf("%d and %d %d %d\n", nid1, sid, nid_a, nid_b); btorf("%d and %d %d %d\n", nid1, sid, nid_a, nid_b);
btorf("%d and %d %d %d\n", nid2, sid, nid_c, nid_d); btorf("%d and %d %d %d\n", nid2, sid, nid_c, nid_d);
btorf("%d or %d %d %d\n", nid3, sid, nid1, nid2); btorf("%d or %d %d %d\n", nid3, sid, nid1, nid2);
btorf("%d not %d %d%s\n", nid4, sid, nid3, getinfo(cell).c_str()); btorf("%d not %d %d%s\n", nid4, sid, nid3, getinfo(cell));
} }
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
@ -491,9 +489,9 @@ struct BtorWorker
int nid = next_nid++; int nid = next_nid++;
if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt))) { if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt))) {
btorf("%d %c%s %d %d %d%s\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str()); btorf("%d %c%s %d %d %d%s\n", nid, a_signed || b_signed ? 's' : 'u', btor_op, sid, nid_a, nid_b, getinfo(cell));
} else { } else {
btorf("%d %s %d %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str()); btorf("%d %s %d %d %d%s\n", nid, btor_op, sid, nid_a, nid_b, getinfo(cell));
} }
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
@ -509,7 +507,7 @@ struct BtorWorker
goto okay; goto okay;
} }
if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos))) if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos), ID($buf), ID($_BUF_)))
{ {
string btor_op; string btor_op;
if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not"; if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not";
@ -521,14 +519,14 @@ struct BtorWorker
int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed); int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
// the $pos cell just passes through, all other cells need an actual operation applied // the $pos/$buf cells just pass through, all other cells need an actual operation applied
int nid = nid_a; int nid = nid_a;
if (cell->type != ID($pos)) if (!cell->type.in(ID($pos), ID($buf), ID($_BUF_)))
{ {
log_assert(!btor_op.empty()); log_assert(!btor_op.empty());
int sid = get_bv_sid(width); int sid = get_bv_sid(width);
nid = next_nid++; nid = next_nid++;
btorf("%d %s %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, getinfo(cell).c_str()); btorf("%d %s %d %d%s\n", nid, btor_op, sid, nid_a, getinfo(cell));
} }
if (GetSize(sig) < width) { if (GetSize(sig) < width) {
@ -568,9 +566,9 @@ struct BtorWorker
int nid = next_nid++; int nid = next_nid++;
if (btor_op != "not") if (btor_op != "not")
btorf("%d %s %d %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str()); btorf("%d %s %d %d %d%s\n", nid, btor_op, sid, nid_a, nid_b, getinfo(cell));
else else
btorf("%d %s %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, getinfo(cell).c_str()); btorf("%d %s %d %d%s\n", nid, btor_op, sid, nid_a, getinfo(cell));
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
@ -601,11 +599,11 @@ struct BtorWorker
if (cell->type == ID($reduce_xnor)) { if (cell->type == ID($reduce_xnor)) {
int nid2 = next_nid++; int nid2 = next_nid++;
btorf("%d %s %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, getinfo(cell).c_str()); btorf("%d %s %d %d%s\n", nid, btor_op, sid, nid_a, getinfo(cell));
btorf("%d not %d %d\n", nid2, sid, nid); btorf("%d not %d %d\n", nid2, sid, nid);
nid = nid2; nid = nid2;
} else { } else {
btorf("%d %s %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, getinfo(cell).c_str()); btorf("%d %s %d %d%s\n", nid, btor_op, sid, nid_a, getinfo(cell));
} }
SigSpec sig = sigmap(cell->getPort(ID::Y)); SigSpec sig = sigmap(cell->getPort(ID::Y));
@ -640,9 +638,9 @@ struct BtorWorker
int tmp = nid; int tmp = nid;
nid = next_nid++; nid = next_nid++;
btorf("%d ite %d %d %d %d\n", tmp, sid, nid_s, nid_b, nid_a); btorf("%d ite %d %d %d %d\n", tmp, sid, nid_s, nid_b, nid_a);
btorf("%d not %d %d%s\n", nid, sid, tmp, getinfo(cell).c_str()); btorf("%d not %d %d%s\n", nid, sid, tmp, getinfo(cell));
} else { } else {
btorf("%d ite %d %d %d %d%s\n", nid, sid, nid_s, nid_b, nid_a, getinfo(cell).c_str()); btorf("%d ite %d %d %d %d%s\n", nid, sid, nid_s, nid_b, nid_a, getinfo(cell));
} }
add_nid_sig(nid, sig_y); add_nid_sig(nid, sig_y);
@ -665,7 +663,7 @@ struct BtorWorker
int nid_s = get_sig_nid(sig_s.extract(i)); int nid_s = get_sig_nid(sig_s.extract(i));
int nid2 = next_nid++; int nid2 = next_nid++;
if (i == GetSize(sig_s)-1) if (i == GetSize(sig_s)-1)
btorf("%d ite %d %d %d %d%s\n", nid2, sid, nid_s, nid_b, nid, getinfo(cell).c_str()); btorf("%d ite %d %d %d %d%s\n", nid2, sid, nid_s, nid_b, nid, getinfo(cell));
else else
btorf("%d ite %d %d %d %d\n", nid2, sid, nid_s, nid_b, nid); btorf("%d ite %d %d %d %d\n", nid2, sid, nid_s, nid_b, nid);
nid = nid2; nid = nid2;
@ -709,12 +707,13 @@ struct BtorWorker
} }
} }
Const initval; Const::Builder initval_bits(GetSize(sig_q));
for (int i = 0; i < GetSize(sig_q); i++) for (int i = 0; i < GetSize(sig_q); i++)
if (initbits.count(sig_q[i])) if (initbits.count(sig_q[i]))
initval.bits().push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0); initval_bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0);
else else
initval.bits().push_back(State::Sx); initval_bits.push_back(State::Sx);
Const initval = initval_bits.build();
int nid_init_val = -1; int nid_init_val = -1;
@ -753,7 +752,7 @@ struct BtorWorker
int sid = get_bv_sid(GetSize(sig_y)); int sid = get_bv_sid(GetSize(sig_y));
int nid = next_nid++; int nid = next_nid++;
btorf("%d state %d%s\n", nid, sid, getinfo(cell).c_str()); btorf("%d state %d%s\n", nid, sid, getinfo(cell));
ywmap_state(sig_y); ywmap_state(sig_y);
@ -776,7 +775,7 @@ struct BtorWorker
int one_nid = get_sig_nid(State::S1); int one_nid = get_sig_nid(State::S1);
int zero_nid = get_sig_nid(State::S0); int zero_nid = get_sig_nid(State::S0);
initstate_nid = next_nid++; initstate_nid = next_nid++;
btorf("%d state %d%s\n", initstate_nid, sid, getinfo(cell).c_str()); btorf("%d state %d%s\n", initstate_nid, sid, getinfo(cell));
btorf("%d init %d %d %d\n", next_nid++, sid, initstate_nid, one_nid); btorf("%d init %d %d %d\n", next_nid++, sid, initstate_nid, one_nid);
btorf("%d next %d %d %d\n", next_nid++, sid, initstate_nid, zero_nid); btorf("%d next %d %d %d\n", next_nid++, sid, initstate_nid, zero_nid);
@ -1043,15 +1042,16 @@ struct BtorWorker
{ {
if (bit.wire == nullptr) if (bit.wire == nullptr)
{ {
Const c(bit.data); Const::Builder c_bits;
c_bits.push_back(bit.data);
while (i+GetSize(c) < GetSize(sig) && sig[i+GetSize(c)].wire == nullptr) while (i + GetSize(c_bits) < GetSize(sig) && sig[i + GetSize(c_bits)].wire == nullptr)
c.bits().push_back(sig[i+GetSize(c)].data); c_bits.push_back(sig[i + GetSize(c_bits)].data);
Const c = c_bits.build();
if (consts.count(c) == 0) { if (consts.count(c) == 0) {
int sid = get_bv_sid(GetSize(c)); int sid = get_bv_sid(GetSize(c));
int nid = next_nid++; int nid = next_nid++;
btorf("%d const %d %s\n", nid, sid, c.as_string().c_str()); btorf("%d const %d %s\n", nid, sid, c.as_string());
consts[c] = nid; consts[c] = nid;
nid_width[nid] = GetSize(c); nid_width[nid] = GetSize(c);
} }
@ -1215,7 +1215,7 @@ struct BtorWorker
int sid = get_bv_sid(GetSize(sig)); int sid = get_bv_sid(GetSize(sig));
int nid = next_nid++; int nid = next_nid++;
btorf("%d input %d%s\n", nid, sid, getinfo(wire).c_str()); btorf("%d input %d%s\n", nid, sid, getinfo(wire));
ywmap_input(wire); ywmap_input(wire);
add_nid_sig(nid, sig); add_nid_sig(nid, sig);
@ -1260,7 +1260,7 @@ struct BtorWorker
btorf_push(stringf("output %s", log_id(wire))); btorf_push(stringf("output %s", log_id(wire)));
int nid = get_sig_nid(wire); int nid = get_sig_nid(wire);
btorf("%d output %d%s\n", next_nid++, nid, getinfo(wire).c_str()); btorf("%d output %d%s\n", next_nid++, nid, getinfo(wire));
btorf_pop(stringf("output %s", log_id(wire))); btorf_pop(stringf("output %s", log_id(wire)));
} }
@ -1282,6 +1282,8 @@ struct BtorWorker
btorf("%d or %d %d %d\n", nid_a_or_not_en, sid, nid_a, nid_not_en); btorf("%d or %d %d %d\n", nid_a_or_not_en, sid, nid_a, nid_not_en);
btorf("%d constraint %d\n", nid, nid_a_or_not_en); btorf("%d constraint %d\n", nid, nid_a_or_not_en);
if (ywmap_json.active()) ywmap_assumes.emplace_back(cell);
btorf_pop(log_id(cell)); btorf_pop(log_id(cell));
} }
@ -1302,10 +1304,12 @@ struct BtorWorker
bad_properties.push_back(nid_en_and_not_a); bad_properties.push_back(nid_en_and_not_a);
} else { } else {
if (cover_mode) { if (cover_mode) {
infof("bad %d%s\n", nid_en_and_not_a, getinfo(cell, true).c_str()); infof("bad %d%s\n", nid_en_and_not_a, getinfo(cell, true));
} else { } else {
int nid = next_nid++; int nid = next_nid++;
btorf("%d bad %d%s\n", nid, nid_en_and_not_a, getinfo(cell, true).c_str()); btorf("%d bad %d%s\n", nid, nid_en_and_not_a, getinfo(cell, true));
if (ywmap_json.active()) ywmap_asserts.emplace_back(cell);
} }
} }
@ -1327,7 +1331,7 @@ struct BtorWorker
bad_properties.push_back(nid_en_and_a); bad_properties.push_back(nid_en_and_a);
} else { } else {
int nid = next_nid++; int nid = next_nid++;
btorf("%d bad %d%s\n", nid, nid_en_and_a, getinfo(cell, true).c_str()); btorf("%d bad %d%s\n", nid, nid_en_and_a, getinfo(cell, true));
} }
btorf_pop(log_id(cell)); btorf_pop(log_id(cell));
@ -1348,7 +1352,7 @@ struct BtorWorker
continue; continue;
int this_nid = next_nid++; int this_nid = next_nid++;
btorf("%d uext %d %d %d%s\n", this_nid, sid, nid, 0, getinfo(wire).c_str()); btorf("%d uext %d %d %d%s\n", this_nid, sid, nid, 0, getinfo(wire));
if (info_clocks.count(nid)) if (info_clocks.count(nid))
info_clocks[this_nid] |= info_clocks[nid]; info_clocks[this_nid] |= info_clocks[nid];
@ -1371,7 +1375,7 @@ struct BtorWorker
SigSpec sig = sigmap(cell->getPort(ID::D)); SigSpec sig = sigmap(cell->getPort(ID::D));
int nid_q = get_sig_nid(sig); int nid_q = get_sig_nid(sig);
int sid = get_bv_sid(GetSize(sig)); int sid = get_bv_sid(GetSize(sig));
btorf("%d next %d %d %d%s\n", next_nid++, sid, nid, nid_q, getinfo(cell).c_str()); 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", log_id(cell)));
} }
@ -1430,7 +1434,7 @@ struct BtorWorker
} }
int nid2 = next_nid++; 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)).c_str()); 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", log_id(mem->memid)));
} }
@ -1463,6 +1467,7 @@ struct BtorWorker
log_assert(cursor == 0); log_assert(cursor == 0);
log_assert(GetSize(todo) == 1); log_assert(GetSize(todo) == 1);
btorf("%d bad %d\n", nid, todo[cursor]); btorf("%d bad %d\n", nid, todo[cursor]);
// What do we do with ywmap_asserts when using single_bad?
} }
} }
@ -1489,7 +1494,7 @@ struct BtorWorker
std::ofstream f; std::ofstream f;
f.open(info_filename.c_str(), std::ofstream::trunc); f.open(info_filename.c_str(), std::ofstream::trunc);
if (f.fail()) if (f.fail())
log_error("Can't open file `%s' for writing: %s\n", info_filename.c_str(), strerror(errno)); log_error("Can't open file `%s' for writing: %s\n", info_filename, strerror(errno));
for (auto &it : info_lines) for (auto &it : info_lines)
f << it; f << it;
f.close(); f.close();
@ -1528,6 +1533,18 @@ struct BtorWorker
emit_ywmap_btor_sig(entry); emit_ywmap_btor_sig(entry);
ywmap_json.end_array(); ywmap_json.end_array();
ywmap_json.name("asserts");
ywmap_json.begin_array();
for (Cell *cell : ywmap_asserts)
ywmap_json.value(witness_path(cell));
ywmap_json.end_array();
ywmap_json.name("assumes");
ywmap_json.begin_array();
for (Cell *cell : ywmap_assumes)
ywmap_json.value(witness_path(cell));
ywmap_json.end_array();
ywmap_json.end_object(); ywmap_json.end_object();
} }
} }

View file

@ -637,20 +637,6 @@ std::string escape_cxx_string(const std::string &input)
return output; return output;
} }
std::string basename(const std::string &filepath)
{
#ifdef _WIN32
const std::string dir_seps = "\\/";
#else
const std::string dir_seps = "/";
#endif
size_t sep_pos = filepath.find_last_of(dir_seps);
if (sep_pos != std::string::npos)
return filepath.substr(sep_pos + 1);
else
return filepath;
}
template<class T> template<class T>
std::string get_hdl_name(T *object) std::string get_hdl_name(T *object)
{ {
@ -1533,7 +1519,7 @@ struct CxxrtlWorker {
} }
// Internal cells // Internal cells
} else if (is_internal_cell(cell->type)) { } else if (is_internal_cell(cell->type)) {
log_cmd_error("Unsupported internal cell `%s'.\n", cell->type.c_str()); log_cmd_error("Unsupported internal cell `%s'.\n", cell->type);
// User cells // User cells
} else if (for_debug) { } else if (for_debug) {
// Outlines are called on demand when computing the value of a debug item. Nothing to do here. // Outlines are called on demand when computing the value of a debug item. Nothing to do here.
@ -1668,26 +1654,29 @@ struct CxxrtlWorker {
f << signal_temp << " == "; f << signal_temp << " == ";
dump_sigspec(compare, /*is_lhs=*/false, for_debug); dump_sigspec(compare, /*is_lhs=*/false, for_debug);
} else if (compare.is_fully_const()) { } else if (compare.is_fully_const()) {
RTLIL::Const compare_mask, compare_value; RTLIL::Const::Builder compare_mask_builder(compare.size());
RTLIL::Const::Builder compare_value_builder(compare.size());
for (auto bit : compare.as_const()) { for (auto bit : compare.as_const()) {
switch (bit) { switch (bit) {
case RTLIL::S0: case RTLIL::S0:
case RTLIL::S1: case RTLIL::S1:
compare_mask.bits().push_back(RTLIL::S1); compare_mask_builder.push_back(RTLIL::S1);
compare_value.bits().push_back(bit); compare_value_builder.push_back(bit);
break; break;
case RTLIL::Sx: case RTLIL::Sx:
case RTLIL::Sz: case RTLIL::Sz:
case RTLIL::Sa: case RTLIL::Sa:
compare_mask.bits().push_back(RTLIL::S0); compare_mask_builder.push_back(RTLIL::S0);
compare_value.bits().push_back(RTLIL::S0); compare_value_builder.push_back(RTLIL::S0);
break; break;
default: default:
log_assert(false); log_assert(false);
} }
} }
RTLIL::Const compare_mask = compare_mask_builder.build();
RTLIL::Const compare_value = compare_value_builder.build();
f << "and_uu<" << compare.size() << ">(" << signal_temp << ", "; f << "and_uu<" << compare.size() << ">(" << signal_temp << ", ";
dump_const(compare_mask); dump_const(compare_mask);
f << ") == "; f << ") == ";
@ -2429,8 +2418,6 @@ struct CxxrtlWorker {
inc_indent(); inc_indent();
for (auto wire : module->wires()) { for (auto wire : module->wires()) {
const auto &debug_wire_type = debug_wire_types[wire]; const auto &debug_wire_type = debug_wire_types[wire];
if (!wire->name.isPublic())
continue;
count_public_wires++; count_public_wires++;
switch (debug_wire_type.type) { switch (debug_wire_type.type) {
case WireType::BUFFERED: case WireType::BUFFERED:
@ -2438,6 +2425,9 @@ struct CxxrtlWorker {
// Member wire // Member wire
std::vector<std::string> flags; std::vector<std::string> flags;
if (!wire->name.isPublic())
flags.push_back("GENERATED");
if (wire->port_input && wire->port_output) if (wire->port_input && wire->port_output)
flags.push_back("INOUT"); flags.push_back("INOUT");
else if (wire->port_output) else if (wire->port_output)
@ -2854,7 +2844,7 @@ struct CxxrtlWorker {
} }
if (split_intf) if (split_intf)
f << "#include \"" << basename(intf_filename) << "\"\n"; f << "#include \"" << name_from_file_path(intf_filename) << "\"\n";
else else
f << "#include <cxxrtl/cxxrtl.h>\n"; f << "#include <cxxrtl/cxxrtl.h>\n";
f << "\n"; f << "\n";
@ -3041,7 +3031,7 @@ struct CxxrtlWorker {
if (init == RTLIL::Const()) { if (init == RTLIL::Const()) {
init = RTLIL::Const(State::Sx, GetSize(bit.wire)); init = RTLIL::Const(State::Sx, GetSize(bit.wire));
} }
init.bits()[bit.offset] = port.init_value[i]; init.set(bit.offset, port.init_value[i]);
} }
} }
} }
@ -3477,8 +3467,8 @@ struct CxxrtlWorker {
}; };
struct CxxrtlBackend : public Backend { struct CxxrtlBackend : public Backend {
static const int DEFAULT_OPT_LEVEL = 6; static constexpr int DEFAULT_OPT_LEVEL = 6;
static const int DEFAULT_DEBUG_LEVEL = 4; static constexpr int DEFAULT_DEBUG_LEVEL = 4;
CxxrtlBackend() : Backend("cxxrtl", "convert design to C++ RTL simulation") { } CxxrtlBackend() : Backend("cxxrtl", "convert design to C++ RTL simulation") { }
void help() override void help() override
@ -3799,7 +3789,7 @@ struct CxxrtlBackend : public Backend {
if (args[argidx] == "-print-output" && argidx+1 < args.size()) { if (args[argidx] == "-print-output" && argidx+1 < args.size()) {
worker.print_output = args[++argidx]; worker.print_output = args[++argidx];
if (!(worker.print_output == "std::cout" || worker.print_output == "std::cerr")) { if (!(worker.print_output == "std::cout" || worker.print_output == "std::cerr")) {
log_cmd_error("Invalid output stream \"%s\".\n", worker.print_output.c_str()); log_cmd_error("Invalid output stream \"%s\".\n", worker.print_output);
worker.print_output = "std::cout"; worker.print_output = "std::cout";
} }
continue; continue;

View file

@ -200,6 +200,10 @@ enum cxxrtl_flag {
// node, such as inputs and dangling wires. // node, such as inputs and dangling wires.
CXXRTL_UNDRIVEN = 1 << 4, CXXRTL_UNDRIVEN = 1 << 4,
// Generated correspond to netlist nodes that correspond to state with an internal name, that
// need to be saved, but wouldn't otherwise have a debug item generated.
CXXRTL_GENERATED = 1 << 5,
// More object flags may be added in the future, but the existing ones will never change. // More object flags may be added in the future, but the existing ones will never change.
}; };

View file

@ -1294,6 +1294,7 @@ struct debug_item : ::cxxrtl_object {
DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC, DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC,
DRIVEN_COMB = CXXRTL_DRIVEN_COMB, DRIVEN_COMB = CXXRTL_DRIVEN_COMB,
UNDRIVEN = CXXRTL_UNDRIVEN, UNDRIVEN = CXXRTL_UNDRIVEN,
GENERATED = CXXRTL_GENERATED,
}; };
debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {} debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {}

View file

@ -30,9 +30,9 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str() #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).c_str() #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).c_str() #define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false)
struct EdifNames struct EdifNames
{ {
@ -48,8 +48,8 @@ struct EdifNames
if (define) { if (define) {
std::string new_id = operator()(id, false); std::string new_id = operator()(id, false);
if (port_rename) if (port_rename)
return stringf("(rename %s \"%s%c%d:%d%c\")", new_id.c_str(), id.c_str(), delim_left, range_left, range_right, delim_right); return stringf("(rename %s \"%s%c%d:%d%c\")", new_id, id, delim_left, range_left, range_right, delim_right);
return new_id != id ? stringf("(rename %s \"%s\")", new_id.c_str(), id.c_str()) : id; return new_id != id ? stringf("(rename %s \"%s\")", new_id, id) : id;
} }
if (name_map.count(id) > 0) if (name_map.count(id) > 0)
@ -334,7 +334,7 @@ struct EdifBackend : public Backend {
auto add_prop = [&](IdString name, Const val) { auto add_prop = [&](IdString name, Const val) {
if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0)
*f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str()); *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string());
else if (val.size() <= 32 && RTLIL::SigSpec(val).is_fully_def()) else if (val.size() <= 32 && RTLIL::SigSpec(val).is_fully_def())
*f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int()); *f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
else { else {
@ -348,7 +348,7 @@ struct EdifBackend : public Backend {
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 }; char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
hex_string = std::string(digit_str) + hex_string; hex_string = std::string(digit_str) + hex_string;
} }
*f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val), hex_string.c_str()); *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val), hex_string);
} }
}; };
for (auto module : sorted_modules) for (auto module : sorted_modules)
@ -513,13 +513,13 @@ struct EdifBackend : public Backend {
if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) { if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) {
if (sig == RTLIL::State::Sx) { if (sig == RTLIL::State::Sx) {
for (auto &ref : it.second) for (auto &ref : it.second)
log_warning("Exporting x-bit on %s as zero bit.\n", ref.first.c_str()); log_warning("Exporting x-bit on %s as zero bit.\n", ref.first);
sig = RTLIL::State::S0; sig = RTLIL::State::S0;
} else if (sig == RTLIL::State::Sz) { } else if (sig == RTLIL::State::Sz) {
continue; continue;
} else { } else {
for (auto &ref : it.second) for (auto &ref : it.second)
log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.first.c_str()); log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.first);
log_abort(); log_abort();
} }
} }
@ -536,7 +536,7 @@ struct EdifBackend : public Backend {
} }
*f << stringf(" (net %s (joined\n", EDIF_DEF(netname)); *f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
for (auto &ref : it.second) for (auto &ref : it.second)
*f << stringf(" %s\n", ref.first.c_str()); *f << stringf(" %s\n", ref.first);
if (sig.wire == NULL) { if (sig.wire == NULL) {
if (nogndvcc) if (nogndvcc)
log_error("Design contains constant nodes (map with \"hilomap\" first).\n"); log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
@ -577,7 +577,7 @@ struct EdifBackend : public Backend {
auto &refs = net_join_db.at(mapped_sig); auto &refs = net_join_db.at(mapped_sig);
for (auto &ref : refs) for (auto &ref : refs)
if (ref.second) if (ref.second)
*f << stringf(" %s\n", ref.first.c_str()); *f << stringf(" %s\n", ref.first);
*f << stringf(" )"); *f << stringf(" )");
if (attr_properties && raw_sig.wire != NULL) if (attr_properties && raw_sig.wire != NULL)

View file

@ -253,7 +253,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
const std::string extmoduleFileinfo = getFileinfo(cell); const std::string extmoduleFileinfo = getFileinfo(cell);
// Emit extmodule header. // Emit extmodule header.
f << stringf(" extmodule %s: %s\n", exported_name.c_str(), extmoduleFileinfo.c_str()); f << stringf(" extmodule %s: %s\n", exported_name, extmoduleFileinfo);
// Emit extmodule ports. // Emit extmodule ports.
for (auto wire : mod_instance->wires()) for (auto wire : mod_instance->wires())
@ -280,7 +280,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
// Emit extmodule "defname" field. This is the name of the verilog blackbox // Emit extmodule "defname" field. This is the name of the verilog blackbox
// that is used when verilog is emitted, so we use the name of mod_instance // that is used when verilog is emitted, so we use the name of mod_instance
// here. // here.
f << stringf("%sdefname = %s\n", indent.c_str(), blackbox_name.c_str()); f << stringf("%sdefname = %s\n", indent, blackbox_name);
// Emit extmodule generic parameters. // Emit extmodule generic parameters.
for (const auto &p : cell->parameters) for (const auto &p : cell->parameters)
@ -301,7 +301,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream
param_name.end() param_name.end()
); );
f << stringf("%sparameter %s = %s\n", indent.c_str(), param_name.c_str(), param_value.c_str()); f << stringf("%sparameter %s = %s\n", indent, param_name, param_value);
} }
f << "\n"; f << "\n";
@ -347,7 +347,7 @@ void emit_elaborated_extmodules(RTLIL::Design *design, std::ostream &f)
auto modInstance = design->module(cell->type); auto modInstance = design->module(cell->type);
// Ensure that we actually have a module instance // Ensure that we actually have a module instance
if (modInstance == nullptr) { if (modInstance == nullptr) {
log_error("Unknown cell type %s\n", cell->type.c_str()); log_error("Unknown cell type %s\n", cell->type);
return; return;
} }
@ -417,7 +417,7 @@ struct FirrtlWorker
else else
{ {
string wire_id = make_id(chunk.wire->name); string wire_id = make_id(chunk.wire->name);
new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset); new_expr = stringf("bits(%s, %d, %d)", wire_id, chunk.offset + chunk.width - 1, chunk.offset);
} }
if (expr.empty()) if (expr.empty())
@ -465,7 +465,7 @@ struct FirrtlWorker
// If there is no instance for this, just return. // If there is no instance for this, just return.
if (instModule == NULL) if (instModule == NULL)
{ {
log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str()); log_warning("No instance for %s.%s\n", cell_type, cell_name);
return; return;
} }
@ -477,7 +477,7 @@ struct FirrtlWorker
instanceOf; instanceOf;
std::string cellFileinfo = getFileinfo(cell); std::string cellFileinfo = getFileinfo(cell);
wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceName.c_str(), cellFileinfo.c_str())); wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent, cell_name, cell_name_comment, instanceName, cellFileinfo));
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->second.size() > 0) { if (it->second.size() > 0) {
@ -490,7 +490,7 @@ struct FirrtlWorker
const SigSpec *sinkSig = nullptr; const SigSpec *sinkSig = nullptr;
switch (dir) { switch (dir) {
case FD_INOUT: case FD_INOUT:
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type, log_signal(it->second));
YS_FALLTHROUGH YS_FALLTHROUGH
case FD_OUT: case FD_OUT:
sourceExpr = firstName; sourceExpr = firstName;
@ -498,27 +498,27 @@ struct FirrtlWorker
sinkSig = &secondSig; sinkSig = &secondSig;
break; break;
case FD_NODIRECTION: case FD_NODIRECTION:
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type, log_signal(it->second));
YS_FALLTHROUGH YS_FALLTHROUGH
case FD_IN: case FD_IN:
sourceExpr = secondExpr; sourceExpr = secondExpr;
sinkExpr = firstName; sinkExpr = firstName;
break; break;
default: default:
log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir); log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type, log_signal(it->second), dir);
break; break;
} }
// Check for subfield assignment. // Check for subfield assignment.
std::string bitsString = "bits("; std::string bitsString = "bits(";
if (sinkExpr.compare(0, bitsString.length(), bitsString) == 0) { if (sinkExpr.compare(0, bitsString.length(), bitsString) == 0) {
if (sinkSig == nullptr) if (sinkSig == nullptr)
log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str()); log_error("Unknown subfield %s.%s\n", cell_type, sinkExpr);
// Don't generate the assignment here. // Don't generate the assignment here.
// Add the source and sink to the "reverse_wire_map" and we'll output the assignment // Add the source and sink to the "reverse_wire_map" and we'll output the assignment
// as part of the coalesced subfield assignments for this wire. // as part of the coalesced subfield assignments for this wire.
register_reverse_wire_map(sourceExpr, *sinkSig); register_reverse_wire_map(sourceExpr, *sinkSig);
} else { } else {
wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.c_str())); wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent, sinkExpr, sourceExpr, cellFileinfo));
} }
} }
} }
@ -535,7 +535,7 @@ struct FirrtlWorker
int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1); string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
// Deal with the difference in semantics between FIRRTL and verilog // Deal with the difference in semantics between FIRRTL and verilog
result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1); result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr, max_shift_string, max_shift_string, b_expr, max_shift_width_bits - 1);
} }
return result; return result;
} }
@ -543,7 +543,7 @@ struct FirrtlWorker
void emit_module() void emit_module()
{ {
std::string moduleFileinfo = getFileinfo(module); std::string moduleFileinfo = getFileinfo(module);
f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str()); f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo);
vector<string> port_decls, wire_decls, mem_exprs, cell_exprs, wire_exprs; vector<string> port_decls, wire_decls, mem_exprs, cell_exprs, wire_exprs;
std::vector<Mem> memories = Mem::get_all_memories(module); std::vector<Mem> memories = Mem::get_all_memories(module);
@ -565,12 +565,12 @@ struct FirrtlWorker
{ {
if (wire->port_input && wire->port_output) 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", log_id(module), log_id(wire));
port_decls.push_back(stringf("%s%s %s: UInt<%d> %s\n", indent.c_str(), wire->port_input ? "input" : "output", port_decls.push_back(stringf("%s%s %s: UInt<%d> %s\n", indent, wire->port_input ? "input" : "output",
wireName, wire->width, wireFileinfo.c_str())); wireName, wire->width, wireFileinfo.c_str()));
} }
else else
{ {
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), wireName, wire->width, wireFileinfo.c_str())); wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, wireName, wire->width, wireFileinfo));
} }
} }
@ -602,7 +602,7 @@ struct FirrtlWorker
if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor))) if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor)))
{ {
string a_expr = make_expr(cell->getPort(ID::A)); string a_expr = make_expr(cell->getPort(ID::A));
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str())); wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo));
if (a_signed) { if (a_signed) {
a_expr = "asSInt(" + a_expr + ")"; a_expr = "asSInt(" + a_expr + ")";
@ -610,7 +610,7 @@ struct FirrtlWorker
// Don't use the results of logical operations (a single bit) to control padding // Don't use the results of logical operations (a single bit) to control padding
if (!(cell->type.in(ID($eq), ID($eqx), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($reduce_bool), ID($logic_not)) && y_width == 1) ) { if (!(cell->type.in(ID($eq), ID($eqx), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($reduce_bool), ID($logic_not)) && y_width == 1) ) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); a_expr = stringf("pad(%s, %d)", a_expr, y_width);
} }
// Assume the FIRRTL width is a single bit. // Assume the FIRRTL width is a single bit.
@ -622,27 +622,27 @@ struct FirrtlWorker
firrtl_width = a_width; firrtl_width = a_width;
} else if (cell->type == ID($logic_not)) { } else if (cell->type == ID($logic_not)) {
primop = "eq"; primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str()); a_expr = stringf("%s, UInt(0)", a_expr);
} }
else if (cell->type == ID($reduce_and)) primop = "andr"; else if (cell->type == ID($reduce_and)) primop = "andr";
else if (cell->type == ID($reduce_or)) primop = "orr"; else if (cell->type == ID($reduce_or)) primop = "orr";
else if (cell->type == ID($reduce_xor)) primop = "xorr"; else if (cell->type == ID($reduce_xor)) primop = "xorr";
else if (cell->type == ID($reduce_xnor)) { else if (cell->type == ID($reduce_xnor)) {
primop = "not"; primop = "not";
a_expr = stringf("xorr(%s)", a_expr.c_str()); a_expr = stringf("xorr(%s)", a_expr);
} }
else if (cell->type == ID($reduce_bool)) { else if (cell->type == ID($reduce_bool)) {
primop = "neq"; primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width); a_expr = stringf("%s, %cInt<%d>(0)", a_expr, a_signed ? 'S' : 'U', a_width);
} }
string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str()); string expr = stringf("%s(%s)", primop, a_expr);
if ((firrtl_is_signed && !always_uint)) if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str()); expr = stringf("asUInt(%s)", expr);
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
register_reverse_wire_map(y_id, cell->getPort(ID::Y)); register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue; continue;
@ -654,13 +654,13 @@ struct FirrtlWorker
string a_expr = make_expr(cell->getPort(ID::A)); string a_expr = make_expr(cell->getPort(ID::A));
string b_expr = make_expr(cell->getPort(ID::B)); string b_expr = make_expr(cell->getPort(ID::B));
std::string cellFileinfo = getFileinfo(cell); std::string cellFileinfo = getFileinfo(cell);
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str())); wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo));
if (a_signed) { if (a_signed) {
a_expr = "asSInt(" + a_expr + ")"; a_expr = "asSInt(" + a_expr + ")";
// Expand the "A" operand to the result width // Expand the "A" operand to the result width
if (a_width < y_width) { if (a_width < y_width) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); a_expr = stringf("pad(%s, %d)", a_expr, y_width);
a_width = y_width; a_width = y_width;
} }
} }
@ -670,7 +670,7 @@ struct FirrtlWorker
b_expr = "asSInt(" + b_expr + ")"; b_expr = "asSInt(" + b_expr + ")";
// Expand the "B" operand to the result width // Expand the "B" operand to the result width
if (b_width < y_width) { if (b_width < y_width) {
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); b_expr = stringf("pad(%s, %d)", b_expr, y_width);
b_width = y_width; b_width = y_width;
} }
} }
@ -680,11 +680,11 @@ struct FirrtlWorker
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_))) if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_)))
{ {
if (a_width < y_width) { if (a_width < y_width) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); a_expr = stringf("pad(%s, %d)", a_expr, y_width);
a_width = y_width; a_width = y_width;
} }
if (b_width < y_width) { if (b_width < y_width) {
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); b_expr = stringf("pad(%s, %d)", b_expr, y_width);
b_width = y_width; b_width = y_width;
} }
} }
@ -856,23 +856,23 @@ struct FirrtlWorker
string expr; string expr;
// Deal with $xnor == ~^ (not xor) // Deal with $xnor == ~^ (not xor)
if (primop == "xnor") { if (primop == "xnor") {
expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str()); expr = stringf("not(xor(%s, %s))", a_expr, b_expr);
} else { } else {
expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); expr = stringf("%s(%s, %s)", primop, a_expr, b_expr);
} }
// Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result. // Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result.
// If the operation is signed, the FIRRTL width will be 1 one bit larger. // If the operation is signed, the FIRRTL width will be 1 one bit larger.
if (extract_y_bits) { if (extract_y_bits) {
expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); expr = stringf("bits(%s, %d, 0)", expr, y_width - 1);
} else if (firrtl_is_signed && (firrtl_width + 1) < y_width) { } else if (firrtl_is_signed && (firrtl_width + 1) < y_width) {
expr = stringf("pad(%s, %d)", expr.c_str(), y_width); expr = stringf("pad(%s, %d)", expr, y_width);
} }
if ((firrtl_is_signed && !always_uint)) if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str()); expr = stringf("asUInt(%s)", expr);
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
register_reverse_wire_map(y_id, cell->getPort(ID::Y)); register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue; continue;
@ -885,11 +885,11 @@ struct FirrtlWorker
string a_expr = make_expr(cell->getPort(ID::A)); string a_expr = make_expr(cell->getPort(ID::A));
string b_expr = make_expr(cell->getPort(ID::B)); string b_expr = make_expr(cell->getPort(ID::B));
string s_expr = make_expr(cell->getPort(ID::S)); string s_expr = make_expr(cell->getPort(ID::S));
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), width, cellFileinfo.c_str())); wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, width, cellFileinfo));
string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str()); string expr = stringf("mux(%s, %s, %s)", s_expr, b_expr, a_expr);
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
register_reverse_wire_map(y_id, cell->getPort(ID::Y)); register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue; continue;
@ -911,9 +911,9 @@ struct FirrtlWorker
string expr = make_expr(cell->getPort(ID::D)); string expr = make_expr(cell->getPort(ID::D));
string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")"; string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")";
wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent.c_str(), y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str())); wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent, y_id, width, clk_expr, cellFileinfo));
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo));
register_reverse_wire_map(y_id, cell->getPort(ID::Q)); register_reverse_wire_map(y_id, cell->getPort(ID::Q));
continue; continue;
@ -926,7 +926,7 @@ struct FirrtlWorker
string a_expr = make_expr(cell->getPort(ID::A)); string a_expr = make_expr(cell->getPort(ID::A));
// Get the initial bit selector // Get the initial bit selector
string b_expr = make_expr(cell->getPort(ID::B)); string b_expr = make_expr(cell->getPort(ID::B));
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent, y_id, y_width));
if (cell->getParam(ID::B_SIGNED).as_bool()) { if (cell->getParam(ID::B_SIGNED).as_bool()) {
// Use validif to constrain the selection (test the sign bit) // Use validif to constrain the selection (test the sign bit)
@ -934,9 +934,9 @@ struct FirrtlWorker
int b_sign = cell->parameters.at(ID::B_WIDTH).as_int() - 1; int b_sign = cell->parameters.at(ID::B_WIDTH).as_int() - 1;
b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string); b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
} }
string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str()); string expr = stringf("dshr(%s, %s)", a_expr, b_expr);
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str())); cell_exprs.push_back(stringf("%s%s <= %s\n", indent, y_id, expr));
register_reverse_wire_map(y_id, cell->getPort(ID::Y)); register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue; continue;
} }
@ -948,21 +948,21 @@ struct FirrtlWorker
string b_expr = make_expr(cell->getPort(ID::B)); string b_expr = make_expr(cell->getPort(ID::B));
auto b_string = b_expr.c_str(); auto b_string = b_expr.c_str();
string expr; string expr;
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent, y_id, y_width));
if (cell->getParam(ID::B_SIGNED).as_bool()) { if (cell->getParam(ID::B_SIGNED).as_bool()) {
// We generate a left or right shift based on the sign of b. // We generate a left or right shift based on the sign of b.
std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_width).c_str(), y_width); std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr, gen_dshl(b_expr, b_width), y_width);
std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); std::string dshr = stringf("dshr(%s, %s)", a_expr, b_string);
expr = stringf("mux(%s < 0, %s, %s)", expr = stringf("mux(%s < 0, %s, %s)",
b_string, b_string,
dshl.c_str(), dshl.c_str(),
dshr.c_str() dshr.c_str()
); );
} else { } else {
expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); expr = stringf("dshr(%s, %s)", a_expr, b_string);
} }
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str())); cell_exprs.push_back(stringf("%s%s <= %s\n", indent, y_id, expr));
register_reverse_wire_map(y_id, cell->getPort(ID::Y)); register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue; continue;
} }
@ -973,10 +973,10 @@ struct FirrtlWorker
// Verilog appears to treat the result as signed, so if the result is wider than "A", // Verilog appears to treat the result as signed, so if the result is wider than "A",
// we need to pad. // we need to pad.
if (a_width < y_width) { if (a_width < y_width) {
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); a_expr = stringf("pad(%s, %d)", a_expr, y_width);
} }
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent, y_id, y_width));
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), a_expr.c_str())); cell_exprs.push_back(stringf("%s%s <= %s\n", indent, y_id, a_expr));
register_reverse_wire_map(y_id, cell->getPort(ID::Y)); register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue; continue;
} }
@ -999,7 +999,7 @@ struct FirrtlWorker
for (int i = 0; i < GetSize(mem.rd_ports); i++) for (int i = 0; i < GetSize(mem.rd_ports); i++)
{ {
auto &port = mem.rd_ports[i]; auto &port = mem.rd_ports[i];
string port_name(stringf("%s.r%d", mem_id.c_str(), i)); string port_name(stringf("%s.r%d", mem_id, i));
if (port.clk_enable) 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, log_id(module), log_id(mem.memid));
@ -1010,17 +1010,17 @@ struct FirrtlWorker
string ena_expr = make_expr(State::S1); string ena_expr = make_expr(State::S1);
string clk_expr = make_expr(State::S0); string clk_expr = make_expr(State::S0);
rpe << stringf("%s%s.addr <= %s\n", indent.c_str(), port_name.c_str(), addr_expr.c_str()); rpe << stringf("%s%s.addr <= %s\n", indent, port_name, addr_expr);
rpe << stringf("%s%s.en <= %s\n", indent.c_str(), port_name.c_str(), ena_expr.c_str()); rpe << stringf("%s%s.en <= %s\n", indent, port_name, ena_expr);
rpe << stringf("%s%s.clk <= asClock(%s)\n", indent.c_str(), port_name.c_str(), clk_expr.c_str()); rpe << stringf("%s%s.clk <= asClock(%s)\n", indent, port_name, clk_expr);
cell_exprs.push_back(rpe.str()); cell_exprs.push_back(rpe.str());
register_reverse_wire_map(stringf("%s.data", port_name.c_str()), port.data); register_reverse_wire_map(stringf("%s.data", port_name), port.data);
} }
for (int i = 0; i < GetSize(mem.wr_ports); i++) for (int i = 0; i < GetSize(mem.wr_ports); i++)
{ {
auto &port = mem.wr_ports[i]; auto &port = mem.wr_ports[i];
string port_name(stringf("%s.w%d", mem_id.c_str(), i)); string port_name(stringf("%s.w%d", mem_id, i));
if (!port.clk_enable) 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, log_id(module), log_id(mem.memid));
@ -1037,18 +1037,18 @@ struct FirrtlWorker
string ena_expr = make_expr(port.en[0]); string ena_expr = make_expr(port.en[0]);
string clk_expr = make_expr(port.clk); string clk_expr = make_expr(port.clk);
string mask_expr = make_expr(State::S1); string mask_expr = make_expr(State::S1);
wpe << stringf("%s%s.data <= %s\n", indent.c_str(), port_name.c_str(), data_expr.c_str()); wpe << stringf("%s%s.data <= %s\n", indent, port_name, data_expr);
wpe << stringf("%s%s.addr <= %s\n", indent.c_str(), port_name.c_str(), addr_expr.c_str()); wpe << stringf("%s%s.addr <= %s\n", indent, port_name, addr_expr);
wpe << stringf("%s%s.en <= %s\n", indent.c_str(), port_name.c_str(), ena_expr.c_str()); wpe << stringf("%s%s.en <= %s\n", indent, port_name, ena_expr);
wpe << stringf("%s%s.clk <= asClock(%s)\n", indent.c_str(), port_name.c_str(), clk_expr.c_str()); wpe << stringf("%s%s.clk <= asClock(%s)\n", indent, port_name, clk_expr);
wpe << stringf("%s%s.mask <= %s\n", indent.c_str(), port_name.c_str(), mask_expr.c_str()); wpe << stringf("%s%s.mask <= %s\n", indent, port_name, mask_expr);
cell_exprs.push_back(wpe.str()); cell_exprs.push_back(wpe.str());
} }
std::ostringstream me; std::ostringstream me;
me << stringf(" mem %s:\n", mem_id.c_str()); me << stringf(" mem %s:\n", mem_id);
me << stringf(" data-type => UInt<%d>\n", mem.width); me << stringf(" data-type => UInt<%d>\n", mem.width);
me << stringf(" depth => %d\n", mem.size); me << stringf(" depth => %d\n", mem.size);
for (int i = 0; i < GetSize(mem.rd_ports); i++) for (int i = 0; i < GetSize(mem.rd_ports); i++)
@ -1068,8 +1068,8 @@ struct FirrtlWorker
int y_width = GetSize(conn.first); int y_width = GetSize(conn.first);
string expr = make_expr(conn.second); string expr = make_expr(conn.second);
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent, y_id, y_width));
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str())); cell_exprs.push_back(stringf("%s%s <= %s\n", indent, y_id, expr));
register_reverse_wire_map(y_id, conn.first); register_reverse_wire_map(y_id, conn.first);
} }
@ -1112,7 +1112,7 @@ struct FirrtlWorker
chunk_width++; chunk_width++;
} }
new_expr = stringf("bits(%s, %d, %d)", start_map.first.c_str(), new_expr = stringf("bits(%s, %d, %d)", start_map.first,
start_map.second + chunk_width - 1, start_map.second); start_map.second + chunk_width - 1, start_map.second);
is_valid = true; is_valid = true;
} }
@ -1135,13 +1135,13 @@ struct FirrtlWorker
if (is_valid) { if (is_valid) {
if (make_unconn_id) { if (make_unconn_id) {
wire_decls.push_back(stringf("%swire %s: UInt<1> %s\n", indent.c_str(), unconn_id.c_str(), wireFileinfo.c_str())); wire_decls.push_back(stringf("%swire %s: UInt<1> %s\n", indent, unconn_id, wireFileinfo));
// `invalid` is a firrtl construction for simulation so we will not // `invalid` is a firrtl construction for simulation so we will not
// tag it with a @[fileinfo] tag as it doesn't directly correspond to // tag it with a @[fileinfo] tag as it doesn't directly correspond to
// a specific line of verilog code. // a specific line of verilog code.
wire_decls.push_back(stringf("%s%s is invalid\n", indent.c_str(), unconn_id.c_str())); wire_decls.push_back(stringf("%s%s is invalid\n", indent, unconn_id));
} }
wire_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), make_id(wire->name), expr.c_str(), wireFileinfo.c_str())); wire_exprs.push_back(stringf("%s%s <= %s %s\n", indent, make_id(wire->name), expr, wireFileinfo));
} else { } else {
if (make_unconn_id) { if (make_unconn_id) {
unconn_id.clear(); unconn_id.clear();
@ -1149,7 +1149,7 @@ struct FirrtlWorker
// `invalid` is a firrtl construction for simulation so we will not // `invalid` is a firrtl construction for simulation so we will not
// tag it with a @[fileinfo] tag as it doesn't directly correspond to // tag it with a @[fileinfo] tag as it doesn't directly correspond to
// a specific line of verilog code. // a specific line of verilog code.
wire_decls.push_back(stringf("%s%s is invalid\n", indent.c_str(), make_id(wire->name))); wire_decls.push_back(stringf("%s%s is invalid\n", indent, make_id(wire->name)));
} }
} }
@ -1223,6 +1223,7 @@ struct FirrtlBackend : public Backend {
Pass::call(design, "demuxmap"); Pass::call(design, "demuxmap");
Pass::call(design, "bwmuxmap"); Pass::call(design, "bwmuxmap");
used_names.clear();
namecache.clear(); namecache.clear();
autoid_counter = 0; autoid_counter = 0;
@ -1248,7 +1249,7 @@ struct FirrtlBackend : public Backend {
log_cmd_error("There is no top module in this design!\n"); log_cmd_error("There is no top module in this design!\n");
std::string circuitFileinfo = getFileinfo(top); std::string circuitFileinfo = getFileinfo(top);
*f << stringf("circuit %s: %s\n", make_id(top->name), circuitFileinfo.c_str()); *f << stringf("circuit %s: %s\n", make_id(top->name), circuitFileinfo);
emit_elaborated_extmodules(design, *f); emit_elaborated_extmodules(design, *f);
@ -1262,6 +1263,7 @@ struct FirrtlBackend : public Backend {
} }
} }
used_names.clear();
namecache.clear(); namecache.clear();
autoid_counter = 0; autoid_counter = 0;
} }

View file

@ -268,7 +268,7 @@ struct FunctionalCxxBackend : public Backend
extra_args(f, filename, args, argidx, design); extra_args(f, filename, args, argidx, design);
for (auto module : design->selected_modules()) { for (auto module : design->selected_modules()) {
log("Dumping module `%s'.\n", module->name.c_str()); log("Dumping module `%s'.\n", module->name);
printCxx(*f, filename, module); printCxx(*f, filename, module);
} }
} }

View file

@ -285,7 +285,7 @@ struct FunctionalSmtBackend : public Backend {
extra_args(f, filename, args, argidx, design); extra_args(f, filename, args, argidx, design);
for (auto module : design->selected_modules()) { for (auto module : design->selected_modules()) {
log("Processing module `%s`.\n", module->name.c_str()); log("Processing module `%s`.\n", module->name);
SmtModule smt(module); SmtModule smt(module);
smt.write(*f); smt.write(*f);
} }

View file

@ -19,8 +19,8 @@
*/ */
#include "kernel/functional.h" #include "kernel/functional.h"
#include "kernel/yosys.h"
#include "kernel/sexpr.h" #include "kernel/sexpr.h"
#include "kernel/yosys.h"
#include <ctype.h> #include <ctype.h>
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
@ -29,26 +29,24 @@ PRIVATE_NAMESPACE_BEGIN
using SExprUtil::list; using SExprUtil::list;
const char *reserved_keywords[] = { const char *reserved_keywords[] = {
// reserved keywords from the racket spec // reserved keywords from the racket spec
"struct", "lambda", "values", "extract", "concat", "bv", "let", "define", "cons", "list", "read", "write", "struct", "lambda", "values", "extract", "concat", "bv", "let", "define", "cons", "list", "read", "write", "stream", "error", "raise", "exit",
"stream", "error", "raise", "exit", "for", "begin", "when", "unless", "module", "require", "provide", "apply", "for", "begin", "when", "unless", "module", "require", "provide", "apply", "if", "cond", "even", "odd", "any", "and", "or", "match", "command-line",
"if", "cond", "even", "odd", "any", "and", "or", "match", "command-line", "ffi-lib", "thread", "kill", "sync", "ffi-lib", "thread", "kill", "sync", "future", "touch", "subprocess", "make-custodian", "custodian-shutdown-all", "current-custodian", "make",
"future", "touch", "subprocess", "make-custodian", "custodian-shutdown-all", "current-custodian", "make", "tcp", "tcp", "connect", "prepare", "malloc", "free", "_fun", "_cprocedure", "build", "path", "file", "peek", "bytes", "flush", "with", "lexer", "parser",
"connect", "prepare", "malloc", "free", "_fun", "_cprocedure", "build", "path", "file", "peek", "bytes", "syntax", "interface", "send", "make-object", "new", "instantiate", "define-generics", "set",
"flush", "with", "lexer", "parser", "syntax", "interface", "send", "make-object", "new", "instantiate",
"define-generics", "set",
// reserved for our own purposes // reserved for our own purposes
"inputs", "state", "name", "inputs", "state", "name", nullptr};
nullptr
};
struct SmtrScope : public Functional::Scope<int> { struct SmtrScope : public Functional::Scope<int> {
SmtrScope() { SmtrScope()
for(const char **p = reserved_keywords; *p != nullptr; p++) {
for (const char **p = reserved_keywords; *p != nullptr; p++)
reserve(*p); reserve(*p);
} }
bool is_character_legal(char c, int index) override { bool is_character_legal(char c, int index) override
{
return isascii(c) && (isalpha(c) || (isdigit(c) && index > 0) || strchr("@$%^&_+=.", c)); return isascii(c) && (isalpha(c) || (isdigit(c) && index > 0) || strchr("@$%^&_+=.", c));
} }
}; };
@ -56,10 +54,11 @@ struct SmtrScope : public Functional::Scope<int> {
struct SmtrSort { struct SmtrSort {
Functional::Sort sort; Functional::Sort sort;
SmtrSort(Functional::Sort sort) : sort(sort) {} SmtrSort(Functional::Sort sort) : sort(sort) {}
SExpr to_sexpr() const { SExpr to_sexpr() const
if(sort.is_memory()) { {
if (sort.is_memory()) {
return list("list", list("bitvector", sort.addr_width()), list("bitvector", sort.data_width())); return list("list", list("bitvector", sort.addr_width()), list("bitvector", sort.data_width()));
} else if(sort.is_signal()) { } else if (sort.is_signal()) {
return list("bitvector", sort.width()); return list("bitvector", sort.width());
} else { } else {
log_error("unknown sort"); log_error("unknown sort");
@ -67,7 +66,8 @@ struct SmtrSort {
} }
}; };
class SmtrStruct { class SmtrStruct
{
struct Field { struct Field {
SmtrSort sort; SmtrSort sort;
std::string accessor; std::string accessor;
@ -77,19 +77,22 @@ class SmtrStruct {
vector<Field> fields; vector<Field> fields;
SmtrScope &global_scope; SmtrScope &global_scope;
SmtrScope local_scope; SmtrScope local_scope;
public:
public:
std::string name; std::string name;
SmtrStruct(std::string name, SmtrScope &scope) : global_scope(scope), local_scope(), name(name) {} SmtrStruct(std::string name, SmtrScope &scope) : global_scope(scope), local_scope(), name(name) {}
void insert(IdString field_name, SmtrSort sort) { void insert(IdString field_name, SmtrSort sort)
{
field_names(field_name); field_names(field_name);
auto base_name = local_scope.unique_name(field_name); auto base_name = local_scope.unique_name(field_name);
auto accessor = name + "-" + base_name; auto accessor = name + "-" + base_name;
global_scope.reserve(accessor); global_scope.reserve(accessor);
fields.emplace_back(Field{sort, accessor, base_name}); fields.emplace_back(Field{sort, accessor, base_name});
} }
void write_definition(SExprWriter &w) { void write_definition(SExprWriter &w)
{
vector<SExpr> field_list; vector<SExpr> field_list;
for(const auto &field : fields) { for (const auto &field : fields) {
field_list.emplace_back(field.name); field_list.emplace_back(field.name);
} }
w.push(); w.push();
@ -102,23 +105,26 @@ public:
} }
w.pop(); w.pop();
} }
template<typename Fn> void write_value(SExprWriter &w, Fn fn) { template <typename Fn> void write_value(SExprWriter &w, Fn fn)
{
w.open(list(name)); w.open(list(name));
for(auto field_name : field_names) { for (auto field_name : field_names) {
w << fn(field_name); w << fn(field_name);
w.comment(RTLIL::unescape_id(field_name), true); w.comment(RTLIL::unescape_id(field_name), true);
} }
w.close(); w.close();
} }
SExpr access(SExpr record, IdString name) { SExpr access(SExpr record, IdString name)
{
size_t i = field_names.at(name); size_t i = field_names.at(name);
return list(fields[i].accessor, std::move(record)); return list(fields[i].accessor, std::move(record));
} }
}; };
std::string smt_const(RTLIL::Const const &c) { std::string smt_const(RTLIL::Const const &c)
{
std::string s = "#b"; std::string s = "#b";
for(int i = c.size(); i-- > 0; ) for (int i = c.size(); i-- > 0;)
s += c[i] == State::S1 ? '1' : '0'; s += c[i] == State::S1 ? '1' : '0';
return s; return s;
} }
@ -131,15 +137,9 @@ struct SmtrPrintVisitor : public Functional::AbstractVisitor<SExpr> {
SmtrPrintVisitor(SmtrStruct &input_struct, SmtrStruct &state_struct) : input_struct(input_struct), state_struct(state_struct) {} SmtrPrintVisitor(SmtrStruct &input_struct, SmtrStruct &state_struct) : input_struct(input_struct), state_struct(state_struct) {}
SExpr from_bool(SExpr &&arg) { SExpr from_bool(SExpr &&arg) { return list("bool->bitvector", std::move(arg)); }
return list("bool->bitvector", std::move(arg)); SExpr to_bool(SExpr &&arg) { return list("bitvector->bool", std::move(arg)); }
} SExpr to_list(SExpr &&arg) { return list("bitvector->bits", std::move(arg)); }
SExpr to_bool(SExpr &&arg) {
return list("bitvector->bool", std::move(arg));
}
SExpr to_list(SExpr &&arg) {
return list("bitvector->bits", std::move(arg));
}
SExpr buf(Node, Node a) override { return n(a); } SExpr buf(Node, Node a) override { return n(a); }
SExpr slice(Node, Node a, int offset, int out_width) override { return list("extract", offset + out_width - 1, offset, n(a)); } SExpr slice(Node, Node a, int offset, int out_width) override { return list("extract", offset + out_width - 1, offset, n(a)); }
@ -166,8 +166,9 @@ struct SmtrPrintVisitor : public Functional::AbstractVisitor<SExpr> {
SExpr unsigned_greater_than(Node, Node a, Node b) override { return from_bool(list("bvugt", n(a), n(b))); } SExpr unsigned_greater_than(Node, Node a, Node b) override { return from_bool(list("bvugt", n(a), n(b))); }
SExpr unsigned_greater_equal(Node, Node a, Node b) override { return from_bool(list("bvuge", n(a), n(b))); } SExpr unsigned_greater_equal(Node, Node a, Node b) override { return from_bool(list("bvuge", n(a), n(b))); }
SExpr extend(SExpr &&a, int in_width, int out_width) { SExpr extend(SExpr &&a, int in_width, int out_width)
if(in_width < out_width) {
if (in_width < out_width)
return list("zero-extend", std::move(a), list("bitvector", out_width)); return list("zero-extend", std::move(a), list("bitvector", out_width));
else else
return std::move(a); return std::move(a);
@ -176,12 +177,20 @@ struct SmtrPrintVisitor : public Functional::AbstractVisitor<SExpr> {
SExpr logical_shift_right(Node, Node a, Node b) override { return list("bvlshr", n(a), extend(n(b), b.width(), a.width())); } SExpr logical_shift_right(Node, Node a, Node b) override { return list("bvlshr", n(a), extend(n(b), b.width(), a.width())); }
SExpr arithmetic_shift_right(Node, Node a, Node b) override { return list("bvashr", n(a), extend(n(b), b.width(), a.width())); } SExpr arithmetic_shift_right(Node, Node a, Node b) override { return list("bvashr", n(a), extend(n(b), b.width(), a.width())); }
SExpr mux(Node, Node a, Node b, Node s) override { return list("if", to_bool(n(s)), n(b), n(a)); } SExpr mux(Node, Node a, Node b, Node s) override { return list("if", to_bool(n(s)), n(b), n(a)); }
SExpr constant(Node, RTLIL::Const const& value) override { return list("bv", smt_const(value), value.size()); } SExpr constant(Node, RTLIL::Const const &value) override { return list("bv", smt_const(value), value.size()); }
SExpr memory_read(Node, Node mem, Node addr) override { return list("list-ref-bv", n(mem), n(addr)); } SExpr memory_read(Node, Node mem, Node addr) override { return list("list-ref-bv", n(mem), n(addr)); }
SExpr memory_write(Node, Node mem, Node addr, Node data) override { return list("list-set-bv", n(mem), n(addr), n(data)); } SExpr memory_write(Node, Node mem, Node addr, Node data) override { return list("list-set-bv", n(mem), n(addr), n(data)); }
SExpr input(Node, IdString name, IdString kind) override { log_assert(kind == ID($input)); return input_struct.access("inputs", name); } SExpr input(Node, IdString name, IdString kind) override
SExpr state(Node, IdString name, IdString kind) override { log_assert(kind == ID($state)); return state_struct.access("state", name); } {
log_assert(kind == ID($input));
return input_struct.access("inputs", name);
}
SExpr state(Node, IdString name, IdString kind) override
{
log_assert(kind == ID($state));
return state_struct.access("state", name);
}
}; };
struct SmtrModule { struct SmtrModule {
@ -196,12 +205,10 @@ struct SmtrModule {
SmtrStruct state_struct; SmtrStruct state_struct;
SmtrModule(Module *module, bool assoc_list_helpers) SmtrModule(Module *module, bool assoc_list_helpers)
: ir(Functional::IR::from_module(module)) : ir(Functional::IR::from_module(module)), scope(), name(scope.unique_name(module->name)),
, scope() input_struct(scope.unique_name(module->name.str() + "_Inputs"), scope),
, name(scope.unique_name(module->name)) output_struct(scope.unique_name(module->name.str() + "_Outputs"), scope),
, input_struct(scope.unique_name(module->name.str() + "_Inputs"), scope) state_struct(scope.unique_name(module->name.str() + "_State"), scope)
, output_struct(scope.unique_name(module->name.str() + "_Outputs"), scope)
, state_struct(scope.unique_name(module->name.str() + "_State"), scope)
{ {
scope.reserve(name + "_initial"); scope.reserve(name + "_initial");
if (assoc_list_helpers) { if (assoc_list_helpers) {
@ -222,19 +229,17 @@ struct SmtrModule {
{ {
w.push(); w.push();
w.open(list("define", list(name, "inputs", "state"))); w.open(list("define", list(name, "inputs", "state")));
auto inlined = [&](Functional::Node n) { auto inlined = [&](Functional::Node n) { return n.fn() == Functional::Fn::constant; };
return n.fn() == Functional::Fn::constant;
};
SmtrPrintVisitor visitor(input_struct, state_struct); SmtrPrintVisitor visitor(input_struct, state_struct);
auto node_to_sexpr = [&](Functional::Node n) -> SExpr { auto node_to_sexpr = [&](Functional::Node n) -> SExpr {
if(inlined(n)) if (inlined(n))
return n.visit(visitor); return n.visit(visitor);
else else
return scope(n.id(), n.name()); return scope(n.id(), n.name());
}; };
visitor.n = node_to_sexpr; visitor.n = node_to_sexpr;
for(auto n : ir) for (auto n : ir)
if(!inlined(n)) { if (!inlined(n)) {
w.open(list("let", list(list(node_to_sexpr(n), n.visit(visitor)))), false); w.open(list("let", list(list(node_to_sexpr(n), n.visit(visitor)))), false);
w.comment(SmtrSort(n.sort()).to_sexpr().to_string(), true); w.comment(SmtrSort(n.sort()).to_sexpr().to_string(), true);
} }
@ -256,7 +261,7 @@ struct SmtrModule {
else if (state->sort.is_memory()) { else if (state->sort.is_memory()) {
const auto &contents = state->initial_value_memory(); const auto &contents = state->initial_value_memory();
w.open(list("list")); w.open(list("list"));
for(int i = 0; i < 1<<state->sort.addr_width(); i++) { for (int i = 0; i < 1 << state->sort.addr_width(); i++) {
w << list("bv", smt_const(contents[i]), state->sort.data_width()); w << list("bv", smt_const(contents[i]), state->sort.data_width());
} }
w.close(); w.close();
@ -303,7 +308,7 @@ struct SmtrModule {
} }
void write(std::ostream &out) void write(std::ostream &out)
{ {
SExprWriter w(out); SExprWriter w(out);
input_struct.write_definition(w); input_struct.write_definition(w);
@ -324,8 +329,9 @@ struct SmtrModule {
struct FunctionalSmtrBackend : public Backend { struct FunctionalSmtrBackend : public Backend {
FunctionalSmtrBackend() : Backend("functional_rosette", "Generate Rosette compatible Racket from Functional IR") {} FunctionalSmtrBackend() : Backend("functional_rosette", "Generate Rosette compatible Racket from Functional IR") {}
void help() override { void help() override
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n"); log("\n");
log(" write_functional_rosette [options] [filename]\n"); log(" write_functional_rosette [options] [filename]\n");
log("\n"); log("\n");
@ -347,8 +353,7 @@ struct FunctionalSmtrBackend : public Backend {
log_header(design, "Executing Functional Rosette Backend.\n"); log_header(design, "Executing Functional Rosette Backend.\n");
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++) {
{
if (args[argidx] == "-provides") if (args[argidx] == "-provides")
provides = true; provides = true;
else if (args[argidx] == "-assoc-list-helpers") else if (args[argidx] == "-assoc-list-helpers")

View file

@ -105,7 +105,7 @@ struct MemContentsTest {
RTLIL::Const values; RTLIL::Const values;
for(addr_t addr = low; addr <= high; addr++) { for(addr_t addr = low; addr <= high; addr++) {
RTLIL::Const word(data_dist(rnd), data_width); RTLIL::Const word(data_dist(rnd), data_width);
values.bits().insert(values.bits().end(), word.begin(), word.end()); values.append(word);
} }
insert_concatenated(low, values); insert_concatenated(low, values);
} }
@ -116,7 +116,9 @@ struct MemContentsTest {
struct FunctionalTestGeneric : public Pass struct FunctionalTestGeneric : public Pass
{ {
FunctionalTestGeneric() : Pass("test_generic", "test the generic compute graph") {} FunctionalTestGeneric() : Pass("test_generic", "test the generic compute graph") {
internal();
}
void help() override void help() override
{ {
@ -141,7 +143,7 @@ struct FunctionalTestGeneric : public Pass
*/ */
for (auto module : design->selected_modules()) { for (auto module : design->selected_modules()) {
log("Dumping module `%s'.\n", module->name.c_str()); log("Dumping module `%s'.\n", module->name);
auto fir = Functional::IR::from_module(module); auto fir = Functional::IR::from_module(module);
for(auto node : fir) 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 << RTLIL::unescape_id(node.name()) << " = " << node.to_string([](auto n) { return RTLIL::unescape_id(n.name()); }) << "\n";

View file

@ -100,13 +100,13 @@ struct IntersynthBackend : public Backend {
} }
extra_args(f, filename, args, argidx); extra_args(f, filename, args, argidx);
log("Output filename: %s\n", filename.c_str()); log("Output filename: %s\n", filename);
for (auto filename : libfiles) { for (auto filename : libfiles) {
std::ifstream f; std::ifstream f;
f.open(filename.c_str()); f.open(filename.c_str());
if (f.fail()) if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str()); log_error("Can't open lib file `%s'.\n", filename);
RTLIL::Design *lib = new RTLIL::Design; RTLIL::Design *lib = new RTLIL::Design;
Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : "verilog")); Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : "verilog"));
libs.push_back(lib); libs.push_back(lib);
@ -172,7 +172,7 @@ struct IntersynthBackend : public Backend {
if (sig.size() != 0) { if (sig.size() != 0) {
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size())); 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)); celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", log_id(port.first));
node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str()); node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig));
} }
} }
for (auto &param : cell->parameters) { for (auto &param : cell->parameters) {
@ -199,13 +199,13 @@ struct IntersynthBackend : public Backend {
if (!flag_notypes) { if (!flag_notypes) {
*f << stringf("### Connection Types\n"); *f << stringf("### Connection Types\n");
for (auto code : conntypes_code) for (auto code : conntypes_code)
*f << stringf("%s", code.c_str()); *f << stringf("%s", code);
*f << stringf("\n### Cell Types\n"); *f << stringf("\n### Cell Types\n");
for (auto code : celltypes_code) for (auto code : celltypes_code)
*f << stringf("%s", code.c_str()); *f << stringf("%s", code);
} }
*f << stringf("\n### Netlists\n"); *f << stringf("\n### Netlists\n");
*f << stringf("%s", netlists_code.c_str()); *f << stringf("%s", netlists_code);
for (auto lib : libs) for (auto lib : libs)
delete lib; delete lib;

View file

@ -125,7 +125,7 @@ struct JnyWriter
f << "{\n"; f << "{\n";
f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/main/misc/jny.schema.json\",\n"; f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/main/misc/jny.schema.json\",\n";
f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_maybe_version()).c_str()); f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_maybe_version()));
f << " \"version\": \"0.0.1\",\n"; f << " \"version\": \"0.0.1\",\n";
f << " \"invocation\": \"" << escape_string(invk) << "\",\n"; f << " \"invocation\": \"" << escape_string(invk) << "\",\n";
f << " \"features\": ["; f << " \"features\": [";
@ -232,7 +232,7 @@ struct JnyWriter
const auto _indent = gen_indent(indent_level); const auto _indent = gen_indent(indent_level);
f << _indent << "{\n"; f << _indent << "{\n";
f << stringf(" %s\"name\": \"%s\",\n", _indent.c_str(), escape_string(RTLIL::unescape_id(mod->name)).c_str()); f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(RTLIL::unescape_id(mod->name)));
f << _indent << " \"cell_sorts\": [\n"; f << _indent << " \"cell_sorts\": [\n";
bool first_sort{true}; bool first_sort{true};
@ -280,7 +280,7 @@ struct JnyWriter
f << ",\n"; f << ",\n";
f << _indent << " {\n"; f << _indent << " {\n";
f << stringf(" %s\"name\": \"%s\",\n", _indent.c_str(), escape_string(RTLIL::unescape_id(con.first)).c_str()); f << stringf(" %s\"name\": \"%s\",\n", _indent, escape_string(RTLIL::unescape_id(con.first)));
f << _indent << " \"direction\": \""; f << _indent << " \"direction\": \"";
if (port_cell->input(con.first)) if (port_cell->input(con.first))
f << "i"; f << "i";
@ -290,7 +290,7 @@ struct JnyWriter
if (con.second.size() == 1) if (con.second.size() == 1)
f << _indent << " \"range\": [0, 0]\n"; f << _indent << " \"range\": [0, 0]\n";
else else
f << stringf(" %s\"range\": [%d, %d]\n", _indent.c_str(), con.second.size(), 0); f << stringf(" %s\"range\": [%d, %d]\n", _indent, con.second.size(), 0);
f << _indent << " }"; f << _indent << " }";
first_port = false; first_port = false;
@ -304,7 +304,7 @@ struct JnyWriter
const auto _indent = gen_indent(indent_level); const auto _indent = gen_indent(indent_level);
f << _indent << "{\n"; f << _indent << "{\n";
f << stringf(" %s\"type\": \"%s\",\n", _indent.c_str(), sort.first.c_str()); f << stringf(" %s\"type\": \"%s\",\n", _indent, sort.first);
f << _indent << " \"ports\": [\n"; f << _indent << " \"ports\": [\n";
write_cell_ports(port_cell, indent_level + 2); write_cell_ports(port_cell, indent_level + 2);
@ -351,10 +351,10 @@ struct JnyWriter
f << stringf(",\n"); f << stringf(",\n");
const auto param_val = param.second; const auto param_val = param.second;
if (!param_val.empty()) { if (!param_val.empty()) {
f << stringf(" %s\"%s\": ", _indent.c_str(), escape_string(RTLIL::unescape_id(param.first)).c_str()); f << stringf(" %s\"%s\": ", _indent, escape_string(RTLIL::unescape_id(param.first)));
write_param_val(param_val); write_param_val(param_val);
} else { } else {
f << stringf(" %s\"%s\": true", _indent.c_str(), escape_string(RTLIL::unescape_id(param.first)).c_str()); f << stringf(" %s\"%s\": true", _indent, escape_string(RTLIL::unescape_id(param.first)));
} }
first_param = false; first_param = false;
@ -366,7 +366,7 @@ struct JnyWriter
log_assert(cell != nullptr); log_assert(cell != nullptr);
f << _indent << " {\n"; f << _indent << " {\n";
f << stringf(" %s\"name\": \"%s\"", _indent.c_str(), escape_string(RTLIL::unescape_id(cell->name)).c_str()); f << stringf(" %s\"name\": \"%s\"", _indent, escape_string(RTLIL::unescape_id(cell->name)));
if (_include_connections) { if (_include_connections) {
f << ",\n" << _indent << " \"connections\": [\n"; f << ",\n" << _indent << " \"connections\": [\n";
@ -553,7 +553,7 @@ struct JnyPass : public Pass {
ff->open(filename.c_str(), std::ofstream::trunc); ff->open(filename.c_str(), std::ofstream::trunc);
if (ff->fail()) { if (ff->fail()) {
delete ff; delete ff;
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); log_error("Can't open file `%s' for writing: %s\n", filename, strerror(errno));
} }
f = ff; f = ff;
invk << filename; invk << filename;
@ -568,7 +568,7 @@ struct JnyPass : public Pass {
if (!empty) { if (!empty) {
delete f; delete f;
} else { } else {
log("%s", buf.str().c_str()); log("%s", buf.str());
} }
} }

View file

@ -135,7 +135,7 @@ struct JsonWriter
bool first = true; bool first = true;
for (auto &param : parameters) { for (auto &param : parameters) {
f << stringf("%s\n", first ? "" : ","); f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str()); f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first));
write_parameter_value(param.second); write_parameter_value(param.second);
first = false; first = false;
} }
@ -155,7 +155,7 @@ struct JsonWriter
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", log_id(module));
} }
f << stringf(" %s: {\n", get_name(module->name).c_str()); f << stringf(" %s: {\n", get_name(module->name));
f << stringf(" \"attributes\": {"); f << stringf(" \"attributes\": {");
write_parameters(module->attributes, /*for_module=*/true); write_parameters(module->attributes, /*for_module=*/true);
@ -174,7 +174,7 @@ struct JsonWriter
if (use_selection && !module->selected(w)) if (use_selection && !module->selected(w))
continue; continue;
f << stringf("%s\n", first ? "" : ","); f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(n).c_str()); f << stringf(" %s: {\n", get_name(n));
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output"); f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
if (w->start_offset) if (w->start_offset)
f << stringf(" \"offset\": %d,\n", w->start_offset); f << stringf(" \"offset\": %d,\n", w->start_offset);
@ -182,7 +182,7 @@ struct JsonWriter
f << stringf(" \"upto\": 1,\n"); f << stringf(" \"upto\": 1,\n");
if (w->is_signed) if (w->is_signed)
f << stringf(" \"signed\": %d,\n", w->is_signed); f << stringf(" \"signed\": %d,\n", w->is_signed);
f << stringf(" \"bits\": %s\n", get_bits(w).c_str()); f << stringf(" \"bits\": %s\n", get_bits(w));
f << stringf(" }"); f << stringf(" }");
first = false; first = false;
} }
@ -196,13 +196,13 @@ struct JsonWriter
if (!scopeinfo_mode && c->type == ID($scopeinfo)) if (!scopeinfo_mode && c->type == ID($scopeinfo))
continue; continue;
f << stringf("%s\n", first ? "" : ","); f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(c->name).c_str()); f << stringf(" %s: {\n", get_name(c->name));
f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); f << stringf(" \"type\": %s,\n", get_name(c->type));
if (aig_mode) { if (aig_mode) {
Aig aig(c); Aig aig(c);
if (!aig.name.empty()) { if (!aig.name.empty()) {
f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); f << stringf(" \"model\": \"%s\",\n", aig.name);
aig_models.insert(aig); aig_models.insert(aig);
} }
} }
@ -220,7 +220,7 @@ struct JsonWriter
if (c->input(conn.first)) if (c->input(conn.first))
direction = c->output(conn.first) ? "inout" : "input"; direction = c->output(conn.first) ? "inout" : "input";
f << stringf("%s\n", first2 ? "" : ","); f << stringf("%s\n", first2 ? "" : ",");
f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); f << stringf(" %s: \"%s\"", get_name(conn.first), direction);
first2 = false; first2 = false;
} }
f << stringf("\n },\n"); f << stringf("\n },\n");
@ -229,7 +229,7 @@ struct JsonWriter
bool first2 = true; bool first2 = true;
for (auto &conn : c->connections()) { for (auto &conn : c->connections()) {
f << stringf("%s\n", first2 ? "" : ","); f << stringf("%s\n", first2 ? "" : ",");
f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str()); f << stringf(" %s: %s", get_name(conn.first), get_bits(conn.second));
first2 = false; first2 = false;
} }
f << stringf("\n }\n"); f << stringf("\n }\n");
@ -245,7 +245,7 @@ struct JsonWriter
if (use_selection && !module->selected(it.second)) if (use_selection && !module->selected(it.second))
continue; continue;
f << stringf("%s\n", first ? "" : ","); f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(it.second->name).c_str()); f << stringf(" %s: {\n", get_name(it.second->name));
f << stringf(" \"hide_name\": %s,\n", it.second->name[0] == '$' ? "1" : "0"); f << stringf(" \"hide_name\": %s,\n", it.second->name[0] == '$' ? "1" : "0");
f << stringf(" \"attributes\": {"); f << stringf(" \"attributes\": {");
write_parameters(it.second->attributes); write_parameters(it.second->attributes);
@ -265,9 +265,9 @@ struct JsonWriter
if (use_selection && !module->selected(w)) if (use_selection && !module->selected(w))
continue; continue;
f << stringf("%s\n", first ? "" : ","); f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(w->name).c_str()); f << stringf(" %s: {\n", get_name(w->name));
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); f << stringf(" \"bits\": %s,\n", get_bits(w));
if (w->start_offset) if (w->start_offset)
f << stringf(" \"offset\": %d,\n", w->start_offset); f << stringf(" \"offset\": %d,\n", w->start_offset);
if (w->upto) if (w->upto)
@ -291,7 +291,7 @@ struct JsonWriter
design->sort(); design->sort();
f << stringf("{\n"); f << stringf("{\n");
f << stringf(" \"creator\": %s,\n", get_string(yosys_maybe_version()).c_str()); f << stringf(" \"creator\": %s,\n", get_string(yosys_maybe_version()));
f << stringf(" \"modules\": {\n"); f << stringf(" \"modules\": {\n");
vector<Module*> modules = use_selection ? design->selected_modules() : design->modules(); vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
bool first_module = true; bool first_module = true;
@ -308,7 +308,7 @@ struct JsonWriter
for (auto &aig : aig_models) { for (auto &aig : aig_models) {
if (!first_model) if (!first_model)
f << stringf(",\n"); f << stringf(",\n");
f << stringf(" \"%s\": [\n", aig.name.c_str()); f << stringf(" \"%s\": [\n", aig.name);
int node_idx = 0; int node_idx = 0;
for (auto &node : aig.nodes) { for (auto &node : aig.nodes) {
if (node_idx != 0) if (node_idx != 0)
@ -701,7 +701,7 @@ struct JsonPass : public Pass {
ff->open(filename.c_str(), std::ofstream::trunc); ff->open(filename.c_str(), std::ofstream::trunc);
if (ff->fail()) { if (ff->fail()) {
delete ff; delete ff;
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); log_error("Can't open file `%s' for writing: %s\n", filename, strerror(errno));
} }
f = ff; f = ff;
} else { } else {
@ -714,7 +714,7 @@ struct JsonPass : public Pass {
if (!empty) { if (!empty) {
delete f; delete f;
} else { } else {
log("%s", buf.str().c_str()); log("%s", buf.str());
} }
} }
} JsonPass; } JsonPass;

View file

@ -24,12 +24,23 @@
#include "rtlil_backend.h" #include "rtlil_backend.h"
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/utils.h"
#include <errno.h> #include <errno.h>
#include <iterator>
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
using namespace RTLIL_BACKEND; using namespace RTLIL_BACKEND;
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
void RTLIL_BACKEND::dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj)
{
for (const auto& [name, value] : reversed(obj->attributes)) {
f << stringf("%s" "attribute %s ", indent, name);
dump_const(f, value);
f << stringf("\n");
}
}
void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint) void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
{ {
if (width < 0) if (width < 0)
@ -50,7 +61,9 @@ void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi
return; return;
} }
} }
f << stringf("%d'", width); if ((data.flags & RTLIL::CONST_FLAG_UNSIZED) == 0) {
f << stringf("%d'", width);
}
if (data.flags & RTLIL::CONST_FLAG_SIGNED) { if (data.flags & RTLIL::CONST_FLAG_SIGNED) {
f << stringf("s"); f << stringf("s");
} }
@ -96,11 +109,11 @@ void RTLIL_BACKEND::dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk,
dump_const(f, chunk.data, chunk.width, chunk.offset, autoint); dump_const(f, chunk.data, chunk.width, chunk.offset, autoint);
} else { } else {
if (chunk.width == chunk.wire->width && chunk.offset == 0) if (chunk.width == chunk.wire->width && chunk.offset == 0)
f << stringf("%s", chunk.wire->name.c_str()); f << stringf("%s", chunk.wire->name);
else if (chunk.width == 1) else if (chunk.width == 1)
f << stringf("%s [%d]", chunk.wire->name.c_str(), chunk.offset); f << stringf("%s [%d]", chunk.wire->name, chunk.offset);
else else
f << stringf("%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset); f << stringf("%s [%d:%d]", chunk.wire->name, chunk.offset+chunk.width-1, chunk.offset);
} }
} }
@ -110,8 +123,9 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
dump_sigchunk(f, sig.as_chunk(), autoint); dump_sigchunk(f, sig.as_chunk(), autoint);
} else { } else {
f << stringf("{ "); f << stringf("{ ");
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) { auto chunks = sig.chunks();
dump_sigchunk(f, *it, false); for (const auto& chunk : reversed(chunks)) {
dump_sigchunk(f, chunk, false);
f << stringf(" "); f << stringf(" ");
} }
f << stringf("}"); f << stringf("}");
@ -120,16 +134,12 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire) void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
{ {
for (auto &it : wire->attributes) { dump_attributes(f, indent, wire);
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
if (wire->driverCell_) { if (wire->driverCell_) {
f << stringf("%s" "# driver %s %s\n", indent.c_str(), f << stringf("%s" "# driver %s %s\n", indent,
wire->driverCell()->name.c_str(), wire->driverPort().c_str()); wire->driverCell()->name, wire->driverPort());
} }
f << stringf("%s" "wire ", indent.c_str()); f << stringf("%s" "wire ", indent);
if (wire->width != 1) if (wire->width != 1)
f << stringf("width %d ", wire->width); f << stringf("width %d ", wire->width);
if (wire->upto) if (wire->upto)
@ -144,101 +154,85 @@ void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::
f << stringf("inout %d ", wire->port_id); f << stringf("inout %d ", wire->port_id);
if (wire->is_signed) if (wire->is_signed)
f << stringf("signed "); f << stringf("signed ");
f << stringf("%s\n", wire->name.c_str()); f << stringf("%s\n", wire->name);
} }
void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory) void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
{ {
for (auto &it : memory->attributes) { dump_attributes(f, indent, memory);
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str()); f << stringf("%s" "memory ", indent);
dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "memory ", indent.c_str());
if (memory->width != 1) if (memory->width != 1)
f << stringf("width %d ", memory->width); f << stringf("width %d ", memory->width);
if (memory->size != 0) if (memory->size != 0)
f << stringf("size %d ", memory->size); f << stringf("size %d ", memory->size);
if (memory->start_offset != 0) if (memory->start_offset != 0)
f << stringf("offset %d ", memory->start_offset); f << stringf("offset %d ", memory->start_offset);
f << stringf("%s\n", memory->name.c_str()); f << stringf("%s\n", memory->name);
} }
void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell) void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
{ {
for (auto &it : cell->attributes) { dump_attributes(f, indent, cell);
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str()); f << stringf("%s" "cell %s %s\n", indent, cell->type, cell->name);
dump_const(f, it.second); for (const auto& [name, param] : reversed(cell->parameters)) {
f << stringf("%s parameter%s%s%s %s ", indent,
(param.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
(param.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
(param.flags & RTLIL::CONST_FLAG_UNSIZED) != 0 ? " unsized" : "",
name);
dump_const(f, param);
f << stringf("\n"); f << stringf("\n");
} }
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str()); for (const auto& [port, sig] : reversed(cell->connections_)) {
for (auto &it : cell->parameters) { f << stringf("%s connect %s ", indent, port);
f << stringf("%s parameter%s%s %s ", indent.c_str(), dump_sigspec(f, sig);
(it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
(it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
it.first.c_str());
dump_const(f, it.second);
f << stringf("\n"); f << stringf("\n");
} }
for (auto &it : cell->connections()) { f << stringf("%s" "end\n", indent);
f << stringf("%s connect %s ", indent.c_str(), it.first.c_str());
dump_sigspec(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "end\n", indent.c_str());
} }
void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs) void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
{ {
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) for (const auto& [lhs, rhs] : cs->actions) {
{ f << stringf("%s" "assign ", indent);
f << stringf("%s" "assign ", indent.c_str()); dump_sigspec(f, lhs);
dump_sigspec(f, it->first);
f << stringf(" "); f << stringf(" ");
dump_sigspec(f, it->second); dump_sigspec(f, rhs);
f << stringf("\n"); f << stringf("\n");
} }
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it) for (const auto& sw : cs->switches)
dump_proc_switch(f, indent, *it); dump_proc_switch(f, indent, sw);
} }
void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw) void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw)
{ {
for (auto it = sw->attributes.begin(); it != sw->attributes.end(); ++it) { dump_attributes(f, indent, sw);
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
f << stringf("%s" "switch ", indent.c_str()); f << stringf("%s" "switch ", indent);
dump_sigspec(f, sw->signal); dump_sigspec(f, sw->signal);
f << stringf("\n"); f << stringf("\n");
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) for (const auto case_ : sw->cases)
{ {
for (auto ait = (*it)->attributes.begin(); ait != (*it)->attributes.end(); ++ait) { dump_attributes(f, indent, case_);
f << stringf("%s attribute %s ", indent.c_str(), ait->first.c_str()); f << stringf("%s case ", indent);
dump_const(f, ait->second); for (size_t i = 0; i < case_->compare.size(); i++) {
f << stringf("\n");
}
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0) if (i > 0)
f << stringf(" , "); f << stringf(" , ");
dump_sigspec(f, (*it)->compare[i]); dump_sigspec(f, case_->compare[i]);
} }
f << stringf("\n"); f << stringf("\n");
dump_proc_case_body(f, indent + " ", *it); dump_proc_case_body(f, indent + " ", case_);
} }
f << stringf("%s" "end\n", indent.c_str()); f << stringf("%s" "end\n", indent);
} }
void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy) void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy)
{ {
f << stringf("%s" "sync ", indent.c_str()); f << stringf("%s" "sync ", indent);
switch (sy->type) { switch (sy->type) {
case RTLIL::ST0: f << stringf("low "); case RTLIL::ST0: f << stringf("low ");
if (0) case RTLIL::ST1: f << stringf("high "); if (0) case RTLIL::ST1: f << stringf("high ");
@ -253,21 +247,17 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
case RTLIL::STi: f << stringf("init\n"); break; case RTLIL::STi: f << stringf("init\n"); break;
} }
for (auto &it: sy->actions) { for (const auto& [lhs, rhs] : sy->actions) {
f << stringf("%s update ", indent.c_str()); f << stringf("%s update ", indent);
dump_sigspec(f, it.first); dump_sigspec(f, lhs);
f << stringf(" "); f << stringf(" ");
dump_sigspec(f, it.second); dump_sigspec(f, rhs);
f << stringf("\n"); f << stringf("\n");
} }
for (auto &it: sy->mem_write_actions) { for (auto &it: sy->mem_write_actions) {
for (auto it2 = it.attributes.begin(); it2 != it.attributes.end(); ++it2) { dump_attributes(f, indent, &it);
f << stringf("%s attribute %s ", indent.c_str(), it2->first.c_str()); f << stringf("%s memwr %s ", indent, it.memid);
dump_const(f, it2->second);
f << stringf("\n");
}
f << stringf("%s memwr %s ", indent.c_str(), it.memid.c_str());
dump_sigspec(f, it.address); dump_sigspec(f, it.address);
f << stringf(" "); f << stringf(" ");
dump_sigspec(f, it.data); dump_sigspec(f, it.data);
@ -281,21 +271,17 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
void RTLIL_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc) void RTLIL_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc)
{ {
for (auto it = proc->attributes.begin(); it != proc->attributes.end(); ++it) { dump_attributes(f, indent, proc);
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str()); f << stringf("%s" "process %s\n", indent, proc->name);
dump_const(f, it->second);
f << stringf("\n");
}
f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str());
dump_proc_case_body(f, indent + " ", &proc->root_case); dump_proc_case_body(f, indent + " ", &proc->root_case);
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it) for (auto* sync : proc->syncs)
dump_proc_sync(f, indent + " ", *it); dump_proc_sync(f, indent + " ", sync);
f << stringf("%s" "end\n", indent.c_str()); f << stringf("%s" "end\n", indent);
} }
void RTLIL_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) void RTLIL_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{ {
f << stringf("%s" "connect ", indent.c_str()); f << stringf("%s" "connect ", indent);
dump_sigspec(f, left); dump_sigspec(f, left);
f << stringf(" "); f << stringf(" ");
dump_sigspec(f, right); dump_sigspec(f, right);
@ -309,13 +295,9 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (print_header) if (print_header)
{ {
for (auto it = module->attributes.begin(); it != module->attributes.end(); ++it) { dump_attributes(f, indent, module);
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
f << stringf("%s" "module %s\n", indent.c_str(), module->name.c_str()); f << stringf("%s" "module %s\n", indent, module->name);
if (!module->avail_parameters.empty()) { if (!module->avail_parameters.empty()) {
if (only_selected) if (only_selected)
@ -323,9 +305,9 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
for (const auto &p : module->avail_parameters) { for (const auto &p : module->avail_parameters) {
const auto &it = module->parameter_default_values.find(p); const auto &it = module->parameter_default_values.find(p);
if (it == module->parameter_default_values.end()) { if (it == module->parameter_default_values.end()) {
f << stringf("%s" " parameter %s\n", indent.c_str(), p.c_str()); f << stringf("%s" " parameter %s\n", indent, p);
} else { } else {
f << stringf("%s" " parameter %s ", indent.c_str(), p.c_str()); f << stringf("%s" " parameter %s ", indent, p);
dump_const(f, it->second); dump_const(f, it->second);
f << stringf("\n"); f << stringf("\n");
} }
@ -335,40 +317,40 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (print_body) if (print_body)
{ {
for (auto it : module->wires()) for (const auto& [_, wire] : reversed(module->wires_))
if (!only_selected || design->selected(module, it)) { if (!only_selected || design->selected(module, wire)) {
if (only_selected) if (only_selected)
f << stringf("\n"); f << stringf("\n");
dump_wire(f, indent + " ", it); dump_wire(f, indent + " ", wire);
} }
for (auto it : module->memories) for (const auto& [_, mem] : reversed(module->memories))
if (!only_selected || design->selected(module, it.second)) { if (!only_selected || design->selected(module, mem)) {
if (only_selected) if (only_selected)
f << stringf("\n"); f << stringf("\n");
dump_memory(f, indent + " ", it.second); dump_memory(f, indent + " ", mem);
} }
for (auto it : module->cells()) for (const auto& [_, cell] : reversed(module->cells_))
if (!only_selected || design->selected(module, it)) { if (!only_selected || design->selected(module, cell)) {
if (only_selected) if (only_selected)
f << stringf("\n"); f << stringf("\n");
dump_cell(f, indent + " ", it); dump_cell(f, indent + " ", cell);
} }
for (auto it : module->processes) for (const auto& [_, process] : reversed(module->processes))
if (!only_selected || design->selected(module, it.second)) { if (!only_selected || design->selected(module, process)) {
if (only_selected) if (only_selected)
f << stringf("\n"); f << stringf("\n");
dump_proc(f, indent + " ", it.second); dump_proc(f, indent + " ", process);
} }
bool first_conn_line = true; bool first_conn_line = true;
for (auto it = module->connections().begin(); it != module->connections().end(); ++it) { for (const auto& [lhs, rhs] : module->connections()) {
bool show_conn = !only_selected || design->selected_whole_module(module->name); bool show_conn = !only_selected || design->selected_whole_module(module->name);
if (!show_conn) { if (!show_conn) {
RTLIL::SigSpec sigs = it->first; RTLIL::SigSpec sigs = lhs;
sigs.append(it->second); sigs.append(rhs);
for (auto &c : sigs.chunks()) { for (auto &c : sigs.chunks()) {
if (c.wire == NULL || !design->selected(module, c.wire)) if (c.wire == NULL || !design->selected(module, c.wire))
continue; continue;
@ -378,14 +360,14 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (show_conn) { if (show_conn) {
if (only_selected && first_conn_line) if (only_selected && first_conn_line)
f << stringf("\n"); f << stringf("\n");
dump_conn(f, indent + " ", it->first, it->second); dump_conn(f, indent + " ", lhs, rhs);
first_conn_line = false; first_conn_line = false;
} }
} }
} }
if (print_header) if (print_header)
f << stringf("%s" "end\n", indent.c_str()); f << stringf("%s" "end\n", indent);
} }
void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n) void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
@ -394,7 +376,7 @@ void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
if (!flag_m) { if (!flag_m) {
int count_selected_mods = 0; int count_selected_mods = 0;
for (auto module : design->modules()) { for (auto* module : design->modules()) {
if (design->selected_whole_module(module->name)) if (design->selected_whole_module(module->name))
flag_m = true; flag_m = true;
if (design->selected(module)) if (design->selected(module))
@ -410,7 +392,7 @@ void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
f << stringf("autoidx %d\n", autoidx); f << stringf("autoidx %d\n", autoidx);
} }
for (auto module : design->modules()) { for (const auto& [_, module] : reversed(design->modules_)) {
if (!only_selected || design->selected(module)) { if (!only_selected || design->selected(module)) {
if (only_selected) if (only_selected)
f << stringf("\n"); f << stringf("\n");
@ -438,10 +420,14 @@ struct RTLILBackend : public Backend {
log(" -selected\n"); log(" -selected\n");
log(" only write selected parts of the design.\n"); log(" only write selected parts of the design.\n");
log("\n"); log("\n");
log(" -sort\n");
log(" sort design in-place (used to be default).\n");
log("\n");
} }
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
{ {
bool selected = false; bool selected = false;
bool do_sort = false;
log_header(design, "Executing RTLIL backend.\n"); log_header(design, "Executing RTLIL backend.\n");
@ -452,13 +438,18 @@ struct RTLILBackend : public Backend {
selected = true; selected = true;
continue; continue;
} }
if (arg == "-sort") {
do_sort = true;
continue;
}
break; break;
} }
extra_args(f, filename, args, argidx); extra_args(f, filename, args, argidx);
design->sort(); log("Output filename: %s\n", filename);
log("Output filename: %s\n", filename.c_str()); if (do_sort)
design->sort();
*f << stringf("# Generated by %s\n", yosys_maybe_version()); *f << stringf("# Generated by %s\n", yosys_maybe_version());
RTLIL_BACKEND::dump_design(*f, design, selected, true, false); RTLIL_BACKEND::dump_design(*f, design, selected, true, false);
@ -528,10 +519,10 @@ struct DumpPass : public Pass {
if (!empty) { if (!empty) {
rewrite_filename(filename); rewrite_filename(filename);
std::ofstream *ff = new std::ofstream; std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc); ff->open(filename, append ? std::ofstream::app : std::ofstream::trunc);
if (ff->fail()) { if (ff->fail()) {
delete ff; delete ff;
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); log_error("Can't open file `%s' for writing: %s\n", filename, strerror(errno));
} }
f = ff; f = ff;
} else { } else {
@ -543,7 +534,7 @@ struct DumpPass : public Pass {
if (!empty) { if (!empty) {
delete f; delete f;
} else { } else {
log("%s", buf.str().c_str()); log("%s", buf.str());
} }
} }
} DumpPass; } DumpPass;

View file

@ -31,6 +31,7 @@
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
namespace RTLIL_BACKEND { namespace RTLIL_BACKEND {
void dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj);
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true); void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true);
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true); void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true);
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true); void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true);

View file

@ -218,8 +218,8 @@ struct SimplecWorker
s[i] -= 'a' - 'A'; s[i] -= 'a' - 'A';
util_declarations.push_back(""); util_declarations.push_back("");
util_declarations.push_back(stringf("#ifndef %s", s.c_str())); util_declarations.push_back(stringf("#ifndef %s", s));
util_declarations.push_back(stringf("#define %s", s.c_str())); util_declarations.push_back(stringf("#define %s", s));
} }
string util_get_bit(const string &signame, int n, int idx) string util_get_bit(const string &signame, int n, int idx)
@ -232,33 +232,33 @@ struct SimplecWorker
if (generated_utils.count(util_name) == 0) if (generated_utils.count(util_name) == 0)
{ {
util_ifdef_guard(util_name); util_ifdef_guard(util_name);
util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str())); util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name, sigtype(n)));
util_declarations.push_back(stringf("{")); util_declarations.push_back(stringf("{"));
int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize); string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize);
util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name.c_str(), word_offset)); util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name, word_offset));
util_declarations.push_back(stringf("}")); util_declarations.push_back(stringf("}"));
util_declarations.push_back(stringf("#endif")); util_declarations.push_back(stringf("#endif"));
generated_utils.insert(util_name); generated_utils.insert(util_name);
} }
return stringf("%s(&%s)", util_name.c_str(), signame.c_str()); return stringf("%s(&%s)", util_name, signame);
} }
string util_set_bit(const string &signame, int n, int idx, const string &expr) string util_set_bit(const string &signame, int n, int idx, const string &expr)
{ {
if (n == 1 && idx == 0) if (n == 1 && idx == 0)
return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str()); return stringf(" %s.value_0_0 = %s;", signame, expr);
string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n); string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n);
if (generated_utils.count(util_name) == 0) if (generated_utils.count(util_name) == 0)
{ {
util_ifdef_guard(util_name); util_ifdef_guard(util_name);
util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str())); util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name, sigtype(n)));
util_declarations.push_back(stringf("{")); util_declarations.push_back(stringf("{"));
int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize;
@ -266,9 +266,9 @@ struct SimplecWorker
#if 0 #if 0
util_declarations.push_back(stringf(" if (value)")); util_declarations.push_back(stringf(" if (value)"));
util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset)); util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name, word_offset));
util_declarations.push_back(stringf(" else")); util_declarations.push_back(stringf(" else"));
util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset)); util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name, word_offset));
#else #else
util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);", util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);",
value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset)); value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset));
@ -279,7 +279,7 @@ struct SimplecWorker
generated_utils.insert(util_name); generated_utils.insert(util_name);
} }
return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str()); return stringf(" %s(&%s, %s);", util_name, signame, expr);
} }
void create_module_struct(Module *mod) void create_module_struct(Module *mod)
@ -339,38 +339,38 @@ struct SimplecWorker
for (int i = 0; i < GetSize(topo.sorted); i++) for (int i = 0; i < GetSize(topo.sorted); i++)
topoidx[mod->cell(topo.sorted[i])] = i; topoidx[mod->cell(topo.sorted[i])] = i;
string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str()); string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name));
for (int i = 0; i < GetSize(ifdef_name); i++) for (int i = 0; i < GetSize(ifdef_name); i++)
if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z') if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z')
ifdef_name[i] -= 'a' - 'A'; ifdef_name[i] -= 'a' - 'A';
struct_declarations.push_back(""); struct_declarations.push_back("");
struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str())); struct_declarations.push_back(stringf("#ifndef %s", ifdef_name));
struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str())); struct_declarations.push_back(stringf("#define %s", ifdef_name));
struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str())); struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name)));
struct_declarations.push_back("{"); struct_declarations.push_back("{");
struct_declarations.push_back(" // Input Ports"); struct_declarations.push_back(" // Input Ports");
for (Wire *w : mod->wires()) for (Wire *w : mod->wires())
if (w->port_input) if (w->port_input)
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
struct_declarations.push_back(""); struct_declarations.push_back("");
struct_declarations.push_back(" // Output Ports"); struct_declarations.push_back(" // Output Ports");
for (Wire *w : mod->wires()) for (Wire *w : mod->wires())
if (!w->port_input && w->port_output) if (!w->port_input && w->port_output)
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
struct_declarations.push_back(""); struct_declarations.push_back("");
struct_declarations.push_back(" // Internal Wires"); struct_declarations.push_back(" // Internal Wires");
for (Wire *w : mod->wires()) for (Wire *w : mod->wires())
if (!w->port_input && !w->port_output) if (!w->port_input && !w->port_output)
struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w)));
for (Cell *c : mod->cells()) for (Cell *c : mod->cells())
if (design->module(c->type)) if (design->module(c->type))
struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c))); struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type), cid(c->name), log_id(c)));
struct_declarations.push_back(stringf("};")); struct_declarations.push_back(stringf("};"));
struct_declarations.push_back("#endif"); struct_declarations.push_back("#endif");
@ -407,14 +407,14 @@ struct SimplecWorker
string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0"; string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
string expr; string expr;
if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str()); if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr, b_expr);
if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str()); if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr, b_expr);
if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str()); if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr, b_expr);
if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str()); if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr, b_expr);
if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str()); if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr, b_expr);
if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str()); if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr, b_expr);
if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str()); if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr, b_expr);
if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr.c_str(), b_expr.c_str()); if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr, b_expr);
log_assert(y.wire); log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
@ -436,8 +436,8 @@ struct SimplecWorker
string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0"; string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
string expr; string expr;
if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr, b_expr, c_expr);
if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr, b_expr, c_expr);
log_assert(y.wire); log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
@ -461,8 +461,8 @@ struct SimplecWorker
string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0"; string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0";
string expr; string expr;
if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str()); if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr, b_expr, c_expr, d_expr);
if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str()); if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr, b_expr, c_expr, d_expr);
log_assert(y.wire); log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
@ -484,9 +484,9 @@ struct SimplecWorker
string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0"; string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
// casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933) // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933)
string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(), string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr,
cell->type == ID($_NMUX_) ? "!" : "", b_expr.c_str(), cell->type == ID($_NMUX_) ? "!" : "", b_expr,
cell->type == ID($_NMUX_) ? "!" : "", a_expr.c_str()); cell->type == ID($_NMUX_) ? "!" : "", a_expr);
log_assert(y.wire); log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
@ -504,7 +504,7 @@ struct SimplecWorker
while (work->dirty) while (work->dirty)
{ {
if (verbose && (!work->dirty_bits.empty() || !work->dirty_cells.empty())) if (verbose && (!work->dirty_bits.empty() || !work->dirty_cells.empty()))
log(" In %s:\n", work->log_prefix.c_str()); log(" In %s:\n", work->log_prefix);
while (!work->dirty_bits.empty() || !work->dirty_cells.empty()) while (!work->dirty_bits.empty() || !work->dirty_cells.empty())
{ {
@ -517,8 +517,8 @@ struct SimplecWorker
if (chunk.wire == nullptr) if (chunk.wire == nullptr)
continue; continue;
if (verbose) if (verbose)
log(" Propagating %s.%s[%d:%d].\n", work->log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset); log(" Propagating %s.%s[%d:%d].\n", work->log_prefix, log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset);
funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix.c_str(), log_signal(chunk))); funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix, log_signal(chunk)));
} }
for (SigBit bit : dirtysig) for (SigBit bit : dirtysig)
@ -539,7 +539,7 @@ struct SimplecWorker
work->parent->set_dirty(parent_bit); work->parent->set_dirty(parent_bit);
if (verbose) if (verbose)
log(" Propagating %s.%s[%d] -> %s.%s[%d].\n", work->log_prefix.c_str(), log_id(bit.wire), bit.offset, 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); work->parent->log_prefix.c_str(), log_id(parent_bit.wire), parent_bit.offset);
} }
@ -556,11 +556,11 @@ struct SimplecWorker
child->set_dirty(child_bit); child->set_dirty(child_bit);
if (verbose) if (verbose)
log(" Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", work->log_prefix.c_str(), log_id(bit.wire), bit.offset, 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); work->log_prefix.c_str(), log_id(std::get<0>(port)), log_id(child_bit.wire), child_bit.offset);
} else { } else {
if (verbose) if (verbose)
log(" Marking cell %s.%s (via %s.%s[%d]).\n", work->log_prefix.c_str(), log_id(std::get<0>(port)), 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); work->log_prefix.c_str(), log_id(bit.wire), bit.offset);
work->set_dirty(std::get<0>(port)); work->set_dirty(std::get<0>(port));
} }
@ -579,7 +579,7 @@ struct SimplecWorker
string hiername = work->log_prefix + "." + log_id(cell); string hiername = work->log_prefix + "." + log_id(cell);
if (verbose) if (verbose)
log(" Evaluating %s (%s, best of %d).\n", hiername.c_str(), log_id(cell->type), GetSize(work->dirty_cells)); log(" Evaluating %s (%s, best of %d).\n", hiername, log_id(cell->type), GetSize(work->dirty_cells));
if (activated_cells.count(hiername)) if (activated_cells.count(hiername))
reactivated_cells.insert(hiername); reactivated_cells.insert(hiername);
@ -630,13 +630,13 @@ struct SimplecWorker
void make_func(HierDirtyFlags *work, const string &func_name, const vector<string> &preamble) void make_func(HierDirtyFlags *work, const string &func_name, const vector<string> &preamble)
{ {
log("Generating function %s():\n", func_name.c_str()); log("Generating function %s():\n", func_name);
activated_cells.clear(); activated_cells.clear();
reactivated_cells.clear(); reactivated_cells.clear();
funct_declarations.push_back(""); funct_declarations.push_back("");
funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str())); funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name, cid(work->module->name)));
funct_declarations.push_back("{"); funct_declarations.push_back("{");
for (auto &line : preamble) for (auto &line : preamble)
funct_declarations.push_back(line); funct_declarations.push_back(line);
@ -657,7 +657,7 @@ struct SimplecWorker
{ {
SigSpec sig = sigmaps.at(module)(w); SigSpec sig = sigmaps.at(module)(w);
Const val = w->attributes.at(ID::init); Const val = w->attributes.at(ID::init);
val.bits().resize(GetSize(sig), State::Sx); val.resize(GetSize(sig), State::Sx);
for (int i = 0; i < GetSize(sig); i++) for (int i = 0; i < GetSize(sig); i++)
if (val[i] == State::S0 || val[i] == State::S1) { if (val[i] == State::S0 || val[i] == State::S1) {

View file

@ -82,27 +82,27 @@ struct Smt2Worker
if (statebv) if (statebv)
{ {
if (width == 0) { if (width == 0) {
decl_str = stringf("(define-fun |%s| ((state |%s_s|)) Bool (= ((_ extract %d %d) state) #b1))", name.c_str(), get_id(module), statebv_width, statebv_width); decl_str = stringf("(define-fun |%s| ((state |%s_s|)) Bool (= ((_ extract %d %d) state) #b1))", name, get_id(module), statebv_width, statebv_width);
statebv_width += 1; statebv_width += 1;
} else { } else {
decl_str = stringf("(define-fun |%s| ((state |%s_s|)) (_ BitVec %d) ((_ extract %d %d) state))", name.c_str(), get_id(module), width, statebv_width+width-1, statebv_width); decl_str = stringf("(define-fun |%s| ((state |%s_s|)) (_ BitVec %d) ((_ extract %d %d) state))", name, get_id(module), width, statebv_width+width-1, statebv_width);
statebv_width += width; statebv_width += width;
} }
} }
else if (statedt) else if (statedt)
{ {
if (width == 0) { if (width == 0) {
decl_str = stringf(" (|%s| Bool)", name.c_str()); decl_str = stringf(" (|%s| Bool)", name);
} else { } else {
decl_str = stringf(" (|%s| (_ BitVec %d))", name.c_str(), width); decl_str = stringf(" (|%s| (_ BitVec %d))", name, width);
} }
} }
else else
{ {
if (width == 0) { if (width == 0) {
decl_str = stringf("(declare-fun |%s| (|%s_s|) Bool)", name.c_str(), get_id(module)); decl_str = stringf("(declare-fun |%s| (|%s_s|) Bool)", name, get_id(module));
} else { } else {
decl_str = stringf("(declare-fun |%s| (|%s_s|) (_ BitVec %d))", name.c_str(), get_id(module), width); decl_str = stringf("(declare-fun |%s| (|%s_s|) (_ BitVec %d))", name, get_id(module), width);
} }
} }
@ -130,7 +130,7 @@ struct Smt2Worker
for (auto &mem : memories) for (auto &mem : memories)
{ {
if (is_smtlib2_module) if (is_smtlib2_module)
log_error("Memory %s.%s not allowed in module with smtlib2_module attribute", get_id(module), mem.memid.c_str()); log_error("Memory %s.%s not allowed in module with smtlib2_module attribute", get_id(module), mem.memid);
mem.narrow(); mem.narrow();
mem_dict[mem.memid] = &mem; mem_dict[mem.memid] = &mem;
@ -383,7 +383,7 @@ struct Smt2Worker
} }
if (fcache.count(sig[i]) && fcache.at(sig[i]).second == -1) { if (fcache.count(sig[i]) && fcache.at(sig[i]).second == -1) {
subexpr.push_back(stringf("(ite %s #b1 #b0)", get_bool(sig[i], state_name).c_str())); subexpr.push_back(stringf("(ite %s #b1 #b0)", get_bool(sig[i], state_name)));
continue; continue;
} }
@ -495,7 +495,7 @@ struct Smt2Worker
} }
if (width != GetSize(sig_y) && type != 'b') if (width != GetSize(sig_y) && type != 'b')
processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr.c_str()); processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr);
if (verbose) 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), "", log_id(cell));
@ -617,14 +617,14 @@ struct Smt2Worker
string infostr = cell->attributes.count(ID::src) ? cell->attributes.at(ID::src).decode_string().c_str() : get_id(cell); string infostr = cell->attributes.count(ID::src) ? cell->attributes.at(ID::src).decode_string().c_str() : get_id(cell);
if (cell->attributes.count(ID::reg)) if (cell->attributes.count(ID::reg))
infostr += " " + cell->attributes.at(ID::reg).decode_string(); infostr += " " + cell->attributes.at(ID::reg).decode_string();
decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(QY)), infostr.c_str())); decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(QY)), infostr));
if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::maximize)){ if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::maximize)){
decls.push_back(stringf("; yosys-smt2-maximize %s#%d\n", get_id(module), idcounter)); decls.push_back(stringf("; yosys-smt2-maximize %s#%d\n", get_id(module), idcounter));
log("Wire %s is maximized\n", cell->getPort(QY).as_wire()->name.str().c_str()); log("Wire %s is maximized\n", cell->getPort(QY).as_wire()->name.str());
} }
else if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::minimize)){ else if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::minimize)){
decls.push_back(stringf("; yosys-smt2-minimize %s#%d\n", get_id(module), idcounter)); decls.push_back(stringf("; yosys-smt2-minimize %s#%d\n", get_id(module), idcounter));
log("Wire %s is minimized\n", cell->getPort(QY).as_wire()->name.str().c_str()); log("Wire %s is minimized\n", cell->getPort(QY).as_wire()->name.str());
} }
bool init_only = cell->type.in(ID($anyconst), ID($anyinit), ID($allconst)); bool init_only = cell->type.in(ID($anyconst), ID($anyinit), ID($allconst));
@ -722,7 +722,7 @@ struct Smt2Worker
2*GetSize(cell->getPort(ID::A).chunks()) < GetSize(cell->getPort(ID::A))) { 2*GetSize(cell->getPort(ID::A).chunks()) < GetSize(cell->getPort(ID::A))) {
bool is_and = cell->type == ID($reduce_and); bool is_and = cell->type == ID($reduce_and);
string bits(GetSize(cell->getPort(ID::A)), is_and ? '1' : '0'); string bits(GetSize(cell->getPort(ID::A)), is_and ? '1' : '0');
return export_bvop(cell, stringf("(%s A #b%s)", is_and ? "=" : "distinct", bits.c_str()), 'b'); return export_bvop(cell, stringf("(%s A #b%s)", is_and ? "=" : "distinct", bits), 'b');
} }
if (cell->type == ID($reduce_and)) return export_reduce(cell, "(and A)", true); if (cell->type == ID($reduce_and)) return export_reduce(cell, "(and A)", true);
@ -746,7 +746,7 @@ struct Smt2Worker
get_bv(sig_s); get_bv(sig_s);
for (int i = 0; i < GetSize(sig_s); i++) for (int i = 0; i < GetSize(sig_s); i++)
processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(), processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]),
get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str()); get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str());
if (verbose) if (verbose)
@ -1079,24 +1079,24 @@ struct Smt2Worker
RTLIL::SigSpec sig = sigmap(wire); RTLIL::SigSpec sig = sigmap(wire);
Const val = wire->attributes.at(ID::init); Const val = wire->attributes.at(ID::init);
val.bits().resize(GetSize(sig), State::Sx); val.resize(GetSize(sig), State::Sx);
if (bvmode && GetSize(sig) > 1) { if (bvmode && GetSize(sig) > 1) {
Const mask(State::S1, GetSize(sig)); Const mask(State::S1, GetSize(sig));
bool use_mask = false; bool use_mask = false;
for (int i = 0; i < GetSize(sig); i++) for (int i = 0; i < GetSize(sig); i++)
if (val[i] != State::S0 && val[i] != State::S1) { if (val[i] != State::S0 && val[i] != State::S1) {
val.bits()[i] = State::S0; val.set(i, State::S0);
mask.bits()[i] = State::S0; mask.set(i, State::S0);
use_mask = true; use_mask = true;
} }
if (use_mask) if (use_mask)
init_list.push_back(stringf("(= (bvand %s #b%s) #b%s) ; %s", get_bv(sig).c_str(), mask.as_string().c_str(), val.as_string().c_str(), get_id(wire))); init_list.push_back(stringf("(= (bvand %s #b%s) #b%s) ; %s", get_bv(sig), mask.as_string(), val.as_string(), get_id(wire)));
else else
init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), get_id(wire))); init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig), val.as_string(), get_id(wire)));
} else { } else {
for (int i = 0; i < GetSize(sig); i++) for (int i = 0; i < GetSize(sig); i++)
if (val[i] == State::S0 || val[i] == State::S1) if (val[i] == State::S0 || val[i] == State::S1)
init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val[i] == State::S1 ? "true" : "false", get_id(wire))); init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]), val[i] == State::S1 ? "true" : "false", get_id(wire)));
} }
} }
@ -1131,7 +1131,7 @@ struct Smt2Worker
} }
if (private_name && cell->attributes.count(ID::src)) if (private_name && cell->attributes.count(ID::src))
decls.push_back(stringf("; yosys-smt2-%s %d %s %s\n", cell->type.c_str() + 1, id, get_id(cell), cell->attributes.at(ID::src).decode_string().c_str())); decls.push_back(stringf("; yosys-smt2-%s %d %s %s\n", cell->type.c_str() + 1, id, get_id(cell), cell->attributes.at(ID::src).decode_string()));
else else
decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, get_id(cell))); decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, get_id(cell)));
@ -1180,11 +1180,11 @@ struct Smt2Worker
SigSpec sig = sigmap(conn.second); SigSpec sig = sigmap(conn.second);
if (bvmode || GetSize(w) == 1) { if (bvmode || GetSize(w) == 1) {
hier.push_back(stringf(" (= %s (|%s_n %s| %s)) ; %s.%s\n", (GetSize(w) > 1 ? get_bv(sig) : get_bool(sig)).c_str(), hier.push_back(stringf(" (= %s (|%s_n %s| %s)) ; %s.%s\n", (GetSize(w) > 1 ? get_bv(sig) : get_bool(sig)),
get_id(cell->type), get_id(w), cell_state.c_str(), get_id(cell->type), get_id(w))); get_id(cell->type), get_id(w), cell_state.c_str(), get_id(cell->type), get_id(w)));
} else { } else {
for (int i = 0; i < GetSize(w); i++) for (int i = 0; i < GetSize(w); i++)
hier.push_back(stringf(" (= %s (|%s_n %s %d| %s)) ; %s.%s[%d]\n", get_bool(sig[i]).c_str(), hier.push_back(stringf(" (= %s (|%s_n %s %d| %s)) ; %s.%s[%d]\n", get_bool(sig[i]),
get_id(cell->type), get_id(w), i, cell_state.c_str(), get_id(cell->type), get_id(w), i)); get_id(cell->type), get_id(w), i, cell_state.c_str(), get_id(cell->type), get_id(w), i));
} }
} }
@ -1204,25 +1204,25 @@ struct Smt2Worker
{ {
std::string expr_d = get_bool(cell->getPort(ID::D)); std::string expr_d = get_bool(cell->getPort(ID::D));
std::string expr_q = get_bool(cell->getPort(ID::Q), "next_state"); std::string expr_q = get_bool(cell->getPort(ID::Q), "next_state");
trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort(ID::Q)))); trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d, expr_q, get_id(cell), log_signal(cell->getPort(ID::Q))));
ex_state_eq.push_back(stringf("(= %s %s)", get_bool(cell->getPort(ID::Q)).c_str(), get_bool(cell->getPort(ID::Q), "other_state").c_str())); ex_state_eq.push_back(stringf("(= %s %s)", get_bool(cell->getPort(ID::Q)), get_bool(cell->getPort(ID::Q), "other_state")));
} }
if (cell->type.in(ID($ff), ID($dff), ID($anyinit))) if (cell->type.in(ID($ff), ID($dff), ID($anyinit)))
{ {
std::string expr_d = get_bv(cell->getPort(ID::D)); std::string expr_d = get_bv(cell->getPort(ID::D));
std::string expr_q = get_bv(cell->getPort(ID::Q), "next_state"); std::string expr_q = get_bv(cell->getPort(ID::Q), "next_state");
trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort(ID::Q)))); trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d, expr_q, get_id(cell), log_signal(cell->getPort(ID::Q))));
ex_state_eq.push_back(stringf("(= %s %s)", get_bv(cell->getPort(ID::Q)).c_str(), get_bv(cell->getPort(ID::Q), "other_state").c_str())); ex_state_eq.push_back(stringf("(= %s %s)", get_bv(cell->getPort(ID::Q)), get_bv(cell->getPort(ID::Q), "other_state")));
} }
if (cell->type.in(ID($anyconst), ID($allconst))) if (cell->type.in(ID($anyconst), ID($allconst)))
{ {
std::string expr_d = get_bv(cell->getPort(ID::Y)); std::string expr_d = get_bv(cell->getPort(ID::Y));
std::string expr_q = get_bv(cell->getPort(ID::Y), "next_state"); std::string expr_q = get_bv(cell->getPort(ID::Y), "next_state");
trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort(ID::Y)))); trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d, expr_q, get_id(cell), log_signal(cell->getPort(ID::Y))));
if (cell->type == ID($anyconst)) if (cell->type == ID($anyconst))
ex_state_eq.push_back(stringf("(= %s %s)", get_bv(cell->getPort(ID::Y)).c_str(), get_bv(cell->getPort(ID::Y), "other_state").c_str())); ex_state_eq.push_back(stringf("(= %s %s)", get_bv(cell->getPort(ID::Y)), get_bv(cell->getPort(ID::Y), "other_state")));
} }
} }
@ -1341,11 +1341,11 @@ struct Smt2Worker
std::string expr_d = stringf("(|%s#%d#%d| state)", get_id(module), arrayid, GetSize(mem->wr_ports)); std::string expr_d = stringf("(|%s#%d#%d| state)", get_id(module), arrayid, GetSize(mem->wr_ports));
std::string expr_q = stringf("(|%s#%d#0| next_state)", get_id(module), arrayid); std::string expr_q = stringf("(|%s#%d#0| next_state)", get_id(module), arrayid);
trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), get_id(mem->memid))); trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d, expr_q, get_id(mem->memid)));
ex_state_eq.push_back(stringf("(= (|%s#%d#0| state) (|%s#%d#0| other_state))", get_id(module), arrayid, get_id(module), arrayid)); ex_state_eq.push_back(stringf("(= (|%s#%d#0| state) (|%s#%d#0| other_state))", get_id(module), arrayid, get_id(module), arrayid));
if (has_async_wr) if (has_async_wr)
hier.push_back(stringf(" (= %s (|%s| state)) ; %s\n", expr_d.c_str(), final_memstate.c_str(), get_id(mem->memid))); hier.push_back(stringf(" (= %s (|%s| state)) ; %s\n", expr_d, final_memstate, get_id(mem->memid)));
Const init_data = mem->get_init_data(); Const init_data = mem->get_init_data();
@ -1361,10 +1361,10 @@ struct Smt2Worker
for (int k = 0; k < GetSize(initword); k++) { for (int k = 0; k < GetSize(initword); k++) {
if (initword[k] == State::S0 || initword[k] == State::S1) { if (initword[k] == State::S0 || initword[k] == State::S1) {
gen_init_constr = true; gen_init_constr = true;
initmask.bits()[k] = State::S1; initmask.set(k, State::S1);
} else { } else {
initmask.bits()[k] = State::S0; initmask.set(k, State::S0);
initword.bits()[k] = State::S0; initword.set(k, State::S0);
} }
} }
@ -1402,7 +1402,7 @@ struct Smt2Worker
expr = "\n " + ex_state_eq.front() + "\n"; expr = "\n " + ex_state_eq.front() + "\n";
} else { } else {
for (auto &str : ex_state_eq) for (auto &str : ex_state_eq)
expr += stringf("\n %s", str.c_str()); expr += stringf("\n %s", str);
expr += "\n)"; expr += "\n)";
} }
} }
@ -1415,7 +1415,7 @@ struct Smt2Worker
expr = "\n " + ex_input_eq.front() + "\n"; expr = "\n " + ex_input_eq.front() + "\n";
} else { } else {
for (auto &str : ex_input_eq) for (auto &str : ex_input_eq)
expr += stringf("\n %s", str.c_str()); expr += stringf("\n %s", str);
expr += "\n)"; expr += "\n)";
} }
} }
@ -1429,7 +1429,7 @@ struct Smt2Worker
assert_expr = "\n " + assert_list.front() + "\n"; assert_expr = "\n " + assert_list.front() + "\n";
} else { } else {
for (auto &str : assert_list) for (auto &str : assert_list)
assert_expr += stringf("\n %s", str.c_str()); assert_expr += stringf("\n %s", str);
assert_expr += "\n)"; assert_expr += "\n)";
} }
} }
@ -1442,7 +1442,7 @@ struct Smt2Worker
assume_expr = "\n " + assume_list.front() + "\n"; assume_expr = "\n " + assume_list.front() + "\n";
} else { } else {
for (auto &str : assume_list) for (auto &str : assume_list)
assume_expr += stringf("\n %s", str.c_str()); assume_expr += stringf("\n %s", str);
assume_expr += "\n)"; assume_expr += "\n)";
} }
} }
@ -1455,7 +1455,7 @@ struct Smt2Worker
init_expr = "\n " + init_list.front() + "\n"; init_expr = "\n " + init_list.front() + "\n";
} else { } else {
for (auto &str : init_list) for (auto &str : init_list)
init_expr += stringf("\n %s", str.c_str()); init_expr += stringf("\n %s", str);
init_expr += "\n)"; init_expr += "\n)";
} }
} }
@ -1776,7 +1776,7 @@ struct Smt2Backend : public Backend {
if (args[argidx] == "-tpl" && argidx+1 < args.size()) { if (args[argidx] == "-tpl" && argidx+1 < args.size()) {
template_f.open(args[++argidx]); template_f.open(args[++argidx]);
if (template_f.fail()) if (template_f.fail())
log_error("Can't open template file `%s'.\n", args[argidx].c_str()); log_error("Can't open template file `%s'.\n", args[argidx]);
continue; continue;
} }
if (args[argidx] == "-bv" || args[argidx] == "-mem") { if (args[argidx] == "-bv" || args[argidx] == "-mem") {
@ -1846,7 +1846,7 @@ struct Smt2Backend : public Backend {
*f << stringf("; yosys-smt2-stdt\n"); *f << stringf("; yosys-smt2-stdt\n");
for (auto &it : solver_options) for (auto &it : solver_options)
*f << stringf("; yosys-smt2-solver-option %s %s\n", it.first.c_str(), it.second.c_str()); *f << stringf("; yosys-smt2-solver-option %s %s\n", it.first, it.second);
std::vector<RTLIL::Module*> sorted_modules; std::vector<RTLIL::Module*> sorted_modules;
@ -1913,7 +1913,7 @@ struct Smt2Backend : public Backend {
} }
if (topmod) if (topmod)
*f << stringf("; yosys-smt2-topmod %s\n", topmod_id.c_str()); *f << stringf("; yosys-smt2-topmod %s\n", topmod_id);
*f << stringf("; end of yosys output\n"); *f << stringf("; end of yosys output\n");

View file

@ -1875,6 +1875,11 @@ elif covermode:
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step)) smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step))
smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step)) smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step))
if step < skip_steps:
print_msg("Skipping step %d.." % (step))
step += 1
continue
while "1" in cover_mask: while "1" in cover_mask:
print_msg("Checking cover reachability in step %d.." % (step)) print_msg("Checking cover reachability in step %d.." % (step))
smt_push() smt_push()

View file

@ -59,7 +59,7 @@ struct SmvWorker
{ {
if (!idcache.count(id)) if (!idcache.count(id))
{ {
string name = stringf("_%s", id.c_str()); string name = stringf("_%s", id);
if (name.compare(0, 2, "_\\") == 0) if (name.compare(0, 2, "_\\") == 0)
name = "_" + name.substr(2); name = "_" + name.substr(2);
@ -163,15 +163,15 @@ struct SmvWorker
if (width >= 0) { if (width >= 0) {
if (is_signed) { if (is_signed) {
if (GetSize(sig) > width) if (GetSize(sig) > width)
s = stringf("signed(resize(%s, %d))", s.c_str(), width); s = stringf("signed(resize(%s, %d))", s, width);
else else
s = stringf("resize(signed(%s), %d)", s.c_str(), width); s = stringf("resize(signed(%s), %d)", s, width);
} else } else
s = stringf("resize(%s, %d)", s.c_str(), width); s = stringf("resize(%s, %d)", s, width);
} else if (is_signed) } else if (is_signed)
s = stringf("signed(%s)", s.c_str()); s = stringf("signed(%s)", s);
else if (count_chunks > 1) else if (count_chunks > 1)
s = stringf("(%s)", s.c_str()); s = stringf("(%s)", s);
strbuf.push_back(s); strbuf.push_back(s);
return strbuf.back().c_str(); return strbuf.back().c_str();
@ -262,7 +262,7 @@ struct SmvWorker
if (cell->type == ID($sshr) && signed_a) if (cell->type == ID($sshr) && signed_a)
{ {
expr_a = rvalue_s(sig_a, width); expr_a = rvalue_s(sig_a, width);
expr = stringf("resize(unsigned(%s %s %s), %d)", expr_a.c_str(), op.c_str(), rvalue(sig_b.extract(0, shift_b_width)), width_y); expr = stringf("resize(unsigned(%s %s %s), %d)", expr_a, op, rvalue(sig_b.extract(0, shift_b_width)), width_y);
if (shift_b_width < GetSize(sig_b)) if (shift_b_width < GetSize(sig_b))
expr = stringf("%s != 0ud%d_0 ? (bool(%s) ? !0ud%d_0 : 0ud%d_0) : %s", expr = stringf("%s != 0ud%d_0 ? (bool(%s) ? !0ud%d_0 : 0ud%d_0) : %s",
rvalue(sig_b.extract(shift_b_width, GetSize(sig_b) - shift_b_width)), GetSize(sig_b) - shift_b_width, rvalue(sig_b.extract(shift_b_width, GetSize(sig_b) - shift_b_width)), GetSize(sig_b) - shift_b_width,
@ -278,8 +278,8 @@ struct SmvWorker
// f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b)); // f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b));
definitions.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b))); definitions.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b)));
string expr_shl = stringf("resize(%s << %s[%d:0], %d)", expr_a.c_str(), b_shl, shift_b_width-1, width_y); string expr_shl = stringf("resize(%s << %s[%d:0], %d)", expr_a, b_shl, shift_b_width-1, width_y);
string expr_shr = stringf("resize(%s >> %s[%d:0], %d)", expr_a.c_str(), b_shr, shift_b_width-1, width_y); string expr_shr = stringf("resize(%s >> %s[%d:0], %d)", expr_a, b_shr, shift_b_width-1, width_y);
if (shift_b_width < GetSize(sig_b)) { if (shift_b_width < GetSize(sig_b)) {
expr_shl = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", b_shl, GetSize(sig_b)-1, shift_b_width, expr_shl = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", b_shl, GetSize(sig_b)-1, shift_b_width,
@ -288,7 +288,7 @@ struct SmvWorker
GetSize(sig_b)-shift_b_width, width_y, expr_shr.c_str()); GetSize(sig_b)-shift_b_width, width_y, expr_shr.c_str());
} }
expr = stringf("bool(%s) ? %s : %s", rvalue(sig_b[GetSize(sig_b)-1]), expr_shl.c_str(), expr_shr.c_str()); expr = stringf("bool(%s) ? %s : %s", rvalue(sig_b[GetSize(sig_b)-1]), expr_shl, expr_shr);
} }
else else
{ {
@ -297,13 +297,13 @@ struct SmvWorker
else else
expr_a = stringf("resize(unsigned(%s), %d)", rvalue_s(sig_a, width_ay), width); expr_a = stringf("resize(unsigned(%s), %d)", rvalue_s(sig_a, width_ay), width);
expr = stringf("resize(%s %s %s[%d:0], %d)", expr_a.c_str(), op.c_str(), rvalue_u(sig_b), shift_b_width-1, width_y); expr = stringf("resize(%s %s %s[%d:0], %d)", expr_a, op, rvalue_u(sig_b), shift_b_width-1, width_y);
if (shift_b_width < GetSize(sig_b)) if (shift_b_width < GetSize(sig_b))
expr = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", rvalue_u(sig_b), GetSize(sig_b)-1, shift_b_width, expr = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", rvalue_u(sig_b), GetSize(sig_b)-1, shift_b_width,
GetSize(sig_b)-shift_b_width, width_y, expr.c_str()); GetSize(sig_b)-shift_b_width, width_y, expr.c_str());
} }
definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort(ID::Y)), expr.c_str())); definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort(ID::Y)), expr));
continue; continue;
} }
@ -426,7 +426,7 @@ struct SmvWorker
if (cell->type == ID($reduce_or)) expr = stringf("%s != 0ub%d_0", expr_a, width_a); if (cell->type == ID($reduce_or)) expr = stringf("%s != 0ub%d_0", expr_a, width_a);
if (cell->type == ID($reduce_bool)) expr = stringf("%s != 0ub%d_0", expr_a, width_a); if (cell->type == ID($reduce_bool)) expr = stringf("%s != 0ub%d_0", expr_a, width_a);
definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y)); definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr, width_y));
continue; continue;
} }
@ -445,7 +445,7 @@ struct SmvWorker
if (cell->type == ID($reduce_xnor)) if (cell->type == ID($reduce_xnor))
expr = "!(" + expr + ")"; expr = "!(" + expr + ")";
definitions.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y)); definitions.push_back(stringf("%s := resize(%s, %d);", expr_y, expr, width_y));
continue; continue;
} }
@ -463,7 +463,7 @@ struct SmvWorker
if (cell->type == ID($logic_and)) expr = expr_a + " & " + expr_b; if (cell->type == ID($logic_and)) expr = expr_a + " & " + expr_b;
if (cell->type == ID($logic_or)) expr = expr_a + " | " + expr_b; if (cell->type == ID($logic_or)) expr = expr_a + " | " + expr_b;
definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y)); definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr, width_y));
continue; continue;
} }
@ -475,7 +475,7 @@ struct SmvWorker
string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort(ID::A)), width_a); string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort(ID::A)), width_a);
const char *expr_y = lvalue(cell->getPort(ID::Y)); const char *expr_y = lvalue(cell->getPort(ID::Y));
definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y)); definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a, width_y));
continue; continue;
} }
@ -491,7 +491,7 @@ struct SmvWorker
expr += stringf("bool(%s) ? %s : ", rvalue(sig_s[i]), rvalue(sig_b.extract(i*width, width))); expr += stringf("bool(%s) ? %s : ", rvalue(sig_s[i]), rvalue(sig_b.extract(i*width, width)));
expr += rvalue(sig_a); expr += rvalue(sig_a);
definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort(ID::Y)), expr.c_str())); definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort(ID::Y)), expr));
continue; continue;
} }
@ -505,7 +505,7 @@ struct SmvWorker
if (cell->type.in(ID($_BUF_), ID($_NOT_))) if (cell->type.in(ID($_BUF_), ID($_NOT_)))
{ {
string op = cell->type == ID($_NOT_) ? "!" : ""; string op = cell->type == ID($_NOT_) ? "!" : "";
definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort(ID::Y)), op.c_str(), rvalue(cell->getPort(ID::A)))); definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort(ID::Y)), op, rvalue(cell->getPort(ID::A))));
continue; continue;
} }
@ -650,7 +650,7 @@ struct SmvWorker
for (int k = GetSize(sig)-1; k >= 0; k--) for (int k = GetSize(sig)-1; k >= 0; k--)
bits += sig[k] == State::S1 ? '1' : '0'; bits += sig[k] == State::S1 ? '1' : '0';
expr = stringf("0ub%d_%s", GetSize(bits), bits.c_str()) + expr; expr = stringf("0ub%d_%s", GetSize(bits), bits) + expr;
} }
else if (sigmap(SigBit(wire, i)) == SigBit(wire, i)) else if (sigmap(SigBit(wire, i)) == SigBit(wire, i))
{ {
@ -683,36 +683,36 @@ struct SmvWorker
} }
} }
definitions.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str())); definitions.push_back(stringf("%s := %s;", cid(wire->name), expr));
} }
if (!inputvars.empty()) { if (!inputvars.empty()) {
f << stringf(" IVAR\n"); f << stringf(" IVAR\n");
for (const string &line : inputvars) for (const string &line : inputvars)
f << stringf(" %s\n", line.c_str()); f << stringf(" %s\n", line);
} }
if (!vars.empty()) { if (!vars.empty()) {
f << stringf(" VAR\n"); f << stringf(" VAR\n");
for (const string &line : vars) for (const string &line : vars)
f << stringf(" %s\n", line.c_str()); f << stringf(" %s\n", line);
} }
if (!definitions.empty()) { if (!definitions.empty()) {
f << stringf(" DEFINE\n"); f << stringf(" DEFINE\n");
for (const string &line : definitions) for (const string &line : definitions)
f << stringf(" %s\n", line.c_str()); f << stringf(" %s\n", line);
} }
if (!assignments.empty()) { if (!assignments.empty()) {
f << stringf(" ASSIGN\n"); f << stringf(" ASSIGN\n");
for (const string &line : assignments) for (const string &line : assignments)
f << stringf(" %s\n", line.c_str()); f << stringf(" %s\n", line);
} }
if (!invarspecs.empty()) { if (!invarspecs.empty()) {
for (const string &line : invarspecs) for (const string &line : invarspecs)
f << stringf(" INVARSPEC %s\n", line.c_str()); f << stringf(" INVARSPEC %s\n", line);
} }
} }
}; };
@ -756,7 +756,7 @@ struct SmvBackend : public Backend {
if (args[argidx] == "-tpl" && argidx+1 < args.size()) { if (args[argidx] == "-tpl" && argidx+1 < args.size()) {
template_f.open(args[++argidx]); template_f.open(args[++argidx]);
if (template_f.fail()) if (template_f.fail())
log_error("Can't open template file `%s'.\n", args[argidx].c_str()); log_error("Can't open template file `%s'.\n", args[argidx]);
continue; continue;
} }
if (args[argidx] == "-verbose") { if (args[argidx] == "-verbose") {
@ -795,7 +795,7 @@ struct SmvBackend : public Backend {
modules.erase(module); modules.erase(module);
if (module == nullptr) if (module == nullptr)
log_error("Module '%s' not found.\n", stmt[1].c_str()); log_error("Module '%s' not found.\n", stmt[1]);
*f << stringf("-- SMV description generated by %s\n", yosys_maybe_version()); *f << stringf("-- SMV description generated by %s\n", yosys_maybe_version());

View file

@ -51,16 +51,16 @@ static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg,
if (s.wire->port_id) if (s.wire->port_id)
use_inames = true; use_inames = true;
if (s.wire->width > 1) if (s.wire->width > 1)
f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset); f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums), s.offset);
else else
f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str()); f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums));
} else { } else {
if (s == RTLIL::State::S0) if (s == RTLIL::State::S0)
f << stringf(" %s", neg.c_str()); f << stringf(" %s", neg);
else if (s == RTLIL::State::S1) else if (s == RTLIL::State::S1)
f << stringf(" %s", pos.c_str()); f << stringf(" %s", pos);
else else
f << stringf(" %s%d", ncpf.c_str(), nc_counter++); f << stringf(" %s%d", ncpf, nc_counter++);
} }
} }
@ -119,7 +119,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
} }
} }
f << stringf(" %s\n", spice_id2str(cell->type).c_str()); f << stringf(" %s\n", spice_id2str(cell->type));
} }
for (auto &conn : module->connections()) for (auto &conn : module->connections())
@ -127,7 +127,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
f << (buf == "DC" ? stringf("V%d", conn_counter++) : stringf("X%d", cell_counter++)); f << (buf == "DC" ? stringf("V%d", conn_counter++) : stringf("X%d", cell_counter++));
print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf.c_str())); f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf));
} }
} }
@ -242,23 +242,23 @@ struct SpiceBackend : public Backend {
ports.at(wire->port_id-1) = wire; ports.at(wire->port_id-1) = wire;
} }
*f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str()); *f << stringf(".SUBCKT %s", spice_id2str(module->name));
for (RTLIL::Wire *wire : ports) { for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL); log_assert(wire != NULL);
if (wire->width > 1) { if (wire->width > 1) {
for (int i = 0; i < wire->width; i++) for (int i = 0; i < wire->width; i++)
*f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i); *f << stringf(" %s.%d", spice_id2str(wire->name), big_endian ? wire->width - 1 - i : i);
} else } else
*f << stringf(" %s", spice_id2str(wire->name).c_str()); *f << stringf(" %s", spice_id2str(wire->name));
} }
*f << stringf("\n"); *f << stringf("\n");
print_spice_module(*f, module, design, neg, pos, buf, ncpf, big_endian, use_inames); print_spice_module(*f, module, design, neg, pos, buf, ncpf, big_endian, use_inames);
*f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str()); *f << stringf(".ENDS %s\n\n", spice_id2str(module->name));
} }
if (!top_module_name.empty()) { if (!top_module_name.empty()) {
if (top_module == NULL) if (top_module == NULL)
log_error("Can't find top module `%s'!\n", top_module_name.c_str()); log_error("Can't find top module `%s'!\n", top_module_name);
print_spice_module(*f, top_module, design, neg, pos, buf, ncpf, big_endian, use_inames); print_spice_module(*f, top_module, design, neg, pos, buf, ncpf, big_endian, use_inames);
*f << stringf("\n"); *f << stringf("\n");
} }

File diff suppressed because it is too large Load diff

View file

@ -17,36 +17,23 @@
* *
* --- * ---
* *
* A very simple and straightforward frontend for the RTLIL text * A simple and straightforward Verilog backend.
* representation.
* *
*/ */
#ifndef RTLIL_FRONTEND_H #ifndef VERILOG_BACKEND_H
#define RTLIL_FRONTEND_H #define VERILOG_BACKEND_H
#include "kernel/yosys.h" #include <string>
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
namespace VERILOG_BACKEND {
namespace RTLIL_FRONTEND { const pool<string> verilog_keywords();
extern std::istream *lexin; bool char_is_verilog_escaped(char c);
extern RTLIL::Design *current_design; bool id_is_verilog_escaped(const std::string &str);
extern bool flag_nooverwrite;
extern bool flag_overwrite;
extern bool flag_lib;
}
}; /* namespace VERILOG_BACKEND */
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
extern int rtlil_frontend_yydebug; #endif /* VERILOG_BACKEND_H */
int rtlil_frontend_yylex(void);
void rtlil_frontend_yyerror(char const *s);
void rtlil_frontend_yywarning(char const *s);
void rtlil_frontend_yyrestart(FILE *f);
int rtlil_frontend_yyparse(void);
int rtlil_frontend_yylex_destroy(void);
int rtlil_frontend_yyget_lineno(void);
#endif

2
docs/.gitignore vendored
View file

@ -1,5 +1,4 @@
/build/ /build/
/source/cmd
/source/generated /source/generated
/source/_images/**/*.log /source/_images/**/*.log
/source/_images/**/*.aux /source/_images/**/*.aux
@ -7,3 +6,4 @@
/source/_images/**/*.svg /source/_images/**/*.svg
/source/_images/**/*.dot /source/_images/**/*.dot
/source/_images/code_examples /source/_images/code_examples
/venv

View file

@ -47,7 +47,7 @@ help:
.PHONY: clean .PHONY: clean
clean: clean-examples clean: clean-examples
rm -rf $(BUILDDIR)/* rm -rf $(BUILDDIR)/*
rm -rf source/cmd util/__pycache__ rm -rf util/__pycache__
rm -rf source/generated rm -rf source/generated
$(MAKE) -C source/_images clean $(MAKE) -C source/_images clean

View file

@ -18,3 +18,8 @@
.literal-block-wrapper .code-block-caption .caption-number { .literal-block-wrapper .code-block-caption .caption-number {
padding-right: 0.5em padding-right: 0.5em
} }
/* Don't double shrink text in a literal in an optionlist */
kbd .option>.literal {
font-size: revert;
}

View file

@ -29,8 +29,7 @@ ezSAT
The files in ``libs/ezsat`` provide a library for simplifying generating CNF The files in ``libs/ezsat`` provide a library for simplifying generating CNF
formulas for SAT solvers. It also contains bindings of MiniSAT. The ezSAT formulas for SAT solvers. It also contains bindings of MiniSAT. The ezSAT
library is written by C. Wolf. It is used by the `sat` pass (see library is written by C. Wolf. It is used by the `sat` pass.
:doc:`/cmd/sat`).
fst fst
--- ---
@ -78,4 +77,4 @@ SubCircuit
The files in ``libs/subcircuit`` provide a library for solving the subcircuit The files in ``libs/subcircuit`` provide a library for solving the subcircuit
isomorphism problem. It is written by C. Wolf and based on the Ullmann Subgraph isomorphism problem. It is written by C. Wolf and based on the Ullmann Subgraph
Isomorphism Algorithm :cite:p:`UllmannSubgraphIsomorphism`. It is used by the Isomorphism Algorithm :cite:p:`UllmannSubgraphIsomorphism`. It is used by the
extract pass (see :doc:`../cmd/extract`). `extract` pass.

View file

@ -72,7 +72,7 @@ circuits.
Tools exist to synthesize high level code (usually in the form of C/C++/SystemC Tools exist to synthesize high level code (usually in the form of C/C++/SystemC
code with additional metadata) to behavioural HDL code (usually in the form of code with additional metadata) to behavioural HDL code (usually in the form of
Verilog or VHDL code). Aside from the many commercial tools for high level Verilog or VHDL code). Aside from the many commercial tools for high level
synthesis there are also a number of FOSS tools for high level synthesis . synthesis there are also a number of FOSS tools for high level synthesis.
Behavioural level Behavioural level
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -185,7 +185,7 @@ advantage that it has a unique normalized form. The latter has much better worst
case performance and is therefore better suited for the synthesis of large logic case performance and is therefore better suited for the synthesis of large logic
functions. functions.
Good FOSS tools exists for multi-level logic synthesis . Good FOSS tools exists for multi-level logic synthesis.
Yosys contains basic logic synthesis functionality but can also use ABC for the Yosys contains basic logic synthesis functionality but can also use ABC for the
logic synthesis step. Using ABC is recommended. logic synthesis step. Using ABC is recommended.
@ -221,7 +221,7 @@ design description as input and generates an RTL, logical gate or physical gate
level description of the design as output. Yosys' main strengths are behavioural level description of the design as output. Yosys' main strengths are behavioural
and RTL synthesis. A wide range of commands (synthesis passes) exist within and RTL synthesis. A wide range of commands (synthesis passes) exist within
Yosys that can be used to perform a wide range of synthesis tasks within the Yosys that can be used to perform a wide range of synthesis tasks within the
domain of behavioural, rtl and logic synthesis. Yosys is designed to be domain of behavioural, RTL and logic synthesis. Yosys is designed to be
extensible and therefore is a good basis for implementing custom synthesis tools extensible and therefore is a good basis for implementing custom synthesis tools
for specialised tasks. for specialised tasks.
@ -572,7 +572,7 @@ of lexical tokens given in :numref:`Tab. %s <tab:Basics_tokens>`.
TOK_SEMICOLON \- TOK_SEMICOLON \-
============== =============== ============== ===============
The lexer is usually generated by a lexer generator (e.g. flex ) from a The lexer is usually generated by a lexer generator (e.g. flex) from a
description file that is using regular expressions to specify the text pattern description file that is using regular expressions to specify the text pattern
that should match the individual tokens. that should match the individual tokens.

View file

@ -63,6 +63,10 @@ significant bit first. Bits may be any of:
- ``m``: A marked bit (internal use only) - ``m``: A marked bit (internal use only)
- ``-``: A don't care value - ``-``: A don't care value
When the bit representation has fewer bits than the width, it is padded to the width with
the most significant explicit bit, or ``0`` if the most significant explicit bit is ``1``,
or ``x`` if there are no explicit bits.
An *integer* is simply a signed integer value in decimal format. **Warning:** An *integer* is simply a signed integer value in decimal format. **Warning:**
Integer constants are limited to 32 bits. That is, they may only be in the range Integer constants are limited to 32 bits. That is, they may only be in the range
:math:`[-2147483648, 2147483648)`. Integers outside this range will result in an :math:`[-2147483648, 2147483648)`. Integers outside this range will result in an
@ -133,6 +137,7 @@ wires, memories, cells, processes, and connections.
<module> ::= <attr-stmt>* <module-stmt> <module-body> <module-end-stmt> <module> ::= <attr-stmt>* <module-stmt> <module-body> <module-end-stmt>
<module-stmt> ::= module <id> <eol> <module-stmt> ::= module <id> <eol>
<module-body> ::= (<param-stmt> <module-body> ::= (<param-stmt>
| <conn-stmt>
| <wire> | <wire>
| <memory> | <memory>
| <cell> | <cell>
@ -170,6 +175,11 @@ See :ref:`sec:rtlil_sigspec` for an overview of signal specifications.
| <sigspec> [ <integer> (:<integer>)? ] | <sigspec> [ <integer> (:<integer>)? ]
| { <sigspec>* } | { <sigspec>* }
When a ``<wire-id>`` is specified, the wire must have been previously declared.
When a signal slice is specified, the left-hand integer must be greather than or
equal to the right-hand integer.
Connections Connections
^^^^^^^^^^^ ^^^^^^^^^^^
@ -268,7 +278,7 @@ may have zero or more attributes.
.. code:: BNF .. code:: BNF
<switch> ::= <switch-stmt> <case>* <switch-end-stmt> <switch> ::= <switch-stmt> <case>* <switch-end-stmt>
<switch-stmt> := <attr-stmt>* switch <sigspec> <eol> <switch-stmt> ::= <attr-stmt>* switch <sigspec> <eol>
<case> ::= <attr-stmt>* <case-stmt> <case-body> <case> ::= <attr-stmt>* <case-stmt> <case-body>
<case-stmt> ::= case <compare>? <eol> <case-stmt> ::= case <compare>? <eol>
<compare> ::= <sigspec> (, <sigspec>)* <compare> ::= <sigspec> (, <sigspec>)*
@ -295,3 +305,4 @@ be:
| sync always <eol> | sync always <eol>
<sync-type> ::= low | high | posedge | negedge | edge <sync-type> ::= low | high | posedge | negedge | edge
<update-stmt> ::= update <dest-sigspec> <src-sigspec> <eol> <update-stmt> ::= update <dest-sigspec> <src-sigspec> <eol>
| <attr-stmt>* memwr <id> <sigspec> <sigspec> <sigspec> <constant> <eol>

View file

@ -24,8 +24,8 @@ are zero, the value from ``A`` input is sent to the output. If the :math:`n`\
'th bit from ``S`` is set, the value :math:`n`\ 'th ``WIDTH`` bits wide slice of 'th bit from ``S`` is set, the value :math:`n`\ 'th ``WIDTH`` bits wide slice of
the ``B`` input is sent to the output. When more than one bit from ``S`` is set the ``B`` input is sent to the output. When more than one bit from ``S`` is set
the output is undefined. Cells of this type are used to model "parallel cases" the output is undefined. Cells of this type are used to model "parallel cases"
(defined by using the ``parallel_case`` attribute or detected by an (defined by using the ``parallel_case`` attribute, the ``unique`` or ``unique0``
optimization). SystemVerilog keywords, or detected by an optimization).
The `$tribuf` cell is used to implement tristate logic. Cells of this type have The `$tribuf` cell is used to implement tristate logic. Cells of this type have
a ``WIDTH`` parameter and inputs ``A`` and ``EN`` and an output ``Y``. The ``A`` a ``WIDTH`` parameter and inputs ``A`` and ``EN`` and an output ``Y``. The ``A``

View file

@ -0,0 +1,5 @@
Writing output files
--------------------
.. autocmdgroup:: backends
:members:

View file

@ -0,0 +1,5 @@
Formal verification
-------------------
.. autocmdgroup:: formal
:members:

View file

@ -0,0 +1,5 @@
Reading input files
-------------------
.. autocmdgroup:: frontends
:members:

View file

@ -0,0 +1,152 @@
Internal commands for developers
--------------------------------
.. autocmdgroup:: internal
:members:
Writing command help
--------------------
- use `chformal` as an example
- generated help content below
.. _chformal autocmd:
.. autocmd:: chformal
:noindex:
The ``formatted_help()`` method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``PrettyHelp::get_current()``
- ``PrettyHelp::set_group()``
+ used with ``.. autocmdgroup:: <group>``
+ can assign group and return false
+ if no group is set, will try to use ``source_location`` and assign group
from path to source file
- return value
+ true means help content added to current ``PrettyHelp``
+ false to use ``Pass::help()``
- adding content
+ help content is a list of ``ContentListing`` nodes, each one having a type,
body, and its own list of children ``ContentListing``\ s
+ ``PrettyHelp::get_root()`` returns the root ``ContentListing`` (``type="root"``)
+ ``ContentListing::{usage, option, codeblock, paragraph}`` each add a
``ContentListing`` to the current node, with type the same as the method
* the first argument is the body of the new node
* ``usage`` shows how to call the command (i.e. its "signature")
* ``paragraph`` content is formatted as a paragraph of text with line breaks
added automatically
* ``codeblock`` content is displayed verbatim, use line breaks as desired;
takes an optional ``language`` argument for assigning the language in RST
output for code syntax highlighting (use ``yoscrypt`` for yosys script
syntax highlighting)
* ``option`` lists a single option for the command, usually starting with a
dash (``-``); takes an optional second argument which adds a paragraph
node as a means of description
+ ``ContentListing::open_usage`` creates and returns a new usage node, can be
used to e.g. add text/options specific to a given usage of the command
+ ``ContentListing::open_option`` creates and returns a new option node, can
be used to e.g. add multiple paragraphs to an option's description
+ paragraphs are treated as raw RST, allowing for inline formatting and
references as if it were written in the RST file itself
.. literalinclude:: /generated/chformal.cc
:language: c++
:start-at: bool formatted_help()
:end-before: void execute
:caption: ``ChformalPass::formatted_help()`` from :file:`passes/cmds/chformal.cc`
Dumping command help to json
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- `help -dump-cmds-json cmds.json`
+ generates a ``ContentListing`` for each command registered in Yosys
+ tries to parse unformatted ``Pass::help()`` output if
``Pass::formatted_help()`` is unimplemented or returns false
* if a line starts with four spaces followed by the name of the command then
a space, it is parsed as a signature (usage node)
* if a line is indented and starts with a dash (``-``), it is parsed as an
option
* anything else is parsed as a codeblock and added to either the root node
or the current option depending on the indentation
+ dictionary of command name to ``ContentListing``
* uses ``ContentListing::to_json()`` recursively for each node in root
* root node used for source location of class definition
* includes flags set during pass constructor (e.g. ``experimental_flag`` set
by ``Pass::experimental()``)
* also title (``short_help`` argument in ``Pass::Pass``), group, and class
name
+ dictionary of group name to list of commands in that group
- used by sphinx autodoc to generate help content
.. literalinclude:: /generated/cmds.json
:language: json
:start-at: "chformal": {
:end-before: "chparam": {
:caption: `chformal` in generated :file:`cmds.json`
.. note:: Synthesis command scripts are special cased
If the final block of help output starts with the string `"The following
commands are executed by this synthesis command:\n"`, then the rest of the
code block is formatted as ``yoscrypt`` (e.g. `synth_ice40`). The caveat
here is that if the ``script()`` calls ``run()`` on any commands *prior* to
the first ``check_label`` then the auto detection will break and revert to
unformatted code (e.g. `synth_fabulous`).
Command line rendering
~~~~~~~~~~~~~~~~~~~~~~
- if ``Pass::formatted_help()`` returns true, will call
``PrettyHelp::log_help()``
+ traverse over the children of the root node and render as plain text
+ effectively the reverse of converting unformatted ``Pass::help()`` text
+ lines are broken at 80 characters while maintaining indentation (controlled
by ``MAX_LINE_LEN`` in :file:`kernel/log_help.cc`)
+ each line is broken into words separated by spaces, if a given word starts
and ends with backticks they will be stripped
- if it returns false it will call ``Pass::help()`` which should call ``log()``
directly to print and format help text
+ if ``Pass::help()`` is not overridden then a default message about missing
help will be displayed
.. literalinclude:: /generated/chformal.log
:lines: 2-
RST generated from autocmd
~~~~~~~~~~~~~~~~~~~~~~~~~~
- below is the raw RST output from ``autocmd`` (``YosysCmdDocumenter`` class in
:file:`docs/util/cmd_documenter.py`) for `chformal` command
- heading will be rendered as a subheading of the most recent heading (see
`chformal autocmd`_ above rendered under `Writing command help`_)
- ``.. cmd:def:: <cmd>`` line is indexed for cross references with ``:cmd:ref:``
directive (`chformal autocmd`_ above uses ``:noindex:`` option so that
`chformal` still links to the correct location)
+ ``:title:`` option controls text that appears when hovering over the
`chformal` link
- commands with warning flags (experimental or internal) add a ``.. warning``
block before any of the help content
- if a command has no ``source_location`` the ``.. note`` at the bottom will
instead link to :doc:`/cmd/index_other`
.. autocmd_rst:: chformal

View file

@ -0,0 +1,5 @@
Yosys kernel commands
---------------------
.. autocmdgroup:: kernel
:members:

View file

@ -0,0 +1,9 @@
:orphan:
Other commands
==============
Unknown source location
.. autocmdgroup:: unknown
:members:

View file

@ -0,0 +1,14 @@
Passes
------
.. toctree::
:maxdepth: 2
:glob:
/cmd/index_passes_hierarchy
/cmd/index_passes_proc
/cmd/index_passes_fsm
/cmd/index_passes_memory
/cmd/index_passes_opt
/cmd/index_passes_techmap
/cmd/index_passes_*

View file

@ -0,0 +1,5 @@
Design modification
-------------------
.. autocmdgroup:: passes/cmds
:members:

View file

@ -0,0 +1,5 @@
Equivalence checking
--------------------
.. autocmdgroup:: passes/equiv
:members:

View file

@ -0,0 +1,5 @@
FSM handling
------------
.. autocmdgroup:: passes/fsm
:members:

View file

@ -0,0 +1,5 @@
Working with hierarchy
----------------------
.. autocmdgroup:: passes/hierarchy
:members:

View file

@ -0,0 +1,5 @@
Memory handling
---------------
.. autocmdgroup:: passes/memory
:members:

View file

@ -0,0 +1,5 @@
Optimization passes
-------------------
.. autocmdgroup:: passes/opt
:members:

View file

@ -0,0 +1,5 @@
Converting process blocks
-------------------------
.. autocmdgroup:: passes/proc
:members:

View file

@ -0,0 +1,5 @@
Simulating circuits
-------------------
.. autocmdgroup:: passes/sat
:members:

View file

@ -0,0 +1,5 @@
Design status
-------------
.. autocmdgroup:: passes/status
:members:

View file

@ -0,0 +1,7 @@
Technology mapping
------------------
.. seealso:: :doc:`/cmd/index_techlibs`
.. autocmdgroup:: passes/techmap
:members:

View file

@ -0,0 +1,11 @@
Technology libraries
====================
Listed in alphabetical order.
.. toctree::
:maxdepth: 2
:glob:
/cmd/index_techlibs_common
/cmd/index_techlibs_*

View file

@ -0,0 +1,5 @@
Achronix
------------------
.. autocmdgroup:: techlibs/achronix
:members:

View file

@ -0,0 +1,5 @@
Anlogic
------------------
.. autocmdgroup:: techlibs/anlogic
:members:

View file

@ -0,0 +1,5 @@
Generic
------------------
.. autocmdgroup:: techlibs/common
:members:

View file

@ -0,0 +1,5 @@
CoolRunner-II
------------------
.. autocmdgroup:: techlibs/coolrunner2
:members:

View file

@ -0,0 +1,5 @@
eASIC
------------------
.. autocmdgroup:: techlibs/easic
:members:

View file

@ -0,0 +1,5 @@
FABulous
------------------
.. autocmdgroup:: techlibs/fabulous
:members:

View file

@ -0,0 +1,5 @@
Gatemate
------------------
.. autocmdgroup:: techlibs/gatemate
:members:

View file

@ -0,0 +1,5 @@
Gowin
------------------
.. autocmdgroup:: techlibs/gowin
:members:

View file

@ -0,0 +1,5 @@
GreenPAK4
------------------
.. autocmdgroup:: techlibs/greenpak4
:members:

View file

@ -0,0 +1,5 @@
iCE40
------------------
.. autocmdgroup:: techlibs/ice40
:members:

View file

@ -0,0 +1,5 @@
Intel (MAX10, Cyclone IV)
-------------------------
.. autocmdgroup:: techlibs/intel
:members:

View file

@ -0,0 +1,5 @@
Intel ALM (Cyclone V, Arria V, Cyclone 10 GX)
---------------------------------------------
.. autocmdgroup:: techlibs/intel_alm
:members:

View file

@ -0,0 +1,5 @@
Lattice
------------------
.. autocmdgroup:: techlibs/lattice
:members:

View file

@ -0,0 +1,5 @@
Microchip
------------------
.. autocmdgroup:: techlibs/microchip
:members:

View file

@ -0,0 +1,5 @@
Microchip - SmartFusion2/IGLOO2
-----------------------------------
.. autocmdgroup:: techlibs/sf2
:members:

View file

@ -0,0 +1,5 @@
NanoXplore
------------------
.. autocmdgroup:: techlibs/nanoxplore
:members:

View file

@ -0,0 +1,5 @@
QuickLogic
------------------
.. autocmdgroup:: techlibs/quicklogic
:members:

View file

@ -0,0 +1,5 @@
Xilinx
------------------
.. autocmdgroup:: techlibs/xilinx
:members:

View file

@ -1,5 +1,3 @@
.. _cmd_ref:
================================================================================ ================================================================================
Command line reference Command line reference
================================================================================ ================================================================================
@ -7,10 +5,31 @@ Command line reference
.. literalinclude:: /generated/yosys .. literalinclude:: /generated/yosys
:start-at: Usage :start-at: Usage
.. toctree:: .. _cmd_ref:
:caption: Command reference
:maxdepth: 1
:glob:
/appendix/env_vars Command reference
/cmd/* -----------------
.. todo:: Can we warn on command groups that aren't included anywhere?
:ref:`List of all commands<cmd-cmd>`
.. toctree::
:maxdepth: 2
/appendix/env_vars
/cmd/index_frontends
/cmd/index_backends
/cmd/index_kernel
/cmd/index_formal
.. toctree::
:maxdepth: 3
/cmd/index_passes
/cmd/index_techlibs
.. toctree::
:maxdepth: 2
/cmd/index_internal

View file

@ -10,7 +10,7 @@ struct MyPass : public Pass {
{ {
log("Arguments to my_cmd:\n"); log("Arguments to my_cmd:\n");
for (auto &arg : args) for (auto &arg : args)
log(" %s\n", arg.c_str()); log(" %s\n", arg);
log("Modules in current design:\n"); log("Modules in current design:\n");
for (auto mod : design->modules()) for (auto mod : design->modules())

Some files were not shown because too many files have changed in this diff Show more