Merge branch 'YosysHQ:main' into master

This commit is contained in:
andy fox 2024-05-28 14:30:06 -07:00 committed by GitHub
commit 542660246f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
136 changed files with 3355 additions and 2539 deletions

55
.github/ISSUE_TEMPLATE/docs_report.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: Documentation Report
description: Report a problem with the Yosys documentation
labels: ["pending-verification"]
body:
- type: markdown
attributes:
value: >
If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area
or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA).
If you have found a bug in Yosys, or in building the documentation,
please fill out the Bug Report issue form, this form is for problems
with the live documentation on [Read the
Docs](https://yosyshq.readthedocs.io/projects/yosys/). Please only
report problems that appear on the latest version of the documentation.
Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need
commercial support for Yosys.
- type: input
id: docs_url
attributes:
label: Link to page
description: "Please provide a link to the page where the problem was found."
placeholder: "e.g. https://yosyshq.readthedocs.io/projects/yosys/"
validations:
required: true
- type: input
id: build_number
attributes:
label: Build number
description: "If possible, please provide the latest build number from https://readthedocs.org/projects/yosys/builds/."
placeholder: "e.g. Build #24078236"
validations:
required: false
- type: textarea
id: problem
attributes:
label: Issue
description: "Please describe what is incorrect, invalid, or missing."
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected
description: "If applicable, please describe what should appear instead."
validations:
required: false

5
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,5 @@
_What are the reasons/motivation for this change?_
_Explain how this is achieved._
_If applicable, please suggest to reviewers how they can test the change._

View File

@ -0,0 +1,33 @@
name: Build environment setup
description: Configure build env for Yosys builds
runs:
using: composite
steps:
- name: Install Linux Dependencies
if: runner.os == 'Linux'
shell: bash
run: |
sudo apt-get update
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev
- name: Install macOS Dependencies
if: runner.os == 'macOS'
shell: bash
run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf
- name: Linux runtime environment
if: runner.os == 'Linux'
shell: bash
run: |
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
echo "procs=$(nproc)" >> $GITHUB_ENV
- name: macOS runtime environment
if: runner.os == 'macOS'
shell: bash
run: |
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH
echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH
echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV

View File

@ -15,7 +15,8 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:

View File

@ -1,18 +0,0 @@
name: Emscripten Build
on: [push, pull_request]
jobs:
emcc:
runs-on: ubuntu-latest
steps:
- uses: mymindstorm/setup-emsdk@v14
- uses: actions/checkout@v4
- name: Build
run: |
make config-emcc
make YOSYS_VER=latest
- uses: actions/upload-artifact@v4
with:
name: yosysjs
path: yosysjs-latest.zip

97
.github/workflows/extra-builds.yml vendored Normal file
View File

@ -0,0 +1,97 @@
name: Test extra build flows
on: [push, pull_request]
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:
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
# cancel previous builds if a new commit is pushed
cancel_others: 'true'
# only run on push *or* pull_request, not both
concurrent_skipping: 'same_content_newer'
vs-prep:
name: Prepare Visual Studio build
runs-on: ubuntu-latest
needs: [pre_job]
if: needs.pre_job.outputs.should_skip != 'true'
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Build
run: make vcxsrc YOSYS_VER=latest
- uses: actions/upload-artifact@v4
with:
name: vcxsrc
path: yosys-win32-vcxsrc-latest.zip
vs-build:
name: Visual Studio build
runs-on: windows-2019
needs: [vs-prep, pre_job]
if: needs.pre_job.outputs.should_skip != 'true'
steps:
- uses: actions/download-artifact@v4
with:
name: vcxsrc
path: .
- name: unzip
run: unzip yosys-win32-vcxsrc-latest.zip
- name: setup-msbuild
uses: microsoft/setup-msbuild@v2
- name: MSBuild
working-directory: yosys-win32-vcxsrc-latest
run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.17763.0
wasi-build:
name: WASI build
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Build
run: |
WASI_SDK=wasi-sdk-19.0
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi
mkdir -p build
cat > build/Makefile.conf <<END
export PATH := $(pwd)/${WASI_SDK}/bin:${PATH}
WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot
CONFIG := wasi
PREFIX := /
ENABLE_TCL := 0
ENABLE_READLINE := 0
ENABLE_PLUGINS := 0
ENABLE_ZLIB := 0
END
make -C build -f ../Makefile CXX=clang -j$(nproc)
nix-build:
name: "Build nix flake"
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: cachix/install-nix-action@v26
with:
install_url: https://releases.nixos.org/nix/nix-2.18.1/install
- run: nix build .?submodules=1

181
.github/workflows/test-build.yml vendored Normal file
View File

@ -0,0 +1,181 @@
name: Build and run tests
on: [push, pull_request]
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:
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
# cancel previous builds if a new commit is pushed
cancel_others: 'true'
# only run on push *or* pull_request, not both
concurrent_skipping: 'same_content_newer'
pre_docs_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:
paths_ignore: '["**/README.md"]'
# cancel previous builds if a new commit is pushed
cancel_others: 'true'
# only run on push *or* pull_request, not both
concurrent_skipping: 'same_content_newer'
build-yosys:
name: Reusable build
runs-on: ${{ matrix.os }}
needs: pre_docs_job
if: needs.pre_docs_job.outputs.should_skip != 'true'
env:
CC: clang
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
fail-fast: false
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
submodules: true
- name: Setup environment
uses: ./.github/actions/setup-build-env
- name: Build
shell: bash
run: |
mkdir build
cd build
make -f ../Makefile config-$CC
make -f ../Makefile -j$procs
- name: Log yosys-config output
run: |
./yosys-config || true
- name: Compress build
shell: bash
run: |
cd build
tar -cvf ../build.tar share/ yosys yosys-*
- name: Store build artifact
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.os }}
path: build.tar
retention-days: 1
test-yosys:
name: Run tests
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, macos-latest]
fail-fast: false
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
- name: Setup environment
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: Cache iverilog
id: cache-iverilog
uses: actions/cache@v4
with:
path: .local/
key: ${{ matrix.os }}-${{ env.IVERILOG_GIT }}
- 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
uses: actions/download-artifact@v4
with:
name: build-${{ matrix.os }}
- name: Uncompress build
shell: bash
run:
tar -xvf build.tar
- name: Log yosys-config output
run: |
./yosys-config || true
- name: Run tests
shell: bash
run: |
make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC
- name: Report errors
if: ${{ failure() }}
shell: bash
run: |
find tests/**/*.err -print -exec cat {} \;
test-docs:
name: Run docs tests
runs-on: ${{ matrix.os }}
needs: [build-yosys, pre_docs_job]
if: needs.pre_docs_job.outputs.should_skip != 'true'
env:
CC: clang
strategy:
matrix:
os: [ubuntu-latest]
fail-fast: false
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
- name: Setup environment
uses: ./.github/actions/setup-build-env
- 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: Log yosys-config output
run: |
./yosys-config || true
- name: Run tests
shell: bash
run: |
make -C docs test -j${{ env.procs }}

79
.github/workflows/test-compile.yml vendored Normal file
View File

@ -0,0 +1,79 @@
name: Compiler testing
on: [push, pull_request]
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:
paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]'
# cancel previous builds if a new commit is pushed
cancel_others: 'true'
# only run on push *or* pull_request, not both
concurrent_skipping: 'same_content_newer'
test-compile:
runs-on: ${{ matrix.os }}
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
env:
CXXFLAGS: ${{ startsWith(matrix.compiler, 'gcc') && '-Wp,-D_GLIBCXX_ASSERTIONS' || ''}}
CC_SHORT: ${{ startsWith(matrix.compiler, 'gcc') && 'gcc' || 'clang' }}
strategy:
matrix:
os:
- ubuntu-latest
compiler:
# oldest supported
- 'clang-14'
- 'gcc-10'
# newest
- 'clang'
- 'gcc'
include:
# macOS
- os: macos-13
compiler: 'clang'
# oldest clang not available on ubuntu-latest
- os: ubuntu-22.04
compiler: 'clang-11'
fail-fast: false
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
submodules: true
- name: Setup environment
uses: ./.github/actions/setup-build-env
- name: Setup Cpp
uses: aminya/setup-cpp@v1
with:
compiler: ${{ matrix.compiler }}
- name: Tool versions
shell: bash
run: |
$CC --version
$CXX --version
# minimum standard
- name: Build C++11
shell: bash
run: |
make config-$CC_SHORT
make -j$procs CXXSTD=c++11 compile-only
# maximum standard, only on newest compilers
- name: Build C++20
if: ${{ matrix.compiler == 'clang' || matrix.compiler == 'gcc'}}
shell: bash
run: |
make config-$CC_SHORT
make -j$procs CXXSTD=c++20 compile-only

View File

@ -1,42 +0,0 @@
name: Build and test doc code samples
on:
pull_request:
branches:
- main
jobs:
test-docs:
runs-on: ubuntu-latest
steps:
- name: Install Dependencies
shell: bash
run: |
sudo apt-get update
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev
- name: Setup GCC
uses: Dup4/actions-setup-gcc@v1
- name: Runtime environment
shell: bash
env:
WORKSPACE: ${{ github.workspace }}
run: |
echo "GITHUB_WORKSPACE=`pwd`" >> $GITHUB_ENV
echo "$GITHUB_WORKSPACE/.local/bin" >> $GITHUB_PATH
echo "procs=$(nproc)" >> $GITHUB_ENV
- name: Checkout Yosys
uses: actions/checkout@v3
- name: Build yosys
shell: bash
run: |
make config-gcc
make -j${{ env.procs }}
- name: Run tests
shell: bash
run: |
make -C docs test -j${{ env.procs }}

View File

@ -1,130 +0,0 @@
name: Build and run tests (Linux)
on: [push, pull_request]
jobs:
test-linux:
runs-on: ${{ matrix.os.id }}
strategy:
matrix:
os:
- { id: ubuntu-20.04, name: focal }
compiler:
- 'clang-12'
- 'gcc-11'
cpp_std:
- 'c++11'
- 'c++14'
- 'c++17'
- 'c++20'
include:
# Limit the older compilers to C++11 mode
- os: { id: ubuntu-20.04, name: focal }
compiler: 'clang-11'
cpp_std: 'c++11'
- os: { id: ubuntu-20.04, name: focal }
compiler: 'gcc-10'
cpp_std: 'c++11'
fail-fast: false
steps:
- name: Install Dependencies
shell: bash
run: |
sudo apt-get update
sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev
- name: Setup GCC
if: startsWith(matrix.compiler, 'gcc')
shell: bash
run: |
CXX=${CC/#gcc/g++}
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install $CC $CXX
echo "CC=$CC" >> $GITHUB_ENV
echo "CXX=$CXX" >> $GITHUB_ENV
echo "CXXFLAGS=-Wp,-D_GLIBCXX_ASSERTIONS" >> $GITHUB_ENV
env:
CC: ${{ matrix.compiler }}
- name: Setup Clang
if: startsWith(matrix.compiler, 'clang')
shell: bash
run: |
wget https://apt.llvm.org/llvm-snapshot.gpg.key
sudo apt-key add llvm-snapshot.gpg.key
rm llvm-snapshot.gpg.key
sudo apt-add-repository "deb https://apt.llvm.org/${{ matrix.os.name }}/ llvm-toolchain-${{ matrix.os.name }} main"
sudo apt-get update
CXX=${CC/#clang/clang++}
sudo apt-get install $CC $CXX
echo "CC=$CC" >> $GITHUB_ENV
echo "CXX=$CXX" >> $GITHUB_ENV
env:
CC: ${{ matrix.compiler }}
- name: Runtime environment
shell: bash
env:
WORKSPACE: ${{ github.workspace }}
run: |
echo "GITHUB_WORKSPACE=`pwd`" >> $GITHUB_ENV
echo "$GITHUB_WORKSPACE/.local/bin" >> $GITHUB_PATH
echo "procs=$(nproc)" >> $GITHUB_ENV
- name: Tool versions
shell: bash
run: |
$CC --version
$CXX --version
- name: Checkout Yosys
uses: actions/checkout@v4
- 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: Cache iverilog
id: cache-iverilog
uses: actions/cache@v4
with:
path: .local/
key: ${{ matrix.os.id }}-${{ env.IVERILOG_GIT }}
- name: Build iverilog
if: steps.cache-iverilog.outputs.cache-hit != 'true'
shell: bash
run: |
mkdir -p $GITHUB_WORKSPACE/.local/
cd iverilog
autoconf
CC=gcc CXX=g++ ./configure --prefix=$GITHUB_WORKSPACE/.local
make -j${{ env.procs }}
make install
- name: Build yosys
shell: bash
run: |
make config-${CC%%-*}
make -j${{ env.procs }} CXXSTD=${{ matrix.cpp_std }} CC=$CC CXX=$CC LD=$CC
- name: Store build artifact
if: (matrix.cpp_std == 'c++11') && (matrix.compiler == 'gcc-11')
uses: actions/upload-artifact@v4
with:
name: compiled-yosys
path: yosys
- name: Run tests
if: (matrix.cpp_std == 'c++11') && (matrix.compiler == 'gcc-11')
shell: bash
run: |
make -j${{ env.procs }} test CXXSTD=${{ matrix.cpp_std }} CC=$CC CXX=$CC LD=$CC
- name: Log yosys-config output
run: |
./yosys-config || true

View File

@ -1,75 +0,0 @@
name: Build and run tests (macOS)
on: [push, pull_request]
jobs:
test-macos:
runs-on: ${{ matrix.os.id }}
strategy:
matrix:
os:
- { id: macos-13, name: 'Ventura' }
cpp_std:
- 'c++11'
- 'c++17'
fail-fast: false
steps:
- name: Install Dependencies
run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash
- name: Runtime environment
shell: bash
env:
WORKSPACE: ${{ github.workspace }}
run: |
echo "GITHUB_WORKSPACE=`pwd`" >> $GITHUB_ENV
echo "$GITHUB_WORKSPACE/.local/bin" >> $GITHUB_PATH
echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH
echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH
echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV
- name: Tool versions
shell: bash
run: |
cc --version
- name: Checkout Yosys
uses: actions/checkout@v4
- 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: Cache iverilog
id: cache-iverilog
uses: actions/cache@v4
with:
path: .local/
key: ${{ matrix.os.id }}-${{ env.IVERILOG_GIT }}
- name: Build iverilog
if: steps.cache-iverilog.outputs.cache-hit != 'true'
shell: bash
run: |
mkdir -p $GITHUB_WORKSPACE/.local/
cd iverilog
autoconf
CC=gcc CXX=g++ ./configure --prefix=$GITHUB_WORKSPACE/.local/
make -j${{ env.procs }}
make install
- name: Build yosys
shell: bash
run: |
make config-clang
make -j${{ env.procs }} CXXSTD=${{ matrix.cpp_std }} CC=cc CXX=cc LD=cc
- name: Run tests
if: matrix.cpp_std == 'c++11'
shell: bash
run: |
make -j${{ env.procs }} test CXXSTD=${{ matrix.cpp_std }} CC=cc CXX=cc LD=cc

95
.github/workflows/test-verific.yml vendored Normal file
View File

@ -0,0 +1,95 @@
name: Build and run tests with Verific (Linux)
on: [push, pull_request]
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:
paths_ignore: '["**/README.md"]'
# don't cancel previous builds
cancel_others: 'true'
# only run on push *or* pull_request, not both
concurrent_skipping: 'same_content_newer'
# we have special actions when running on main, so this should be off
skip_after_successful_duplicate: 'false'
test-verific:
needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'
runs-on: [self-hosted, linux, x64]
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
persist-credentials: false
submodules: true
- name: Runtime environment
run: |
echo "procs=$(nproc)" >> $GITHUB_ENV
- name: Build Yosys
run: |
make config-clang
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf
echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf
echo "ENABLE_CCACHE := 1" >> Makefile.conf
make -j${{ env.procs }}
- name: Install Yosys
run: |
make install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX=
- name: Checkout Documentation
if: ${{ github.ref == 'refs/heads/main' }}
uses: actions/checkout@v4
with:
path: 'yosys-cmd-ref'
repository: 'YosysHQ-Docs/yosys-cmd-ref'
fetch-depth: 0
token: ${{ secrets.CI_DOCS_UPDATE_PAT }}
persist-credentials: true
- name: Update documentation
if: ${{ github.ref == 'refs/heads/main' }}
run: |
make docs
rm -rf docs/build
cd yosys-cmd-ref
rm -rf *
git checkout README.md
cp -R ../docs/* .
rm -rf util/__pycache__
git add -A .
git diff-index --quiet HEAD || git commit -m "Update"
git push
- name: Checkout SBY
uses: actions/checkout@v4
with:
repository: 'YosysHQ/sby'
path: 'sby'
- name: Build SBY
run: |
make -C sby install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX=
- name: Run Yosys tests
run: |
make -j${{ env.procs }} test
- name: Run Verific specific Yosys tests
run: |
make -C tests/sva
cd tests/svtypes && bash run-test.sh
- name: Run SBY tests
if: ${{ github.ref == 'refs/heads/main' }}
run: |
make -C sby run_ci

21
.github/workflows/update-flake-lock.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: update-flake-lock
on:
workflow_dispatch: # allows manual triggering
schedule:
- cron: '0 0 * * 0' # runs weekly on Sunday at 00:00
jobs:
lockfile:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@main
with:
pr-title: "Update flake.lock" # Title of PR to be created
pr-labels: | # Labels to be set on the PR
dependencies
automated

View File

@ -13,6 +13,7 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- name: Take last commit
id: log
run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT

View File

@ -1,31 +0,0 @@
name: Visual Studio Build
on: [push, pull_request]
jobs:
yosys-vcxsrc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: make vcxsrc YOSYS_VER=latest
- uses: actions/upload-artifact@v4
with:
name: vcxsrc
path: yosys-win32-vcxsrc-latest.zip
build:
runs-on: windows-2019
needs: yosys-vcxsrc
steps:
- uses: actions/download-artifact@v4
with:
name: vcxsrc
path: .
- name: unzip
run: unzip yosys-win32-vcxsrc-latest.zip
- name: setup-msbuild
uses: microsoft/setup-msbuild@v1
- name: MSBuild
working-directory: yosys-win32-vcxsrc-latest
run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.17763.0

View File

@ -1,30 +0,0 @@
name: WASI Build
on: [push, pull_request]
jobs:
wasi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: |
WASI_SDK=wasi-sdk-19.0
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi
mkdir -p build
cat > build/Makefile.conf <<END
export PATH := $(pwd)/${WASI_SDK}/bin:${PATH}
WASI_SYSROOT := $(pwd)/${WASI_SDK}/share/wasi-sysroot
CONFIG := wasi
PREFIX := /
ENABLE_TCL := 0
ENABLE_READLINE := 0
ENABLE_PLUGINS := 0
ENABLE_ZLIB := 0
END
make -C build -f ../Makefile CXX=clang -j$(nproc)

2
.gitignore vendored
View File

@ -18,7 +18,6 @@ __pycache__
/coverage.info
/coverage_html
/Makefile.conf
/abc
/viz.js
/yosys
/yosys.exe
@ -46,3 +45,4 @@ __pycache__
/tests/unit/bintest/
/tests/unit/objtest/
/tests/ystests
/result

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "abc"]
path = abc
url = https://github.com/YosysHQ/abc

View File

@ -2,9 +2,37 @@
List of major changes and improvements between releases
=======================================================
Yosys 0.39 .. Yosys 0.40-dev
Yosys 0.41 .. Yosys 0.42-dev
--------------------------
Yosys 0.40 .. Yosys 0.41
--------------------------
* New commands and options
- Added "cellmatch" pass for picking out standard cells automatically.
* Various
- Extended the experimental incremental JSON API to allow arbitrary
smtlib subexpressions.
- Added support for using ABCs library merging when providing multiple
liberty files.
* Verific support
- Expose library name as module attribute.
Yosys 0.39 .. Yosys 0.40
--------------------------
* New commands and options
- Added option "-vhdl2019" to "read" and "verific" pass.
* Various
- Major documentation overhaul.
- Added port statistics to "stat" command.
- Added new formatting features to cxxrtl backend.
* Verific support
- Added better support for VHDL constants import.
- Added support for VHDL 2009.
Yosys 0.38 .. Yosys 0.39
--------------------------
* New commands and options

View File

@ -10,6 +10,7 @@
# PATH (can use glob) USERNAME(S)
CODEOWNERS @nakengelhardt
passes/cmds/scratchpad.cc @nakengelhardt
frontends/rpc/ @whitequark
backends/cxxrtl/ @whitequark
@ -19,7 +20,7 @@ passes/opt/opt_lut.cc @whitequark
passes/techmap/abc9*.cc @eddiehung @Ravenslofty
backends/aiger/xaiger.cc @eddiehung
docs/ @KrystalDelusion
.github/workflows/*.yml @mmicko
## External Contributors
# Only users with write permission to the repository get review

182
Makefile
View File

@ -3,7 +3,6 @@ CONFIG := none
# CONFIG := clang
# CONFIG := gcc
# CONFIG := afl-gcc
# CONFIG := emcc
# CONFIG := wasi
# CONFIG := mxe
# CONFIG := msys2-32
@ -142,7 +141,7 @@ LIBS += -lrt
endif
endif
YOSYS_VER := 0.39+147
YOSYS_VER := 0.41+108
# Note: We arrange for .gitcommit to contain the (short) commit hash in
# tarballs generated with git-archive(1) using .gitattributes. The git repo
@ -158,17 +157,8 @@ endif
OBJS = kernel/version_$(GIT_REV).o
bumpversion:
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 0033808.. | wc -l`/;" Makefile
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline c1ad377.. | wc -l`/;" Makefile
# set 'ABCREV = default' to use abc/ as it is
#
# Note: If you do ABC development, make sure that 'abc' in this directory
# is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC..
ABCREV = 0cd90d0
ABCPULL = 1
ABCURL ?= https://github.com/YosysHQ/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
# set ABCEXTERNAL = <abc-command> to use an external ABC instance
@ -263,45 +253,6 @@ CXX = g++
CXXFLAGS += -std=gnu++11 -Os
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
else ifeq ($(CONFIG),emcc)
CXX = emcc
CXXFLAGS := -std=$(CXXSTD) $(filter-out -fPIC -ggdb,$(CXXFLAGS))
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8"
EMCC_CXXFLAGS := -Os -Wno-warn-absolute-paths
EMCC_LINKFLAGS := --embed-file share
EMCC_LINKFLAGS += -s NO_EXIT_RUNTIME=1
EMCC_LINKFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg','_memset']"
EMCC_LINKFLAGS += -s TOTAL_MEMORY=134217728
EMCC_LINKFLAGS += -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
# https://github.com/kripken/emscripten/blob/master/src/settings.js
CXXFLAGS += $(EMCC_CXXFLAGS)
LINKFLAGS += $(EMCC_LINKFLAGS)
LIBS =
EXE = .js
DISABLE_SPAWN := 1
TARGETS := $(filter-out $(PROGRAM_PREFIX)yosys-config,$(TARGETS))
EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip
ifeq ($(ENABLE_ABC),1)
LINK_ABC := 1
DISABLE_ABC_THREADS := 1
endif
viz.js:
wget -O viz.js.part https://github.com/mdaines/viz.js/releases/download/0.0.3/viz.js
mv viz.js.part viz.js
yosysjs-$(YOSYS_VER).zip: yosys.js viz.js misc/yosysjs/*
rm -rf yosysjs-$(YOSYS_VER) yosysjs-$(YOSYS_VER).zip
mkdir -p yosysjs-$(YOSYS_VER)
cp viz.js misc/yosysjs/* yosys.js yosys.wasm yosysjs-$(YOSYS_VER)/
zip -r yosysjs-$(YOSYS_VER).zip yosysjs-$(YOSYS_VER)
yosys.html: misc/yosys.html
$(P) cp misc/yosys.html yosys.html
else ifeq ($(CONFIG),wasi)
ifeq ($(WASI_SDK),)
CXX = clang++
@ -366,7 +317,7 @@ CXXFLAGS += -std=$(CXXSTD) -Os
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
else
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, emcc, mxe, msys2-32, msys2-64, none)
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, mxe, msys2-32, msys2-64, none)
endif
ifeq ($(ENABLE_LIBYOSYS),1)
@ -504,7 +455,7 @@ LIBS += -lpthread
endif
else
ifeq ($(ABCEXTERNAL),)
TARGETS += $(PROGRAM_PREFIX)yosys-abc$(EXE)
TARGETS := $(PROGRAM_PREFIX)yosys-abc$(EXE) $(TARGETS)
endif
endif
endif
@ -629,6 +580,7 @@ $(eval $(call add_include_file,kernel/sigtools.h))
$(eval $(call add_include_file,kernel/timinginfo.h))
$(eval $(call add_include_file,kernel/utils.h))
$(eval $(call add_include_file,kernel/yosys.h))
$(eval $(call add_include_file,kernel/yosys_common.h))
$(eval $(call add_include_file,kernel/yw.h))
$(eval $(call add_include_file,libs/ezsat/ezsat.h))
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
@ -735,9 +687,11 @@ top-all: $(TARGETS) $(EXTRA_TARGETS)
@echo " Build successful."
@echo ""
ifeq ($(CONFIG),emcc)
yosys.js: $(filter-out yosysjs-$(YOSYS_VER).zip,$(EXTRA_TARGETS))
endif
.PHONY: compile-only
compile-only: $(OBJS) $(GENFILES) $(EXTRA_TARGETS)
@echo ""
@echo " Compile successful."
@echo ""
$(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
$(P) $(CXX) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LINKFLAGS) $(LINKFLAGS) $(OBJS) $(LIBS) $(LIBS_VERIFIC)
@ -788,41 +742,40 @@ $(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in
-e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > $(PROGRAM_PREFIX)yosys-config
$(Q) chmod +x $(PROGRAM_PREFIX)yosys-config
abc/abc-$(ABCREV)$(EXE) abc/libabc-$(ABCREV).a:
.PHONY: check-git-abc
check-git-abc:
@if [ ! -d "$(YOSYS_SRC)/abc" ]; then \
echo "Error: The 'abc' directory does not exist."; \
echo "Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \
exit 1; \
elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^ '; then \
exit 0; \
elif [ -f "$(YOSYS_SRC)/abc/.gitcommit" ] && ! grep -q '\$$Format:%h\$$' "$(YOSYS_SRC)/abc/.gitcommit"; then \
echo "'abc' comes from a tarball. Continuing."; \
exit 0; \
elif [ -f "$(YOSYS_SRC)/abc/.gitcommit" ] && grep -q '\$$Format:%h\$$' "$(YOSYS_SRC)/abc/.gitcommit"; then \
echo "Error: 'abc' is not configured as a git submodule."; \
echo "To resolve this:"; \
echo "1. Back up your changes: Save any modifications from the 'abc' directory to another location."; \
echo "2. Remove the existing 'abc' directory: Delete the 'abc' directory and all its contents."; \
echo "3. Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \
echo "4. Reapply your changes: Move your saved changes back to the 'abc' directory, if necessary."; \
exit 1; \
else \
echo "Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \
exit 1; \
fi
abc/abc$(EXE) abc/libabc.a: check-git-abc
$(P)
ifneq ($(ABCREV),default)
$(Q) if test -d abc/.hg; then \
echo 'REEBE: NOP qverpgbel vf n ut jbexvat pbcl! Erzbir nop/ naq er-eha "znxr".' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
$(Q) if test -d abc && test -d abc/.git && ! git -C abc diff-index --quiet HEAD; then \
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
$(Q) if test -d abc && ! test -d abc/.git && ! test "`cat abc/.gitcommit | cut -c1-7`" = "$(ABCREV)"; then \
echo 'REEBE: Qbjaybnqrq NOP irefvbaf qbrf abg zngpu! Qbjaybnq sebz:' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; echo $(ABCURL)/archive/$(ABCREV).tar.gz; false; \
fi
# set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string
$(Q) if test -d abc && ! test -d abc/.git && test "`cat abc/.gitcommit | cut -c1-7`" = "$(ABCREV)"; then \
echo "Compiling local copy of ABC"; \
elif ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" = "$$rev"); then \
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
echo "Pulling ABC from $(ABCURL):"; set -x; \
test -d abc || git clone $(ABCURL) abc; \
cd abc && $(MAKE) DEP= clean && git fetch $(ABCURL) && git checkout $(ABCREV); \
fi
endif
$(Q) rm -f abc/abc-[0-9a-f]*
$(Q) $(MAKE) -C abc $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc-$(ABCREV)",PROG="abc-$(ABCREV)$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc-$(ABCREV).a)
$(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)
ifeq ($(ABCREV),default)
.PHONY: abc/abc-$(ABCREV)$(EXE)
.PHONY: abc/libabc-$(ABCREV).a
endif
$(PROGRAM_PREFIX)yosys-abc$(EXE): abc/abc$(EXE)
$(P) cp $< $(PROGRAM_PREFIX)yosys-abc$(EXE)
$(PROGRAM_PREFIX)yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
$(P) cp abc/abc-$(ABCREV)$(EXE) $(PROGRAM_PREFIX)yosys-abc$(EXE)
$(PROGRAM_PREFIX)yosys-libabc.a: abc/libabc-$(ABCREV).a
$(P) cp abc/libabc-$(ABCREV).a $(PROGRAM_PREFIX)yosys-libabc.a
$(PROGRAM_PREFIX)yosys-libabc.a: abc/libabc.a
$(P) cp $< $(PROGRAM_PREFIX)yosys-libabc.a
ifneq ($(SEED),)
SEEDOPT="-S $(SEED)"
@ -984,16 +937,33 @@ docs/gen_images:
$(Q) $(MAKE) -C docs images
DOCS_GUIDELINE_FILES := GettingStarted CodingStyle
docs/guidelines:
$(Q) mkdir -p docs/source/temp
$(Q) cp -f $(addprefix guidelines/,$(DOCS_GUIDELINE_FILES)) docs/source/temp
docs/guidelines docs/source/generated:
$(Q) mkdir -p docs/source/generated
$(Q) cp -f $(addprefix guidelines/,$(DOCS_GUIDELINE_FILES)) docs/source/generated
# many of these will return an error which can be safely ignored, so we prefix
# the command with a '-'
DOCS_USAGE_PROGS := yosys yosys-config yosys-filterlib yosys-abc yosys-smtbmc yosys-witness
docs/usage: $(addprefix docs/source/temp/,$(DOCS_USAGE_PROGS))
docs/source/temp/%: docs/guidelines
-$(Q) ./$(PROGRAM_PREFIX)$* --help > $@ 2>&1
# some commands return an error and print the usage text to stderr
define DOC_USAGE_STDERR
docs/source/generated/$(1): $(PROGRAM_PREFIX)$(1) docs/source/generated
-$(Q) ./$$< --help 2> $$@
endef
DOCS_USAGE_STDERR := yosys-config yosys-filterlib
# The in-tree ABC (yosys-abc) is only built when ABCEXTERNAL is not set.
ifeq ($(ABCEXTERNAL),)
DOCS_USAGE_STDERR += yosys-abc
endif
$(foreach usage,$(DOCS_USAGE_STDERR),$(eval $(call DOC_USAGE_STDERR,$(usage))))
# others print to stdout
define DOC_USAGE_STDOUT
docs/source/generated/$(1): $(PROGRAM_PREFIX)$(1) docs/source/generated
$(Q) ./$$< --help > $$@
endef
DOCS_USAGE_STDOUT := yosys yosys-smtbmc yosys-witness
$(foreach usage,$(DOCS_USAGE_STDOUT),$(eval $(call DOC_USAGE_STDOUT,$(usage))))
docs/usage: $(addprefix docs/source/generated/,$(DOCS_USAGE_STDOUT) $(DOCS_USAGE_STDERR))
docs/reqs:
$(Q) $(MAKE) -C docs reqs
@ -1017,7 +987,9 @@ clean:
rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_*
rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff
rm -f tests/tools/cmp_tbdata
$(MAKE) -C docs clean
-$(MAKE) -C docs clean
-$(MAKE) -C docs/images clean
rm -rf docs/source/cmd docs/util/__pycache__
clean-abc:
$(MAKE) -C abc DEP= clean
@ -1033,11 +1005,12 @@ coverage:
genhtml coverage.info --output-directory coverage_html
qtcreator:
echo "$(CXXFLAGS)" | grep -o '\-D[^ ]*' | tr ' ' '\n' | sed 's/-D/#define /' | sed 's/=/ /'> qtcreator.config
{ for file in $(basename $(OBJS)); do \
for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \
done; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \); } > qtcreator.files
{ echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes
touch qtcreator.config qtcreator.creator
touch qtcreator.creator
vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
@ -1080,14 +1053,6 @@ config-gcc-static: clean
config-afl-gcc: clean
echo 'CONFIG := afl-gcc' > Makefile.conf
config-emcc: clean
echo 'CONFIG := emcc' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf
echo 'ENABLE_ABC := 0' >> Makefile.conf
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo 'ENABLE_READLINE := 0' >> Makefile.conf
echo 'ENABLE_ZLIB := 0' >> Makefile.conf
config-wasi: clean
echo 'CONFIG := wasi' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf
@ -1129,9 +1094,6 @@ echo-yosys-ver:
echo-git-rev:
@echo "$(GIT_REV)"
echo-abc-rev:
@echo "$(ABCREV)"
echo-cxx:
@echo "$(CXX)"

1
abc Submodule

@ -0,0 +1 @@
Subproject commit 237d81397fcc85dd3894bf1a449d2955cd3df02d

View File

@ -606,22 +606,30 @@ std::vector<std::string> split_by(const std::string &str, const std::string &sep
return result;
}
std::string escape_cxx_string(const std::string &input)
std::string escape_c_string(const std::string &input)
{
std::string output = "\"";
std::string output;
output.push_back('"');
for (auto c : input) {
if (::isprint(c)) {
if (c == '\\')
output.push_back('\\');
output.push_back(c);
} else {
char l = c & 0xf, h = (c >> 4) & 0xf;
output.append("\\x");
output.push_back((h < 10 ? '0' + h : 'a' + h - 10));
output.push_back((l < 10 ? '0' + l : 'a' + l - 10));
char l = c & 0x3, m = (c >> 3) & 0x3, h = (c >> 6) & 0x3;
output.append("\\");
output.push_back('0' + h);
output.push_back('0' + m);
output.push_back('0' + l);
}
}
output.push_back('"');
return output;
}
std::string escape_cxx_string(const std::string &input)
{
std::string output = escape_c_string(input);
if (output.find('\0') != std::string::npos) {
output.insert(0, "std::string {");
output.append(stringf(", %zu}", input.size()));
@ -2275,46 +2283,92 @@ struct CxxrtlWorker {
dec_indent();
}
void dump_metadata_map(const dict<RTLIL::IdString, RTLIL::Const> &metadata_map)
{
if (metadata_map.empty()) {
f << "metadata_map()";
return;
}
f << "metadata_map({\n";
inc_indent();
for (auto metadata_item : metadata_map) {
if (!metadata_item.first.isPublic())
continue;
if (metadata_item.second.size() > 64 && (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) == 0) {
f << indent << "/* attribute " << metadata_item.first.str().substr(1) << " is over 64 bits wide */\n";
continue;
}
f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", ";
// In Yosys, a real is a type of string.
if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) {
f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint;
} else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) {
f << escape_cxx_string(metadata_item.second.decode_string());
} else if (metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED) {
f << "INT64_C(" << metadata_item.second.as_int(/*is_signed=*/true) << ")";
} else {
f << "UINT64_C(" << metadata_item.second.as_int(/*is_signed=*/false) << ")";
}
f << " },\n";
void dump_serialized_metadata(const dict<RTLIL::IdString, RTLIL::Const> &metadata_map) {
// Creating thousands metadata_map objects using initializer lists in a single function results in one of:
// 1. Megabytes of stack usage (with __attribute__((optnone))).
// 2. Minutes of compile time (without __attribute__((optnone))).
// So, don't create them.
std::string data;
auto put_u64 = [&](uint64_t value) {
for (size_t count = 0; count < 8; count++) {
data += (char)(value >> 56);
value <<= 8;
}
dec_indent();
f << indent << "})";
};
for (auto metadata_item : metadata_map) {
if (!metadata_item.first.isPublic())
continue;
if (metadata_item.second.size() > 64 && (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) == 0) {
f << indent << "/* attribute " << metadata_item.first.str().substr(1) << " is over 64 bits wide */\n";
continue;
}
data += metadata_item.first.str().substr(1) + '\0';
// In Yosys, a real is a type of string.
if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) {
double dvalue = std::stod(metadata_item.second.decode_string());
uint64_t uvalue;
static_assert(sizeof(dvalue) == sizeof(uvalue), "double must be 64 bits in size");
memcpy(&uvalue, &dvalue, sizeof(uvalue));
data += 'd';
put_u64(uvalue);
} else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) {
data += 's';
data += metadata_item.second.decode_string();
data += '\0';
} else if (metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED) {
data += 'i';
put_u64((uint64_t)metadata_item.second.as_int(/*is_signed=*/true));
} else {
data += 'u';
put_u64(metadata_item.second.as_int(/*is_signed=*/false));
}
}
f << escape_c_string(data);
}
void dump_debug_attrs(const RTLIL::AttrObject *object)
void dump_metadata_map(const dict<RTLIL::IdString, RTLIL::Const> &metadata_map) {
if (metadata_map.empty()) {
f << "metadata_map()";
} else {
f << "metadata_map({\n";
inc_indent();
for (auto metadata_item : metadata_map) {
if (!metadata_item.first.isPublic())
continue;
if (metadata_item.second.size() > 64 && (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) == 0) {
f << indent << "/* attribute " << metadata_item.first.str().substr(1) << " is over 64 bits wide */\n";
continue;
}
f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", ";
// In Yosys, a real is a type of string.
if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) {
f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint;
} else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) {
f << escape_cxx_string(metadata_item.second.decode_string());
} else if (metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED) {
f << "INT64_C(" << metadata_item.second.as_int(/*is_signed=*/true) << ")";
} else {
f << "UINT64_C(" << metadata_item.second.as_int(/*is_signed=*/false) << ")";
}
f << " },\n";
}
dec_indent();
f << indent << "})";
}
}
void dump_debug_attrs(const RTLIL::AttrObject *object, bool serialize = true)
{
dict<RTLIL::IdString, RTLIL::Const> attributes = object->attributes;
// Inherently necessary to get access to the object, so a waste of space to emit.
attributes.erase(ID::hdlname);
// Internal Yosys attribute that should be removed but isn't.
attributes.erase(ID::module_not_derived);
dump_metadata_map(attributes);
if (serialize) {
dump_serialized_metadata(attributes);
} else {
dump_metadata_map(attributes);
}
}
void dump_debug_info_method(RTLIL::Module *module)
@ -2337,7 +2391,7 @@ struct CxxrtlWorker {
// The module is responsible for adding its own scope.
f << indent << "scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), ";
f << escape_cxx_string(get_hdl_name(module)) << ", ";
dump_debug_attrs(module);
dump_debug_attrs(module, /*serialize=*/false);
f << ", std::move(cell_attrs));\n";
count_scopes++;
// If there were any submodules that were flattened, the module is also responsible for adding them.
@ -2347,11 +2401,11 @@ struct CxxrtlWorker {
auto module_attrs = scopeinfo_attributes(cell, ScopeinfoAttrs::Module);
auto cell_attrs = scopeinfo_attributes(cell, ScopeinfoAttrs::Cell);
cell_attrs.erase(ID::module_not_derived);
f << indent << "scopes->add(path + " << escape_cxx_string(get_hdl_name(cell)) << ", ";
f << indent << "scopes->add(path, " << escape_cxx_string(get_hdl_name(cell)) << ", ";
f << escape_cxx_string(cell->get_string_attribute(ID(module))) << ", ";
dump_metadata_map(module_attrs);
dump_serialized_metadata(module_attrs);
f << ", ";
dump_metadata_map(cell_attrs);
dump_serialized_metadata(cell_attrs);
f << ");\n";
} else log_assert(false && "Unknown $scopeinfo type");
count_scopes++;
@ -2419,20 +2473,22 @@ struct CxxrtlWorker {
if (has_driven_sync + has_driven_comb + has_undriven > 1)
count_mixed_driver++;
f << indent << "items->add(path + " << escape_cxx_string(get_hdl_name(wire));
f << ", debug_item(" << mangle(wire) << ", " << wire->start_offset;
bool first = true;
for (auto flag : flags) {
if (first) {
first = false;
f << ", ";
} else {
f << "|";
}
f << "debug_item::" << flag;
}
f << "), ";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
dump_debug_attrs(wire);
f << ", " << mangle(wire);
if (wire->start_offset != 0 || !flags.empty()) {
f << ", " << wire->start_offset;
bool first = true;
for (auto flag : flags) {
if (first) {
first = false;
f << ", ";
} else {
f << "|";
}
f << "debug_item::" << flag;
}
}
f << ");\n";
count_member_wires++;
break;
@ -2440,16 +2496,18 @@ struct CxxrtlWorker {
case WireType::ALIAS: {
// Alias of a member wire
const RTLIL::Wire *aliasee = debug_wire_type.sig_subst.as_wire();
f << indent << "items->add(path + " << escape_cxx_string(get_hdl_name(wire));
f << ", debug_item(";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
dump_debug_attrs(aliasee);
f << ", ";
// If the aliasee is an outline, then the alias must be an outline, too; otherwise downstream
// tooling has no way to find out about the outline.
if (debug_wire_types[aliasee].is_outline())
f << "debug_eval_outline";
else
f << "debug_alias()";
f << ", " << mangle(aliasee) << ", " << wire->start_offset << "), ";
dump_debug_attrs(aliasee);
f << ", " << mangle(aliasee);
if (wire->start_offset != 0)
f << ", " << wire->start_offset;
f << ");\n";
count_alias_wires++;
break;
@ -2459,18 +2517,22 @@ struct CxxrtlWorker {
f << indent << "static const value<" << wire->width << "> const_" << mangle(wire) << " = ";
dump_const(debug_wire_type.sig_subst.as_const());
f << ";\n";
f << indent << "items->add(path + " << escape_cxx_string(get_hdl_name(wire));
f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "), ";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
dump_debug_attrs(wire);
f << ", const_" << mangle(wire);
if (wire->start_offset != 0)
f << ", " << wire->start_offset;
f << ");\n";
count_const_wires++;
break;
}
case WireType::OUTLINE: {
// Localized or inlined, but rematerializable wire
f << indent << "items->add(path + " << escape_cxx_string(get_hdl_name(wire));
f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "), ";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
dump_debug_attrs(wire);
f << ", debug_eval_outline, " << mangle(wire);
if (wire->start_offset != 0)
f << ", " << wire->start_offset;
f << ");\n";
count_inline_wires++;
break;
@ -2486,15 +2548,14 @@ struct CxxrtlWorker {
for (auto &mem : mod_memories[module]) {
if (!mem.memid.isPublic())
continue;
f << indent << "items->add(path + " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem));
f << ", debug_item(" << mangle(&mem) << ", ";
f << mem.start_offset << "), ";
f << indent << "items->add(path, " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem)) << ", ";
if (mem.packed) {
dump_debug_attrs(mem.cell);
} else {
dump_debug_attrs(mem.mem);
}
f << ");\n";
f << ", " << mangle(&mem) << ", ";
f << mem.start_offset << ");\n";
}
}
dec_indent();
@ -2506,7 +2567,7 @@ struct CxxrtlWorker {
const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : ".";
f << indent << mangle(cell) << access;
f << "debug_info(items, scopes, path + " << escape_cxx_string(get_hdl_name(cell) + ' ') << ", ";
dump_debug_attrs(cell);
dump_debug_attrs(cell, /*serialize=*/false);
f << ");\n";
}
}
@ -3202,6 +3263,7 @@ struct CxxrtlWorker {
debug_wire_type = wire_type; // wire is a member
if (!debug_alias) continue;
if (wire->port_input || wire->port_output) continue; // preserve input/output metadata in flags
const RTLIL::Wire *it = wire;
while (flow.is_inlinable(it)) {
log_assert(flow.wire_comb_defs[it].size() == 1);

View File

@ -625,11 +625,11 @@ struct value : public expr_base<value<Bits>> {
value<Bits + 1> remainder;
value<Bits + 1> dividend = sext<Bits + 1>();
value<Bits + 1> divisor = other.template sext<Bits + 1>();
if (dividend.is_neg()) dividend = dividend.neg();
if (divisor.is_neg()) divisor = divisor.neg();
if (is_neg()) dividend = dividend.neg();
if (other.is_neg()) divisor = divisor.neg();
std::tie(quotient, remainder) = dividend.udivmod(divisor);
if (dividend.is_neg() != divisor.is_neg()) quotient = quotient.neg();
if (dividend.is_neg()) remainder = remainder.neg();
if (is_neg() != other.is_neg()) quotient = quotient.neg();
if (is_neg()) remainder = remainder.neg();
return {quotient.template trunc<Bits>(), remainder.template trunc<Bits>()};
}
};
@ -941,6 +941,55 @@ struct metadata {
assert(value_type == DOUBLE);
return double_value;
}
// Internal CXXRTL use only.
static std::map<std::string, metadata> deserialize(const char *ptr) {
std::map<std::string, metadata> result;
std::string name;
// Grammar:
// string ::= [^\0]+ \0
// metadata ::= [uid] .{8} | s <string>
// map ::= ( <string> <metadata> )* \0
for (;;) {
if (*ptr) {
name += *ptr++;
} else if (!name.empty()) {
ptr++;
auto get_u64 = [&]() {
uint64_t result = 0;
for (size_t count = 0; count < 8; count++)
result = (result << 8) | *ptr++;
return result;
};
char type = *ptr++;
if (type == 'u') {
uint64_t value = get_u64();
result.emplace(name, value);
} else if (type == 'i') {
int64_t value = (int64_t)get_u64();
result.emplace(name, value);
} else if (type == 'd') {
double dvalue;
uint64_t uvalue = get_u64();
static_assert(sizeof(dvalue) == sizeof(uvalue), "double must be 64 bits in size");
memcpy(&dvalue, &uvalue, sizeof(dvalue));
result.emplace(name, dvalue);
} else if (type == 's') {
std::string value;
while (*ptr)
value += *ptr++;
ptr++;
result.emplace(name, value);
} else {
assert(false && "Unknown type specifier");
return result;
}
name.clear();
} else {
return result;
}
}
}
};
typedef std::map<std::string, metadata> metadata_map;
@ -1010,22 +1059,24 @@ struct observer {
// Default member initializers would make this a non-aggregate-type in C++11, so they are commented out.
struct fmt_part {
enum {
STRING = 0,
LITERAL = 0,
INTEGER = 1,
CHARACTER = 2,
VLOG_TIME = 3,
STRING = 2,
UNICHAR = 3,
VLOG_TIME = 4,
} type;
// STRING type
// LITERAL type
std::string str;
// INTEGER/CHARACTER types
// INTEGER/STRING/UNICHAR types
// + value<Bits> val;
// INTEGER/CHARACTER/VLOG_TIME types
// INTEGER/STRING/VLOG_TIME types
enum {
RIGHT = 0,
LEFT = 1,
NUMERIC = 2,
} justify; // = RIGHT;
char padding; // = '\0';
size_t width; // = 0;
@ -1033,7 +1084,14 @@ struct fmt_part {
// INTEGER type
unsigned base; // = 10;
bool signed_; // = false;
bool plus; // = false;
enum {
MINUS = 0,
PLUS_MINUS = 1,
SPACE_MINUS = 2,
} sign; // = MINUS;
bool hex_upper; // = false;
bool show_base; // = false;
bool group; // = false;
// VLOG_TIME type
bool realtime; // = false;
@ -1049,11 +1107,12 @@ struct fmt_part {
// We might want to replace some of these bit() calls with direct
// chunk access if it turns out to be slow enough to matter.
std::string buf;
std::string prefix;
switch (type) {
case STRING:
case LITERAL:
return str;
case CHARACTER: {
case STRING: {
buf.reserve(Bits/8);
for (int i = 0; i < Bits; i += 8) {
char ch = 0;
@ -1067,35 +1126,76 @@ struct fmt_part {
break;
}
case UNICHAR: {
uint32_t codepoint = val.template get<uint32_t>();
if (codepoint >= 0x10000)
buf += (char)(0xf0 | (codepoint >> 18));
else if (codepoint >= 0x800)
buf += (char)(0xe0 | (codepoint >> 12));
else if (codepoint >= 0x80)
buf += (char)(0xc0 | (codepoint >> 6));
else
buf += (char)codepoint;
if (codepoint >= 0x10000)
buf += (char)(0x80 | ((codepoint >> 12) & 0x3f));
if (codepoint >= 0x800)
buf += (char)(0x80 | ((codepoint >> 6) & 0x3f));
if (codepoint >= 0x80)
buf += (char)(0x80 | ((codepoint >> 0) & 0x3f));
break;
}
case INTEGER: {
size_t width = Bits;
bool negative = signed_ && val.is_neg();
if (negative) {
prefix = "-";
val = val.neg();
} else {
switch (sign) {
case MINUS: break;
case PLUS_MINUS: prefix = "+"; break;
case SPACE_MINUS: prefix = " "; break;
}
}
size_t val_width = Bits;
if (base != 10) {
width = 0;
val_width = 1;
for (size_t index = 0; index < Bits; index++)
if (val.bit(index))
width = index + 1;
val_width = index + 1;
}
if (base == 2) {
for (size_t i = width; i > 0; i--)
buf += (val.bit(i - 1) ? '1' : '0');
if (show_base)
prefix += "0b";
for (size_t index = 0; index < val_width; index++) {
if (group && index > 0 && index % 4 == 0)
buf += '_';
buf += (val.bit(index) ? '1' : '0');
}
} else if (base == 8 || base == 16) {
if (show_base)
prefix += (base == 16) ? (hex_upper ? "0X" : "0x") : "0o";
size_t step = (base == 16) ? 4 : 3;
for (size_t index = 0; index < width; index += step) {
for (size_t index = 0; index < val_width; index += step) {
if (group && index > 0 && index % (4 * step) == 0)
buf += '_';
uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2);
if (step == 4)
value |= val.bit(index + 3) << 3;
buf += "0123456789abcdef"[value];
buf += (hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[value];
}
std::reverse(buf.begin(), buf.end());
} else if (base == 10) {
bool negative = signed_ && val.is_neg();
if (negative)
val = val.neg();
if (show_base)
prefix += "0d";
if (val.is_zero())
buf += '0';
value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>();
size_t index = 0;
while (!xval.is_zero()) {
if (group && index > 0 && index % 3 == 0)
buf += '_';
value<(Bits > 4 ? Bits : 4)> quotient, remainder;
if (Bits >= 4)
std::tie(quotient, remainder) = xval.udivmod(value<(Bits > 4 ? Bits : 4)>{10u});
@ -1103,11 +1203,18 @@ struct fmt_part {
std::tie(quotient, remainder) = std::make_pair(value<(Bits > 4 ? Bits : 4)>{0u}, xval);
buf += '0' + remainder.template trunc<4>().template get<uint8_t>();
xval = quotient;
index++;
}
if (negative || plus)
buf += negative ? '-' : '+';
std::reverse(buf.begin(), buf.end());
} else assert(false && "Unsupported base for fmt_part");
if (justify == NUMERIC && group && padding == '0') {
int group_size = base == 10 ? 3 : 4;
while (prefix.size() + buf.size() < width) {
if (buf.size() % (group_size + 1) == group_size)
buf += '_';
buf += '0';
}
}
std::reverse(buf.begin(), buf.end());
break;
}
@ -1123,17 +1230,29 @@ struct fmt_part {
std::string str;
assert(width == 0 || padding != '\0');
if (justify == RIGHT && buf.size() < width) {
size_t pad_width = width - buf.size();
if (padding == '0' && (buf.front() == '+' || buf.front() == '-')) {
str += buf.front();
buf.erase(0, 1);
}
str += std::string(pad_width, padding);
if (prefix.size() + buf.size() < width) {
size_t pad_width = width - prefix.size() - buf.size();
switch (justify) {
case LEFT:
str += prefix;
str += buf;
str += std::string(pad_width, padding);
break;
case RIGHT:
str += std::string(pad_width, padding);
str += prefix;
str += buf;
break;
case NUMERIC:
str += prefix;
str += std::string(pad_width, padding);
str += buf;
break;
}
} else {
str += prefix;
str += buf;
}
str += buf;
if (justify == LEFT && buf.size() < width)
str += std::string(width - buf.size(), padding);
return str;
}
};
@ -1347,6 +1466,12 @@ struct debug_items {
});
}
// This overload exists to reduce excessive stack slot allocation in `CXXRTL_EXTREMELY_COLD void debug_info()`.
template<class... T>
void add(const std::string &base_path, const char *path, const char *serialized_item_attrs, T&&... args) {
add(base_path + path, debug_item(std::forward<T>(args)...), metadata::deserialize(serialized_item_attrs));
}
size_t count(const std::string &path) const {
if (table.count(path) == 0)
return 0;
@ -1393,6 +1518,11 @@ struct debug_scopes {
scope.cell_attrs = std::unique_ptr<debug_attrs>(new debug_attrs { cell_attrs });
}
// This overload exists to reduce excessive stack slot allocation in `CXXRTL_EXTREMELY_COLD void debug_info()`.
void add(const std::string &base_path, const char *path, const char *module_name, const char *serialized_module_attrs, const char *serialized_cell_attrs) {
add(base_path + path, module_name, metadata::deserialize(serialized_module_attrs), metadata::deserialize(serialized_cell_attrs));
}
size_t contains(const std::string &path) const {
return table.count(path);
}

View File

@ -512,9 +512,10 @@ public:
spool &operator=(const spool &) = delete;
~spool() {
if (int fd = writefd.exchange(-1))
int fd;
if ((fd = writefd.exchange(-1)) != -1)
close(fd);
if (int fd = readfd.exchange(-1))
if ((fd = readfd.exchange(-1)) != -1)
close(fd);
}

View File

@ -199,7 +199,6 @@ def help():
--minimize-assumes
when using --track-assumes, solve for a minimal set of sufficient assumptions.
""" + so.helpmsg())
def usage():
@ -670,18 +669,12 @@ if aimfile is not None:
ywfile_hierwitness_cache = None
def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False):
def ywfile_hierwitness():
global ywfile_hierwitness_cache
if map_steps is None:
map_steps = {}
if ywfile_hierwitness_cache is None:
ywfile_hierwitness = smt.hierwitness(topmod, allregs=True, blackbox=True)
with open(inywfile, "r") as f:
inyw = ReadWitness(f)
if ywfile_hierwitness_cache is None:
ywfile_hierwitness_cache = smt.hierwitness(topmod, allregs=True, blackbox=True)
inits, seqs, clocks, mems = ywfile_hierwitness_cache
inits, seqs, clocks, mems = ywfile_hierwitness
smt_wires = defaultdict(list)
smt_mems = defaultdict(list)
@ -692,9 +685,128 @@ def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False):
for mem in mems:
smt_mems[mem["path"]].append(mem)
addr_re = re.compile(r'\\\[[0-9]+\]$')
bits_re = re.compile(r'[01?]*$')
ywfile_hierwitness_cache = inits, seqs, clocks, mems, smt_wires, smt_mems
return ywfile_hierwitness_cache
def_bits_re = re.compile(r'([01]+)')
def smt_extract_mask(smt_expr, mask):
chunks = []
def_bits = ''
mask_index_order = mask[::-1]
for matched in def_bits_re.finditer(mask_index_order):
chunks.append(matched.span())
def_bits += matched[0]
if not chunks:
return
if len(chunks) == 1:
start, end = chunks[0]
if start == 0 and end == len(mask_index_order):
combined_chunks = smt_expr
else:
combined_chunks = '((_ extract %d %d) %s)' % (end - 1, start, smt_expr)
else:
combined_chunks = '(let ((x %s)) (concat %s))' % (smt_expr, ' '.join(
'((_ extract %d %d) x)' % (end - 1, start)
for start, end in reversed(chunks)
))
return combined_chunks, ''.join(mask_index_order[start:end] for start, end in chunks)[::-1]
def smt_concat(exprs):
if not exprs:
return ""
if len(exprs) == 1:
return exprs[1]
return "(concat %s)" % ' '.join(exprs)
def ywfile_signal(sig, step, mask=None):
assert sig.width > 0
inits, seqs, clocks, mems, smt_wires, smt_mems = ywfile_hierwitness()
sig_end = sig.offset + sig.width
output = []
if sig.path in smt_wires:
for wire in smt_wires[sig.path]:
width, offset = wire["width"], wire["offset"]
smt_bool = smt.net_width(topmod, wire["smtpath"]) == 1
offset = max(offset, 0)
end = width + offset
common_offset = max(sig.offset, offset)
common_end = min(sig_end, end)
if common_end <= common_offset:
continue
smt_expr = smt.witness_net_expr(topmod, f"s{step}", wire)
if not smt_bool:
slice_high = common_end - offset - 1
slice_low = common_offset - offset
smt_expr = "((_ extract %d %d) %s)" % (slice_high, slice_low, smt_expr)
else:
smt_expr = "(ite %s #b1 #b0)" % smt_expr
output.append(((common_offset - sig.offset), (common_end - sig.offset), smt_expr))
if sig.memory_path:
if sig.memory_path in smt_mems:
for mem in smt_mems[sig.memory_path]:
width, size, bv = mem["width"], mem["size"], mem["statebv"]
smt_expr = smt.net_expr(topmod, f"s{step}", mem["smtpath"])
if bv:
word_low = sig.memory_addr * width
word_high = word_low + width - 1
smt_expr = "((_ extract %d %d) %s)" % (word_high, word_low, smt_expr)
else:
addr_width = (size - 1).bit_length()
addr_bits = f"{sig.memory_addr:0{addr_width}b}"
smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits)
if sig.width < width:
slice_high = sig.offset + sig.width - 1
smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr)
output.append((0, sig.width, smt_expr))
output.sort()
output = [chunk for chunk in output if chunk[0] != chunk[1]]
pos = 0
for start, end, smt_expr in output:
assert start == pos
pos = end
assert pos == sig.width
if len(output) == 1:
return output[0][-1]
return smt_concat(smt_expr for start, end, smt_expr in reversed(output))
def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False):
global ywfile_hierwitness_cache
if map_steps is None:
map_steps = {}
with open(inywfile, "r") as f:
inyw = ReadWitness(f)
inits, seqs, clocks, mems, smt_wires, smt_mems = ywfile_hierwitness()
bits_re = re.compile(r'[01?]*$')
max_t = -1
for t, step in inyw.steps():
@ -706,77 +818,14 @@ def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False):
if not bits_re.match(bits):
raise ValueError("unsupported bit value in Yosys witness file")
sig_end = sig.offset + len(bits)
if sig.path in smt_wires:
for wire in smt_wires[sig.path]:
width, offset = wire["width"], wire["offset"]
smt_expr = ywfile_signal(sig, map_steps.get(t, t))
smt_bool = smt.net_width(topmod, wire["smtpath"]) == 1
smt_expr, bits = smt_extract_mask(smt_expr, bits)
offset = max(offset, 0)
smt_constr = "(= %s #b%s)" % (smt_expr, bits)
constr_assumes[t].append((inywfile, smt_constr))
end = width + offset
common_offset = max(sig.offset, offset)
common_end = min(sig_end, end)
if common_end <= common_offset:
continue
smt_expr = smt.witness_net_expr(topmod, f"s{map_steps.get(t, t)}", wire)
if not smt_bool:
slice_high = common_end - offset - 1
slice_low = common_offset - offset
smt_expr = "((_ extract %d %d) %s)" % (slice_high, slice_low, smt_expr)
bit_slice = bits[len(bits) - (common_end - sig.offset):len(bits) - (common_offset - sig.offset)]
if bit_slice.count("?") == len(bit_slice):
continue
if smt_bool:
assert width == 1
smt_constr = "(= %s %s)" % (smt_expr, "true" if bit_slice == "1" else "false")
else:
if "?" in bit_slice:
mask = bit_slice.replace("0", "1").replace("?", "0")
bit_slice = bit_slice.replace("?", "0")
smt_expr = "(bvand %s #b%s)" % (smt_expr, mask)
smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice)
constr_assumes[t].append((inywfile, smt_constr))
if sig.memory_path:
if sig.memory_path in smt_mems:
for mem in smt_mems[sig.memory_path]:
width, size, bv = mem["width"], mem["size"], mem["statebv"]
smt_expr = smt.net_expr(topmod, f"s{map_steps.get(t, t)}", mem["smtpath"])
if bv:
word_low = sig.memory_addr * width
word_high = word_low + width - 1
smt_expr = "((_ extract %d %d) %s)" % (word_high, word_low, smt_expr)
else:
addr_width = (size - 1).bit_length()
addr_bits = f"{sig.memory_addr:0{addr_width}b}"
smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits)
if len(bits) < width:
slice_high = sig.offset + len(bits) - 1
smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr)
bit_slice = bits
if "?" in bit_slice:
mask = bit_slice.replace("0", "1").replace("?", "0")
bit_slice = bit_slice.replace("?", "0")
smt_expr = "(bvand %s #b%s)" % (smt_expr, mask)
smt_constr = "(= %s #b%s)" % (smt_expr, bit_slice)
constr_assumes[t].append((inywfile, smt_constr))
max_t = t
return max_t
if inywfile is not None:
@ -1367,11 +1416,11 @@ def write_yw_trace(steps, index, allregs=False, filename=None):
exprs.extend(smt.witness_net_expr(topmod, f"s{k}", sig) for sig in sigs)
all_sigs.append(sigs)
all_sigs.append((step_values, sigs))
bvs = iter(smt.get_list(exprs))
for sigs in all_sigs:
for (step_values, sigs) in all_sigs:
for sig in sigs:
value = smt.bv2bin(next(bvs))
step_values[sig["sig"]] = value

View File

@ -1,7 +1,7 @@
from collections import defaultdict
import json
import typing
from functools import partial
import ywio
if typing.TYPE_CHECKING:
import smtbmc
@ -34,6 +34,7 @@ class Incremental:
self._witness_index = None
self._yw_constraints = {}
self._define_sorts = {}
def setup(self):
generic_assert_map = smtbmc.get_assert_map(
@ -175,11 +176,7 @@ class Incremental:
if len(expr) == 1:
smt_out.push({"and": "true", "or": "false"}[expr[0]])
elif len(expr) == 2:
arg_sort = self.expr(expr[1], smt_out)
if arg_sort != "Bool":
raise InteractiveError(
f"arguments of {json.dumps(expr[0])} must have sort Bool"
)
self.expr(expr[1], smt_out, required_sort="Bool")
else:
sep = f"({expr[0]} "
for arg in expr[1:]:
@ -189,7 +186,51 @@ class Incremental:
smt_out.append(")")
return "Bool"
def expr_bv_binop(self, expr, smt_out):
self.expr_arg_len(expr, 2)
smt_out.append(f"({expr[0]} ")
arg_sort = self.expr(expr[1], smt_out, required_sort=("BitVec", None))
smt_out.append(" ")
self.expr(expr[2], smt_out, required_sort=arg_sort)
smt_out.append(")")
return arg_sort
def expr_extract(self, expr, smt_out):
self.expr_arg_len(expr, 3)
hi = expr[1]
lo = expr[2]
smt_out.append(f"((_ extract {hi} {lo}) ")
arg_sort = self.expr(expr[3], smt_out, required_sort=("BitVec", None))
smt_out.append(")")
if not (isinstance(hi, int) and 0 <= hi < arg_sort[1]):
raise InteractiveError(
f"high bit index must be 0 <= index < {arg_sort[1]}, is {hi!r}"
)
if not (isinstance(lo, int) and 0 <= lo <= hi):
raise InteractiveError(
f"low bit index must be 0 <= index < {hi}, is {lo!r}"
)
return "BitVec", hi - lo + 1
def expr_bv(self, expr, smt_out):
self.expr_arg_len(expr, 1)
arg = expr[1]
if not isinstance(arg, str) or arg.count("0") + arg.count("1") != len(arg):
raise InteractiveError("bv argument must contain only 0 or 1 bits")
smt_out.append("#b" + arg)
return "BitVec", len(arg)
def expr_yw(self, expr, smt_out):
self.expr_arg_len(expr, 1, 2)
if len(expr) == 2:
name = None
step = expr[1]
@ -219,6 +260,40 @@ class Incremental:
return "Bool"
def expr_yw_sig(self, expr, smt_out):
self.expr_arg_len(expr, 3, 4)
step = expr[1]
path = expr[2]
offset = expr[3]
width = expr[4] if len(expr) == 5 else 1
if not isinstance(offset, int) or offset < 0:
raise InteractiveError(
f"offset must be a non-negative integer, got {json.dumps(offset)}"
)
if not isinstance(width, int) or width <= 0:
raise InteractiveError(
f"width must be a positive integer, got {json.dumps(width)}"
)
if not isinstance(path, list) or not all(isinstance(s, str) for s in path):
raise InteractiveError(
f"path must be a string list, got {json.dumps(path)}"
)
if step not in self.state_set:
raise InteractiveError(f"step {step} not declared")
smt_expr = smtbmc.ywfile_signal(
ywio.WitnessSig(path=path, offset=offset, width=width), step
)
smt_out.append(smt_expr)
return "BitVec", width
def expr_smtlib(self, expr, smt_out):
self.expr_arg_len(expr, 2)
@ -231,10 +306,15 @@ class Incremental:
f"got {json.dumps(smtlib_expr)}"
)
if not isinstance(sort, str):
raise InteractiveError(
f"raw SMT-LIB sort has to be a string, got {json.dumps(sort)}"
)
if (
isinstance(sort, list)
and len(sort) == 2
and sort[0] == "BitVec"
and (sort[1] is None or isinstance(sort[1], int))
):
sort = tuple(sort)
elif not isinstance(sort, str):
raise InteractiveError(f"unsupported raw SMT-LIB sort {json.dumps(sort)}")
smt_out.append(smtlib_expr)
return sort
@ -258,6 +338,14 @@ class Incremental:
return sort
def expr_def(self, expr, smt_out):
self.expr_arg_len(expr, 1)
sort = self._define_sorts.get(expr[1])
if sort is None:
raise InteractiveError(f"unknown definition {json.dumps(expr)}")
smt_out.append(expr[1])
return sort
expr_handlers = {
"step": expr_step,
"cell": expr_cell,
@ -270,8 +358,15 @@ class Incremental:
"not": expr_not,
"and": expr_andor,
"or": expr_andor,
"bv": expr_bv,
"bvand": expr_bv_binop,
"bvor": expr_bv_binop,
"bvxor": expr_bv_binop,
"extract": expr_extract,
"def": expr_def,
"=": expr_eq,
"yw": expr_yw,
"yw_sig": expr_yw_sig,
"smtlib": expr_smtlib,
"!": expr_label,
}
@ -305,10 +400,13 @@ class Incremental:
raise InteractiveError(f"unknown expression {json.dumps(expr[0])}")
def expr_smt(self, expr, required_sort):
return self.expr_smt_and_sort(expr, required_sort)[0]
def expr_smt_and_sort(self, expr, required_sort=None):
smt_out = []
self.expr(expr, smt_out, required_sort=required_sort)
output_sort = self.expr(expr, smt_out, required_sort=required_sort)
out = "".join(smt_out)
return out
return out, output_sort
def cmd_new_step(self, cmd):
step = self.arg_step(cmd, declare=True)
@ -338,7 +436,6 @@ class Incremental:
expr = cmd.get("expr")
key = cmd.get("key")
key = mkkey(key)
result = smtbmc.smt.smt2_assumptions.pop(key, None)
@ -348,7 +445,7 @@ class Incremental:
return result
def cmd_get_unsat_assumptions(self, cmd):
return smtbmc.smt.get_unsat_assumptions(minimize=bool(cmd.get('minimize')))
return smtbmc.smt.get_unsat_assumptions(minimize=bool(cmd.get("minimize")))
def cmd_push(self, cmd):
smtbmc.smt_push()
@ -370,6 +467,27 @@ class Incremental:
if response:
return smtbmc.smt.read()
def cmd_define(self, cmd):
expr = cmd.get("expr")
if expr is None:
raise InteractiveError("'define' copmmand requires 'expr' parameter")
expr, sort = self.expr_smt_and_sort(expr)
if isinstance(sort, tuple) and sort[0] == "module":
raise InteractiveError("'define' does not support module sorts")
define_name = f"|inc def {len(self._define_sorts)}|"
self._define_sorts[define_name] = sort
if isinstance(sort, tuple):
sort = f"(_ {' '.join(map(str, sort))})"
smtbmc.smt.write(f"(define-const {define_name} {sort} {expr})")
return {"name": define_name}
def cmd_design_hierwitness(self, cmd=None):
allregs = (cmd is None) or bool(cmd.get("allreges", False))
if self._cached_hierwitness[allregs] is not None:
@ -451,6 +569,7 @@ class Incremental:
"pop": cmd_pop,
"check": cmd_check,
"smtlib": cmd_smtlib,
"define": cmd_define,
"design_hierwitness": cmd_design_hierwitness,
"write_yw_trace": cmd_write_yw_trace,
"read_yw_trace": cmd_read_yw_trace,

View File

@ -160,6 +160,7 @@ class SmtIo:
self.noincr = opts.noincr
self.info_stmts = opts.info_stmts
self.nocomments = opts.nocomments
self.smt2_options.update(opts.smt2_options)
else:
self.solver = "yices"
@ -959,6 +960,8 @@ class SmtIo:
return int(self.bv2bin(v), 2)
def get_raw_unsat_assumptions(self):
if not self.smt2_assumptions:
return []
self.write("(get-unsat-assumptions)")
exprs = set(self.unparse(part) for part in self.parse(self.read()))
unsat_assumptions = []
@ -973,6 +976,10 @@ class SmtIo:
def get_unsat_assumptions(self, minimize=False):
if not minimize:
return self.get_raw_unsat_assumptions()
orig_assumptions = self.smt2_assumptions
self.smt2_assumptions = dict(orig_assumptions)
required_assumptions = {}
while True:
@ -998,6 +1005,7 @@ class SmtIo:
required_assumptions[candidate_key] = candidate_assume
if candidate_assumptions is not None:
self.smt2_assumptions = orig_assumptions
return list(required_assumptions)
def get(self, expr):
@ -1146,7 +1154,7 @@ class SmtIo:
class SmtOpts:
def __init__(self):
self.shortopts = "s:S:v"
self.longopts = ["unroll", "noincr", "noprogress", "timeout=", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"]
self.longopts = ["unroll", "noincr", "noprogress", "timeout=", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments", "smt2-option="]
self.solver = "yices"
self.solver_opts = list()
self.debug_print = False
@ -1159,6 +1167,7 @@ class SmtOpts:
self.logic = None
self.info_stmts = list()
self.nocomments = False
self.smt2_options = {}
def handle(self, o, a):
if o == "-s":
@ -1185,6 +1194,13 @@ class SmtOpts:
self.info_stmts.append(a)
elif o == "--nocomments":
self.nocomments = True
elif o == "--smt2-option":
args = a.split('=', 1)
if len(args) != 2:
print("--smt2-option expects an <option>=<value> argument")
sys.exit(1)
option, value = args
self.smt2_options[option] = value
else:
return False
return True
@ -1208,6 +1224,9 @@ class SmtOpts:
if solver is "dummy", read solver output from that file
otherwise: write solver output to that file
--smt2-option <option>=<value>
enable an SMT-LIBv2 option.
-v
enable debug output

View File

@ -1070,7 +1070,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf(";\n");
return true;
}
if (cell->type == ID($_BUF_)) {
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort(ID::Y));
@ -2014,22 +2014,29 @@ void dump_sync_effect(std::ostream &f, std::string indent, const RTLIL::SigSpec
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{
if (simple_lhs) {
bool all_chunks_wires = true;
for (auto &chunk : left.chunks())
if (chunk.is_wire() && reg_wires.count(chunk.wire->name))
all_chunks_wires = false;
if (!simple_lhs && all_chunks_wires) {
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, left);
f << stringf(" = ");
dump_sigspec(f, right);
f << stringf(";\n");
} else {
int offset = 0;
for (auto &chunk : left.chunks()) {
f << stringf("%s" "assign ", indent.c_str());
if (chunk.is_wire() && reg_wires.count(chunk.wire->name))
f << stringf("%s" "always%s\n%s ", indent.c_str(), systemverilog ? "_comb" : " @*", indent.c_str());
else
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, chunk);
f << stringf(" = ");
dump_sigspec(f, right.extract(offset, GetSize(chunk)));
f << stringf(";\n");
offset += GetSize(chunk);
}
} else {
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, left);
f << stringf(" = ");
dump_sigspec(f, right);
f << stringf(";\n");
}
}
@ -2276,11 +2283,15 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
active_initdata[sig[i]] = val[i];
}
if (!module->processes.empty())
log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
"can't always be mapped directly to Verilog always blocks. Unintended\n"
"changes in simulation behavior are possible! Use \"proc\" to convert\n"
"processes to logic networks and registers.\n", log_id(module));
bool has_sync_rules = false;
for (auto process : module->processes)
if (!process.second->syncs.empty())
has_sync_rules = true;
if (has_sync_rules)
log_warning("Module %s contains RTLIL processes with sync rules. Such RTLIL "
"processes can't always be mapped directly to Verilog always blocks. "
"unintended changes in simulation behavior are possible! Use \"proc\" "
"to convert processes to logic networks and registers.\n", log_id(module));
f << stringf("\n");
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)

2
docs/.gitignore vendored
View File

@ -1,6 +1,6 @@
/build/
/source/cmd
/source/temp
/source/generated
/source/_images/**/*.log
/source/_images/**/*.aux
/source/_images/**/*.pdf

View File

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

View File

@ -24,3 +24,17 @@ a.external {
th {
text-align: left;
}
body[data-theme="dark"] {
.invert-helper {
filter: url("data:image/svg+xml,<svg xmlns='http%3A//www.w3.org/2000/svg'><filter id='f'><feColorMatrix color-interpolation-filters='sRGB' type='matrix' values='1.47 -1.73 -0.467 0 0.867 -0.733 0.467 -0.467 0 0.867 -0.667 -1.07 1.07 0 0.867 0 0 0 1.0 0'></feColorMatrix></filter></svg>#f");
}
}
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) {
.invert-helper {
filter: url("data:image/svg+xml,<svg xmlns='http%3A//www.w3.org/2000/svg'><filter id='f'><feColorMatrix color-interpolation-filters='sRGB' type='matrix' values='1.47 -1.73 -0.467 0 0.867 -0.733 0.467 -0.467 0 0.867 -0.667 -1.07 1.07 0 0.867 0 0 0 1.0 0'></feColorMatrix></filter></svg>#f");
}
}
}

View File

@ -11,7 +11,7 @@ The ``yosys-config`` tool (an auto-generated shell-script) can be used to query
compiler options and other information needed for building loadable modules for
Yosys. See :doc:`/yosys_internals/extending_yosys/extensions` for details.
.. literalinclude:: /temp/yosys-config
.. literalinclude:: /generated/yosys-config
:start-at: Usage
.. _sec:filterlib:
@ -25,7 +25,7 @@ The ``yosys-filterlib`` tool is a small utility that can be used to strip or
extract information from a Liberty file. This can be useful for removing
sensitive or proprietary information such as timing or other trade secrets.
.. literalinclude:: /temp/yosys-filterlib
.. literalinclude:: /generated/yosys-filterlib
:start-at: Usage
yosys-abc
@ -36,9 +36,8 @@ been accepted upstream. Not all versions of Yosys work with all versions of ABC.
So Yosys comes with its own yosys-abc to avoid compatibility issues between the
two.
.. literalinclude:: /temp/yosys-abc
.. literalinclude:: /generated/yosys-abc
:start-at: usage
:end-before: UC Berkeley
yosys-smtbmc
------------
@ -46,7 +45,7 @@ yosys-smtbmc
The ``yosys-smtbmc`` tool is a utility used by SBY for interacting with smt
solvers.
.. literalinclude:: /temp/yosys-smtbmc
.. literalinclude:: /generated/yosys-smtbmc
yosys-witness
-------------
@ -55,7 +54,7 @@ yosys-witness
This is used in SBY and SCY for producing traces in a consistent format
independent of the solver.
.. literalinclude:: /temp/yosys-witness
.. literalinclude:: /generated/yosys-witness
:start-at: Usage
.. note:: ``yosys-witness`` requires `click`_ Python package for use.

View File

@ -24,7 +24,7 @@ circuit to a functionally equivalent low-level representation of a circuit.
abstraction and how they relate to different kinds of synthesis.
.. figure:: /_images/primer/basics_abstractions.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Basics_abstractions
Different levels of abstraction and synthesis.
@ -499,7 +499,7 @@ using a series of tools and the results are again verified using simulation.
This process is illustrated in :numref:`Fig. %s <fig:Basics_flow>`.
.. figure:: /_images/primer/basics_flow.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Basics_flow
Typical design flow. Green boxes represent manually created models.
@ -598,7 +598,7 @@ Let's consider the following BNF (in Bison syntax):
expr: TOK_IDENTIFIER | TOK_NUMBER | expr TOK_PLUS expr;
.. figure:: /_images/primer/basics_parsetree.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Basics_parsetree
Example parse tree for the Verilog expression
@ -627,7 +627,7 @@ suitable for further processing. In compilers this is often an assembler-like
three-address-code intermediate representation. :cite:p:`Dragonbook`
.. figure:: /_images/primer/basics_ast.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Basics_ast
Example abstract syntax tree for the Verilog expression

View File

@ -4,7 +4,7 @@
Command line reference
================================================================================
.. literalinclude:: /temp/yosys
.. literalinclude:: /generated/yosys
:start-at: Usage
.. toctree::

View File

@ -1,2 +1,3 @@
my_cmd.so
my_cmd.d
*.log

View File

@ -13,18 +13,18 @@ my_cmd.so: my_cmd.cc
$(YOSYS)-config --exec --cxx $(subst $(DATDIR),../../../../share,$(CXXFLAGS)) --ldflags -o my_cmd.so -shared my_cmd.cc --ldlibs
test0.log: my_cmd.so
$(YOSYS) -Ql test0.log_new -m ./my_cmd.so -p 'my_cmd foo bar' absval_ref.v
$(YOSYS) -QTl test0.log_new -m ./my_cmd.so -p 'my_cmd foo bar' -f verilog absval_ref.v
mv test0.log_new test0.log
test1.log: my_cmd.so
$(YOSYS) -Ql test1.log_new -m ./my_cmd.so -p 'clean; test1; dump' absval_ref.v
$(YOSYS) -QTl test1.log_new -m ./my_cmd.so -p 'clean; test1; dump' -f verilog absval_ref.v
mv test1.log_new test1.log
test1.dot: my_cmd.so
$(YOSYS) -m ./my_cmd.so -p 'test1; show -format dot -prefix test1'
test2.log: my_cmd.so
$(YOSYS) -Ql test2.log_new -m ./my_cmd.so -p 'hierarchy -top test; test2' sigmap_test.v
$(YOSYS) -QTl test2.log_new -m ./my_cmd.so -p 'hierarchy -top test; test2' -f verilog sigmap_test.v
mv test2.log_new test2.log
.PHONY: clean

View File

@ -4,7 +4,8 @@ import os
project = 'YosysHQ Yosys'
author = 'YosysHQ GmbH'
copyright ='2022 YosysHQ GmbH'
copyright ='2024 YosysHQ GmbH'
yosys_ver = "0.41"
# select HTML theme
html_theme = 'furo'
@ -46,12 +47,18 @@ extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex']
autosectionlabel_prefix_document = True
autosectionlabel_maxdepth = 1
# set version
if os.getenv("READTHEDOCS") and os.getenv("READTHEDOCS_VERSION") == "latest":
release = yosys_ver + "-dev"
else:
release = yosys_ver
# assign figure numbers
numfig = True
bibtex_bibfiles = ['literature.bib']
latex_elements = {
'releasename': 'Version',
'preamble': r'''
\usepackage{lmodern}
\usepackage{comment}

View File

@ -122,7 +122,7 @@ Since we're just getting started, let's instead begin with :yoscrypt:`hierarchy
Our ``addr_gen`` circuit now looks like this:
.. figure:: /_images/code_examples/fifo/addr_gen_hier.*
:class: width-helper
:class: width-helper invert-helper
:name: addr_gen_hier
``addr_gen`` module after :cmd:ref:`hierarchy`
@ -145,7 +145,7 @@ we run it. For now, we will call :yoscrypt:`proc -noopt` to prevent some
automatic optimizations which would normally happen.
.. figure:: /_images/code_examples/fifo/addr_gen_proc.*
:class: width-helper
:class: width-helper invert-helper
:name: addr_gen_proc
``addr_gen`` module after :yoscrypt:`proc -noopt`
@ -166,7 +166,7 @@ the same time by separating them with a colon and space: :yoscrypt:`opt_expr;
clean`.
.. figure:: /_images/code_examples/fifo/addr_gen_clean.*
:class: width-helper
:class: width-helper invert-helper
:name: addr_gen_clean
``addr_gen`` module after :yoscrypt:`opt_expr; clean`
@ -252,7 +252,7 @@ command only works with a single module, so you may need to call it with
:doc:`/getting_started/scripting_intro` has more on how to use :cmd:ref:`show`.
.. figure:: /_images/code_examples/fifo/rdata_proc.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_proc
``rdata`` output after :cmd:ref:`proc`
@ -298,7 +298,7 @@ optimizations between modules which would otherwise be missed. Let's run
:caption: output of :yoscrypt:`flatten;;`
.. figure:: /_images/code_examples/fifo/rdata_flat.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_flat
``rdata`` output after :yoscrypt:`flatten;;`
@ -385,7 +385,7 @@ options is able to fold one of the ``$mux`` cells into the ``$adff`` to form an
:caption: output of :cmd:ref:`opt_dff`
.. figure:: /_images/code_examples/fifo/rdata_adffe.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_adffe
``rdata`` output after :cmd:ref:`opt_dff`
@ -424,7 +424,7 @@ the schematic and see the output of that cell has now changed.
.. todo:: pending bugfix in :cmd:ref:`wreduce` and/or :cmd:ref:`opt_clean`
.. figure:: /_images/code_examples/fifo/rdata_wreduce.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_wreduce
``rdata`` output after :cmd:ref:`wreduce`
@ -446,7 +446,7 @@ Our next command to run is
:caption: output of :cmd:ref:`memory_dff`
.. figure:: /_images/code_examples/fifo/rdata_memrdv2.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_memrdv2
``rdata`` output after :cmd:ref:`memory_dff`
@ -535,7 +535,7 @@ example design:
:caption: output of :cmd:ref:`alumacc`
.. figure:: /_images/code_examples/fifo/rdata_alumacc.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_alumacc
``rdata`` output after :cmd:ref:`alumacc`
@ -553,7 +553,7 @@ operating on the same memory only in the abstract. :cmd:ref:`memory_collect`
combines all of the reads and writes for a memory block into a single cell.
.. figure:: /_images/code_examples/fifo/rdata_coarse.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_coarse
``rdata`` output after :cmd:ref:`memory_collect`
@ -604,7 +604,7 @@ Mapping to hard memory blocks uses a combination of :cmd:ref:`memory_libmap` and
:caption: ``map_ram`` section
.. figure:: /_images/code_examples/fifo/rdata_map_ram.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_map_ram
``rdata`` output after :ref:`map_ram`
@ -646,7 +646,7 @@ into flip flops (the ``logic fallback``) with :cmd:ref:`memory_map`.
:caption: ``map_ffram`` section
.. figure:: /_images/code_examples/fifo/rdata_map_ffram.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_map_ffram
``rdata`` output after :ref:`map_ffram`
@ -682,7 +682,7 @@ replaced with single-bit ``$_MUX_`` and ``$_DFFE_PP0P_`` cells, while the
:caption: ``map_gates`` section
.. figure:: /_images/code_examples/fifo/rdata_map_gates.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_map_gates
``rdata`` output after :ref:`map_gates`
@ -711,7 +711,7 @@ instead with an ``$_AND_`` cell.
:caption: ``map_ffs`` section
.. figure:: /_images/code_examples/fifo/rdata_map_ffs.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_map_ffs
``rdata`` output after :ref:`map_ffs`
@ -737,7 +737,7 @@ what the difference between these two commands are, refer to
:caption: ``map_luts`` section
.. figure:: /_images/code_examples/fifo/rdata_map_luts.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_map_luts
``rdata`` output after :ref:`map_luts`
@ -754,7 +754,7 @@ Finally we use :cmd:ref:`techmap` to map the generic ``$lut`` cells to iCE40
:caption: ``map_cells`` section
.. figure:: /_images/code_examples/fifo/rdata_map_cells.*
:class: width-helper
:class: width-helper invert-helper
:name: rdata_map_cells
``rdata`` output after :ref:`map_cells`

View File

@ -108,7 +108,7 @@ what the different symbols represent, see :ref:`interactive_show` and the
:doc:`/using_yosys/more_scripting/interactive_investigation` page.
.. figure:: /_images/code_examples/fifo/addr_gen_show.*
:class: width-helper
:class: width-helper invert-helper
:name: addr_gen_show
Calling :yoscrypt:`show addr_gen` after :cmd:ref:`hierarchy`
@ -158,7 +158,7 @@ selection<select_new_cells>` and called it ``new_cells``? We saw in the
``$eq``. We can call :cmd:ref:`show` on that selection just as easily:
.. figure:: /_images/code_examples/fifo/new_cells_show.*
:class: width-helper
:class: width-helper invert-helper
:name: new_cells_show
Calling :yoscrypt:`show -notitle @new_cells`
@ -173,7 +173,7 @@ the two ``PROC`` blocks. To achieve this highlight, we make use of the
:yoscrypt:`-color` option:
.. figure:: /_images/code_examples/fifo/addr_gen_hier.*
:class: width-helper
:class: width-helper invert-helper
Calling :yoscrypt:`show -color maroon3 @new_cells -color cornflowerblue p:* -notitle`

View File

@ -151,7 +151,7 @@ extensible and therefore is a good basis for implementing custom synthesis tools
for specialised tasks.
.. figure:: /_images/primer/levels_of_abstraction.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Levels_of_abstraction
Where Yosys exists in the layers of abstraction

View File

@ -56,7 +56,7 @@ is shown.
``xdot example_first.dot`` etc.
.. figure:: /_images/code_examples/show/example_first.*
:class: width-helper
:class: width-helper invert-helper
Output of the first :cmd:ref:`show` command in :numref:`example_ys`
@ -88,7 +88,7 @@ The :cmd:ref:`proc` command transforms the process from the first diagram into a
multiplexer and a d-type flip-flop, which brings us to the second diagram:
.. figure:: /_images/code_examples/show/example_second.*
:class: width-helper
:class: width-helper invert-helper
Output of the second :cmd:ref:`show` command in :numref:`example_ys`
@ -110,7 +110,7 @@ In this script we directly call :cmd:ref:`opt` as the next step, which finally
leads us to the third diagram:
.. figure:: /_images/code_examples/show/example_third.*
:class: width-helper
:class: width-helper invert-helper
:name: example_out
Output of the third :cmd:ref:`show` command in :ref:`example_ys`
@ -137,7 +137,7 @@ that operate on wide integers, it also introduces some additional complexity
when the individual bits of of a signal vector are accessed.
.. figure:: /_images/code_examples/show/splice.*
:class: width-helper
:class: width-helper invert-helper
:name: splice_dia
Output of ``yosys -p 'prep -top splice_demo; show' splice.v``
@ -165,7 +165,7 @@ Gate level netlists
mapped to a cell library:
.. figure:: /_images/code_examples/show/cmos_00.*
:class: width-helper
:class: width-helper invert-helper
:name: first_pitfall
A half-adder built from simple CMOS gates, demonstrating common pitfalls when
@ -185,7 +185,7 @@ column. Secondly the two-bit vector ``y`` requires breakout-boxes for its
individual bits, resulting in an unnecessary complex diagram.
.. figure:: /_images/code_examples/show/cmos_01.*
:class: width-helper
:class: width-helper invert-helper
:name: second_pitfall
Effects of :cmd:ref:`splitnets` command and of providing a cell library on
@ -358,10 +358,10 @@ reorganizing a module in Yosys and checking the resulting circuit.
:end-before: cd ..
.. figure:: /_images/code_examples/scrambler/scrambler_p01.*
:class: width-helper
:class: width-helper invert-helper
.. figure:: /_images/code_examples/scrambler/scrambler_p02.*
:class: width-helper
:class: width-helper invert-helper
Analyzing the resulting circuit with :doc:`/cmd/eval`:
@ -442,7 +442,7 @@ if the circuit under investigation is encapsulated in a separate module.
Recall the ``memdemo`` design from :ref:`advanced_logic_cones`:
.. figure:: /_images/code_examples/selections/memdemo_00.*
:class: width-helper
:class: width-helper invert-helper
``memdemo``
@ -463,18 +463,18 @@ name of the new cell in the current module. The resulting circuits are shown
below.
.. figure:: /_images/code_examples/selections/submod_02.*
:class: width-helper
:class: width-helper invert-helper
``outstage``
.. figure:: /_images/code_examples/selections/submod_03.*
:class: width-helper
:class: width-helper invert-helper
:name: selstage
``selstage``
.. figure:: /_images/code_examples/selections/submod_01.*
:class: width-helper
:class: width-helper invert-helper
``scramble``

View File

@ -160,7 +160,7 @@ Selecting ``a:sumstuff`` in this module will yield the following circuit
diagram:
.. figure:: /_images/code_examples/selections/sumprod_00.*
:class: width-helper
:class: width-helper invert-helper
:name: sumprod_00
Output of ``show a:sumstuff`` on :numref:`sumprod`
@ -177,7 +177,7 @@ selected wire it selects all cells connected to the wire and vice versa. So
:yoscrypt:`show a:sumstuff %x` yields the diagram shown in :numref:`sumprod_01`:
.. figure:: /_images/code_examples/selections/sumprod_01.*
:class: width-helper
:class: width-helper invert-helper
:name: sumprod_01
Output of ``show a:sumstuff %x`` on :numref:`sumprod`
@ -200,22 +200,22 @@ input ports.
The following sequence of diagrams demonstrates this step-wise expansion:
.. figure:: /_images/code_examples/selections/sumprod_02.*
:class: width-helper
:class: width-helper invert-helper
Output of :yoscrypt:`show prod` on :numref:`sumprod`
.. figure:: /_images/code_examples/selections/sumprod_03.*
:class: width-helper
:class: width-helper invert-helper
Output of :yoscrypt:`show prod %ci` on :numref:`sumprod`
.. figure:: /_images/code_examples/selections/sumprod_04.*
:class: width-helper
:class: width-helper invert-helper
Output of :yoscrypt:`show prod %ci %ci` on :numref:`sumprod`
.. figure:: /_images/code_examples/selections/sumprod_05.*
:class: width-helper
:class: width-helper invert-helper
Output of :yoscrypt:`show prod %ci %ci %ci` on :numref:`sumprod`
@ -280,7 +280,7 @@ provided :file:`memdemo.v` is in the same directory. We can now change to the
diagram in :numref:`memdemo_00`.
.. figure:: /_images/code_examples/selections/memdemo_00.*
:class: width-helper
:class: width-helper invert-helper
:name: memdemo_00
Complete circuit diagram for the design shown in :numref:`memdemo_src`
@ -291,7 +291,7 @@ output signal, ``y``, and its immediate predecessors. Remember `Selecting logic
cones`_ from above, we can use :yoscrypt:`show y %ci2`:
.. figure:: /_images/code_examples/selections/memdemo_01.*
:class: width-helper
:class: width-helper invert-helper
:name: memdemo_01
Output of :yoscrypt:`show y %ci2`
@ -303,7 +303,7 @@ wire into the input ``D`` of the flip-flop cell (indicated by the ``$`` at the
start of the name). Let's go a bit further now and try :yoscrypt:`show y %ci5`:
.. figure:: /_images/code_examples/selections/memdemo_02.*
:class: width-helper
:class: width-helper invert-helper
:name: memdemo_02
Output of :yoscrypt:`show y %ci5`
@ -317,7 +317,7 @@ brackets. In this case, we want to exclude the ``S`` port of the ``$mux`` cell
type with :yoscrypt:`show y %ci5:-$mux[S]`:
.. figure:: /_images/code_examples/selections/memdemo_03.*
:class: width-helper
:class: width-helper invert-helper
:name: memdemo_03
Output of :yoscrypt:`show y %ci5:-$mux[S]`
@ -328,7 +328,7 @@ flip-flop and the 2nd action selects the entire input cone without going over
multiplexer select inputs and flip-flop cells:
.. figure:: /_images/code_examples/selections/memdemo_05.*
:class: width-helper
:class: width-helper invert-helper
:name: memdemo_05
Output of ``show y %ci2:+$dff[Q,D] %ci*:-$mux[S]:-$dff``
@ -340,7 +340,7 @@ ignoring any ports named ``CLK`` or ``S``:
.. TODO:: pending discussion on whether rule ordering is a bug or a feature
.. figure:: /_images/code_examples/selections/memdemo_04.*
:class: width-helper
:class: width-helper invert-helper
:name: memdemo_04
Output of :yoscrypt:`show y %ci*:-[CLK,S]:+$dff,$mux`
@ -417,6 +417,6 @@ Example code from |code_examples/selections|_:
:name: select_ys
.. figure:: /_images/code_examples/selections/select.*
:class: width-helper
:class: width-helper invert-helper
Circuit diagram produced by :numref:`select_ys`

View File

@ -51,7 +51,7 @@ Loading the design
Our circuit now looks like this:
.. figure:: /_images/code_examples/intro/counter_00.*
:class: width-helper
:class: width-helper invert-helper
:name: counter-hierarchy
``counter`` after :cmd:ref:`hierarchy`
@ -66,7 +66,7 @@ Coarse-grain representation
:caption: :file:`counter.ys` - the high-level stuff
.. figure:: /_images/code_examples/intro/counter_01.*
:class: width-helper
:class: width-helper invert-helper
Coarse-grain representation of the ``counter`` module
@ -80,7 +80,7 @@ Logic gate mapping
:caption: :file:`counter.ys` - mapping to internal cell library
.. figure:: /_images/code_examples/intro/counter_02.*
:class: width-helper
:class: width-helper invert-helper
``counter`` after :cmd:ref:`techmap`
@ -111,7 +111,7 @@ Recall that the Yosys built-in logic gate types are ``$_NOT_``, ``$_AND_``,
The final version of our ``counter`` module looks like this:
.. figure:: /_images/code_examples/intro/counter_03.*
:class: width-helper
:class: width-helper invert-helper
``counter`` after hardware cell mapping

View File

@ -23,7 +23,7 @@ Example code can be found in |code_examples/macc|_.
:lines: 1-2
.. figure:: /_images/code_examples/macc/macc_simple_test_00a.*
:class: width-helper
:class: width-helper invert-helper
before :cmd:ref:`extract`
@ -32,7 +32,7 @@ Example code can be found in |code_examples/macc|_.
:lines: 6
.. figure:: /_images/code_examples/macc/macc_simple_test_00b.*
:class: width-helper
:class: width-helper invert-helper
after :cmd:ref:`extract`
@ -49,20 +49,20 @@ Example code can be found in |code_examples/macc|_.
:caption: :file:`macc_simple_test_01.v`
.. figure:: /_images/code_examples/macc/macc_simple_test_01a.*
:class: width-helper
:class: width-helper invert-helper
.. figure:: /_images/code_examples/macc/macc_simple_test_01b.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/macc/macc_simple_test_02.v
:language: verilog
:caption: :file:`macc_simple_test_02.v`
.. figure:: /_images/code_examples/macc/macc_simple_test_02a.*
:class: width-helper
:class: width-helper invert-helper
.. figure:: /_images/code_examples/macc/macc_simple_test_02b.*
:class: width-helper
:class: width-helper invert-helper
The wrap-extract-unwrap method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -149,10 +149,10 @@ Unwrapping adders: :file:`macc_xilinx_unwrap_map.v`
:caption: ``test1`` of :file:`macc_xilinx_test.v`
.. figure:: /_images/code_examples/macc/macc_xilinx_test1a.*
:class: width-helper
:class: width-helper invert-helper
.. figure:: /_images/code_examples/macc/macc_xilinx_test1b.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/macc/macc_xilinx_test.v
:language: verilog
@ -160,15 +160,15 @@ Unwrapping adders: :file:`macc_xilinx_unwrap_map.v`
:caption: ``test2`` of :file:`macc_xilinx_test.v`
.. figure:: /_images/code_examples/macc/macc_xilinx_test2a.*
:class: width-helper
:class: width-helper invert-helper
.. figure:: /_images/code_examples/macc/macc_xilinx_test2b.*
:class: width-helper
:class: width-helper invert-helper
Wrapping in ``test1``:
.. figure:: /_images/code_examples/macc/macc_xilinx_test1b.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
:language: yoscrypt
@ -176,12 +176,12 @@ Wrapping in ``test1``:
:end-before: end part c
.. figure:: /_images/code_examples/macc/macc_xilinx_test1c.*
:class: width-helper
:class: width-helper invert-helper
Wrapping in ``test2``:
.. figure:: /_images/code_examples/macc/macc_xilinx_test2b.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
:language: yoscrypt
@ -189,12 +189,12 @@ Wrapping in ``test2``:
:end-before: end part c
.. figure:: /_images/code_examples/macc/macc_xilinx_test2c.*
:class: width-helper
:class: width-helper invert-helper
Extract in ``test1``:
.. figure:: /_images/code_examples/macc/macc_xilinx_test1c.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
:language: yoscrypt
@ -202,12 +202,12 @@ Extract in ``test1``:
:end-before: end part d
.. figure:: /_images/code_examples/macc/macc_xilinx_test1d.*
:class: width-helper
:class: width-helper invert-helper
Extract in ``test2``:
.. figure:: /_images/code_examples/macc/macc_xilinx_test2c.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
:language: yoscrypt
@ -215,12 +215,12 @@ Extract in ``test2``:
:end-before: end part d
.. figure:: /_images/code_examples/macc/macc_xilinx_test2d.*
:class: width-helper
:class: width-helper invert-helper
Unwrap in ``test2``:
.. figure:: /_images/code_examples/macc/macc_xilinx_test2d.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
:language: yoscrypt
@ -228,4 +228,4 @@ Unwrap in ``test2``:
:end-before: end part e
.. figure:: /_images/code_examples/macc/macc_xilinx_test2e.*
:class: width-helper
:class: width-helper invert-helper

View File

@ -39,7 +39,7 @@ Example
.. _code_examples/synth_flow: https://github.com/YosysHQ/yosys/tree/main/docs/source/code_examples/synth_flow
.. figure:: /_images/code_examples/synth_flow/memory_01.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/synth_flow/memory_01.ys
:language: yoscrypt
@ -50,7 +50,7 @@ Example
:caption: :file:`memory_01.v`
.. figure:: /_images/code_examples/synth_flow/memory_02.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/synth_flow/memory_02.v
:language: verilog

View File

@ -88,7 +88,7 @@ trees can interfere with other optimizations.
:caption: example verilog for demonstrating :cmd:ref:`opt_expr`
.. figure:: /_images/code_examples/opt/opt_expr.*
:class: width-helper
:class: width-helper invert-helper
Before and after :cmd:ref:`opt_expr`
@ -111,7 +111,7 @@ possible optimizations.
:caption: example verilog for demonstrating :cmd:ref:`opt_merge`
.. figure:: /_images/code_examples/opt/opt_merge.*
:class: width-helper
:class: width-helper invert-helper
Before and after :cmd:ref:`opt_merge`
@ -133,7 +133,7 @@ detects this contradiction and replaces the inner multiplexer with a constant 1,
yielding the logic for ``y = a ? b : d``.
.. figure:: /_images/code_examples/opt/opt_muxtree.*
:class: width-helper
:class: width-helper invert-helper
Before and after :cmd:ref:`opt_muxtree`
@ -172,7 +172,7 @@ multiplexing its output to multiplexing the non-shared input signals.
:caption: example verilog for demonstrating :cmd:ref:`opt_share`
.. figure:: /_images/code_examples/opt/opt_share.*
:class: width-helper
:class: width-helper invert-helper
Before and after :cmd:ref:`opt_share`

View File

@ -42,10 +42,10 @@ Example
:caption: :file:`proc_01.ys`
.. figure:: /_images/code_examples/synth_flow/proc_01.*
:class: width-helper
:class: width-helper invert-helper
.. figure:: /_images/code_examples/synth_flow/proc_02.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/synth_flow/proc_02.v
:language: verilog
@ -56,7 +56,7 @@ Example
:caption: :file:`proc_02.ys`
.. figure:: /_images/code_examples/synth_flow/proc_03.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/synth_flow/proc_03.ys
:language: yoscrypt

View File

@ -38,7 +38,7 @@ This document will focus on the much simpler version of RTLIL left after the
commands :cmd:ref:`proc` and :cmd:ref:`memory` (or :yoscrypt:`memory -nomap`):
.. figure:: /_images/internals/simplified_rtlil.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Simplified_RTLIL
Simplified RTLIL entity-relationship diagram without memories and processes
@ -140,7 +140,7 @@ We'll do the same as before and format it as a a ``Yosys::Pass``.
And if we look at the schematic for this new module we see the following:
.. figure:: /_images/code_examples/extensions/test1.*
:class: width-helper
:class: width-helper invert-helper
Output of ``yosys -m ./my_cmd.so -p 'test1; show'``

View File

@ -10,7 +10,7 @@ and generating the data for the next subsystem (see :numref:`Fig. %s
<fig:approach_flow>`).
.. figure:: /_images/internals/approach_flow.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:approach_flow
General data- and control-flow of a synthesis tool

View File

@ -42,7 +42,7 @@ possible it is key that (1) all passes operate on the same data structure
design in different stages of the synthesis.
.. figure:: /_images/internals/overview_flow.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Overview_flow
Yosys simplified data flow (ellipses: data structures, rectangles:

View File

@ -10,7 +10,7 @@ is then passed to the AST frontend that converts it to RTLIL data, as
illustrated in :numref:`Fig. %s <fig:Verilog_flow>`.
.. figure:: /_images/internals/verilog_flow.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Verilog_flow
Simplified Verilog to RTLIL data flow

View File

@ -619,6 +619,92 @@ Finite state machines
Add a brief description of the ``$fsm`` cell type.
Coarse arithmetics
~~~~~~~~~~~~~~~~~~~~~
The ``$macc`` cell type represents a generalized multiply and accumulate operation. The cell is purely combinational. It outputs the result of summing up a sequence of products and other injected summands.
.. code-block::
Y = 0 +- a0factor1 * a0factor2 +- a1factor1 * a1factor2 +- ...
+ B[0] + B[1] + ...
The A port consists of concatenated pairs of multiplier inputs ("factors").
A zero length factor2 acts as a constant 1, turning factor1 into a simple summand.
In this pseudocode, ``u(foo)`` means an unsigned int that's foo bits long.
.. code-block::
struct A {
u(CONFIG.mul_info[0].factor1_len) a0factor1;
u(CONFIG.mul_info[0].factor2_len) a0factor2;
u(CONFIG.mul_info[1].factor1_len) a1factor1;
u(CONFIG.mul_info[1].factor2_len) a1factor2;
...
};
The cell's ``CONFIG`` parameter determines the layout of cell port ``A``.
The CONFIG parameter carries the following information:
.. code-block::
struct CONFIG {
u4 num_bits;
struct mul_info {
bool is_signed;
bool is_subtract;
u(num_bits) factor1_len;
u(num_bits) factor2_len;
}[num_ports];
};
B is an array of concatenated 1-bit-wide unsigned integers to also be summed up.
Arbitrary logic functions
~~~~~~~~~~~~~~~~~~~~~~~~~
The ``$lut`` cell type implements a single-output LUT (lookup table).
It implements an arbitrary logic function with its ``\LUT`` parameter to map
input port ``\A`` to values of ``\Y`` output port values.
In psuedocode: ``Y = \LUT[A]``.
``\A`` has width set by parameter ``\WIDTH`` and ``\Y`` has a width of 1.
Every logic function with a single bit output has a unique ``$lut``
representation.
The ``$sop`` cell type implements a sum-of-products expression, also known
as disjunctive normal form (DNF). It implements an arbitrary logic function.
Its structure mimics a programmable logic array (PLA).
Output port ``\Y`` is the sum of products of the bits of the input port ``\A``
as defined by parameter ``\TABLE``. ``\A`` is ``\WIDTH`` bits wide.
The number of products in the sum is set by parameter ``\DEPTH``, and each
product has two bits for each input bit - for the presence of the
unnegated and negated version of said input bit in the product.
Therefore the ``\TABLE`` parameter holds ``2 * \WIDTH * \DEPTH`` bits.
For example:
Let ``\WIDTH`` be 3. We would like to represent ``\Y =~\A[0] + \A[1]~\A[2]``.
There are 2 products to be summed, so ``\DEPTH`` shall be 2.
.. code-block::
~A[2]-----+
A[2]----+|
~A[1]---+||
A[1]--+|||
~A[0]-+||||
A[0]+|||||
|||||| product formula
010000 ~\A[0]
001001 \A[1]~\A[2]
So the value of ``\TABLE`` will become ``010000001001``.
Any logic function with a single bit output can be represented with
``$sop`` but may have variously minimized or ordered summands represented
in the ``\TABLE`` values.
Specify rules
~~~~~~~~~~~~~
@ -1150,6 +1236,4 @@ file via ABC using the abc pass.
.. todo:: Add information about ``$slice`` and ``$concat`` cells.
.. todo:: Add information about ``$lut`` and ``$sop`` cells.
.. todo:: Add information about ``$alu``, ``$macc``, ``$fa``, and ``$lcu`` cells.
.. todo:: Add information about ``$alu``, ``$fa``, and ``$lcu`` cells.

View File

@ -24,7 +24,7 @@ create an additional ``RTLIL::Design`` object and call the Verilog frontend with
this other object to parse the cell library.
.. figure:: /_images/internals/overview_rtlil.*
:class: width-helper
:class: width-helper invert-helper
:name: fig:Overview_RTLIL
Simplified RTLIL Entity-Relationship Diagram

View File

@ -34,7 +34,7 @@ Mapping OR3X1
:caption: :file:`red_or3x1_map.v`
.. figure:: /_images/code_examples/techmap/red_or3x1.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/techmap/red_or3x1_test.ys
:language: yoscrypt
@ -61,7 +61,7 @@ Conditional techmap
Example:
.. figure:: /_images/code_examples/techmap/sym_mul.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/techmap/sym_mul_map.v
:language: verilog
@ -100,7 +100,7 @@ Scripting in map modules
Example:
.. figure:: /_images/code_examples/techmap/mymul.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/techmap/mymul_map.v
:language: verilog
@ -130,7 +130,7 @@ Handling constant inputs
Example:
.. figure:: /_images/code_examples/techmap/mulshift.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/techmap/mulshift_map.v
:language: verilog
@ -162,7 +162,7 @@ Handling shorted inputs
Example:
.. figure:: /_images/code_examples/techmap/addshift.*
:class: width-helper
:class: width-helper invert-helper
.. literalinclude:: /code_examples/techmap/addshift_map.v
:language: verilog

View File

@ -10,13 +10,14 @@ import sys
logging.basicConfig(level=logging.INFO)
# expects __file__ = yosys/docs/tests/macro_commands.py
TESTS_DIR = Path(__file__).parent
TESTS_DIR = Path(__file__).parent.absolute()
ROOT_DIR = TESTS_DIR.parent.parent
logging.log(logging.INFO, f"Using {ROOT_DIR} as root directory")
THIS_FILE = (TESTS_DIR / "macro_commands.py").relative_to(ROOT_DIR)
MACRO_SOURCE = TESTS_DIR.parent / "source" / "code_examples" / "macro_commands"
assert MACRO_SOURCE.exists(), f"can't find macro_commands in {MACRO_SOURCE}"
YOSYS = TESTS_DIR.parent.parent / "yosys"
YOSYS = ROOT_DIR / "yosys"
assert YOSYS.exists(), f"can't find yosys executable in {YOSYS}"
raise_error = False

61
flake.lock Normal file
View File

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1708807242,
"narHash": "sha256-sRTRkhMD4delO/hPxxi+XwLqPn8BuUq6nnj4JqLwOu0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "73de017ef2d18a04ac4bfd0c02650007ccb31c2a",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

48
flake.nix Normal file
View File

@ -0,0 +1,48 @@
{
description = "A nix flake for the Yosys synthesis suite";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
};
# TODO: don't override src when ./abc is empty
# which happens when the command used is `nix build` and not `nix build ?submodules=1`
abc-verifier = pkgs.abc-verifier.overrideAttrs(x: y: {src = ./abc;});
yosys = pkgs.clangStdenv.mkDerivation {
name = "yosys";
src = ./. ;
buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git pkg-configUpstream ];
checkInputs = with pkgs; [ gtest ];
propagatedBuildInputs = [ abc-verifier ];
preConfigure = "make config-clang";
checkTarget = "test";
installPhase = ''
make install PREFIX=$out ABCEXTERNAL=yosys-abc
ln -s ${abc-verifier}/bin/abc $out/bin/yosys-abc
'';
buildPhase = ''
make -j$(nproc) ABCEXTERNAL=yosys-abc
'';
meta = with pkgs.lib; {
description = "Yosys Open SYnthesis Suite";
homepage = "https://yosyshq.net/yosys/";
license = licenses.isc;
maintainers = with maintainers; [ ];
};
};
in {
packages.default = yosys;
defaultPackage = yosys;
devShell = pkgs.mkShell {
buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier ];
};
}
);
}

View File

@ -590,6 +590,7 @@ void AigerReader::parse_aiger_ascii()
for (unsigned i = 0; i < O; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count);
std::getline(f, line); // Ignore up to start of next line
log_debug2("%d is an output\n", l1);
RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i));
@ -597,20 +598,18 @@ void AigerReader::parse_aiger_ascii()
module->connect(wire, createWireIfNotExists(module, l1));
outputs.push_back(wire);
}
//std::getline(f, line); // Ignore up to start of next line
// Parse bad properties
for (unsigned i = 0; i < B; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
std::getline(f, line); // Ignore up to start of next line
log_debug2("%d is a bad state property\n", l1);
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_output = true;
bad_properties.push_back(wire);
}
//if (B > 0)
// std::getline(f, line); // Ignore up to start of next line
// TODO: Parse invariant constraints
for (unsigned i = 0; i < C; ++i, ++line_count)
@ -628,6 +627,7 @@ void AigerReader::parse_aiger_ascii()
for (unsigned i = 0; i < A; ++i) {
if (!(f >> l1 >> l2 >> l3))
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
std::getline(f, line); // Ignore up to start of next line
log_debug2("%d %d %d is an AND\n", l1, l2, l3);
log_assert(!(l1 & 1));
@ -636,7 +636,6 @@ void AigerReader::parse_aiger_ascii()
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
module->addAndGate("$and" + o_wire->name.str(), i1_wire, i2_wire, o_wire);
}
std::getline(f, line); // Ignore up to start of next line
}
static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
@ -715,6 +714,7 @@ void AigerReader::parse_aiger_binary()
for (unsigned i = 0; i < O; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count);
std::getline(f, line); // Ignore up to start of next line
log_debug2("%d is an output\n", l1);
RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i));
@ -722,20 +722,18 @@ void AigerReader::parse_aiger_binary()
module->connect(wire, createWireIfNotExists(module, l1));
outputs.push_back(wire);
}
std::getline(f, line); // Ignore up to start of next line
// Parse bad properties
for (unsigned i = 0; i < B; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
std::getline(f, line); // Ignore up to start of next line
log_debug2("%d is a bad state property\n", l1);
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_output = true;
bad_properties.push_back(wire);
}
if (B > 0)
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse invariant constraints
for (unsigned i = 0; i < C; ++i, ++line_count)

View File

@ -790,7 +790,7 @@ struct AST_INTERNAL::ProcessGenerator
Fmt fmt;
fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name);
if (ast->str.substr(0, 8) == "$display")
fmt.append_string("\n");
fmt.append_literal("\n");
fmt.emit_rtlil(cell);
} else if (!ast->str.empty()) {
log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str());
@ -2224,7 +2224,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
else
input_error("FATAL.\n");
} else {
input_error("Unknown elabortoon system task '%s'.\n", str.c_str());
input_error("Unknown elaboration system task '%s'.\n", str.c_str());
}
} break;

View File

@ -1079,7 +1079,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
// when $display()/$write() functions are used in an initial block, print them during synthesis
Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base, /*first_arg_at=*/0, /*may_fail=*/true);
if (str.substr(0, 8) == "$display")
fmt.append_string("\n");
fmt.append_literal("\n");
log("%s", fmt.render().c_str());
}

View File

@ -14,6 +14,7 @@ ifneq ($(DISABLE_VERIFIC_VHDL),1)
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2019/. share/verific.new/vhdl_vdbs_2019
endif
$(Q) chmod -R a+rX share/verific.new
$(Q) mv share/verific.new share/verific

View File

@ -214,23 +214,120 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj)
return s;
}
// When used as attributes or parameter values Verific constants come already processed.
// - Real string values are already under quotes
// - Numeric values with specified width are always converted to binary
// - Rest of user defined values are handled as 32bit integers
// - There could be some internal values that are strings without quotes
// so we check if value is all digits or not
//
// Note: For signed values, verific uses <len>'sb<bits> and decimal values can
// also be negative.
static const RTLIL::Const verific_const(const char *value, bool allow_string = true, bool output_signed = false)
RTLIL::Const mkconst_str(const std::string &str)
{
size_t found;
RTLIL::Const val;
std::vector<RTLIL::State> data;
data.reserve(str.size() * 8);
for (size_t i = 0; i < str.size(); i++) {
unsigned char ch = str[str.size() - i - 1];
for (int j = 0; j < 8; j++) {
data.push_back((ch & 1) ? State::S1 : State::S0);
ch = ch >> 1;
}
}
val.bits = data;
val.flags |= RTLIL::CONST_FLAG_STRING;
return val;
}
static const RTLIL::Const extract_vhdl_boolean(std::string &val)
{
if (val == "false")
return RTLIL::Const::from_string("0");
if (val == "true")
return RTLIL::Const::from_string("1");
log_error("Expecting VHDL boolean value.\n");
}
static const RTLIL::Const extract_vhdl_bit(std::string &val, std::string &typ)
{
if (val.size()==3 && val[0]=='\'' && val.back()=='\'')
return RTLIL::Const::from_string(val.substr(1,val.size()-2));
log_error("Error parsing VHDL %s.\n", typ.c_str());
}
static const RTLIL::Const extract_vhdl_bit_vector(std::string &val, std::string &typ)
{
if (val.size()>1 && val[0]=='\"' && val.back()=='\"') {
RTLIL::Const c = RTLIL::Const::from_string(val.substr(1,val.size()-2));
if (typ == "signed")
c.flags |= RTLIL::CONST_FLAG_SIGNED;
return c;
}
log_error("Error parsing VHDL %s.\n", typ.c_str());
}
static const RTLIL::Const extract_vhdl_integer(std::string &val)
{
char *end;
return RTLIL::Const((int)std::strtol(val.c_str(), &end, 10), 32);
}
static const RTLIL::Const extract_vhdl_char(std::string &val)
{
if (val.size()==3 && val[0]=='\"' && val.back()=='\"')
return RTLIL::Const((int)val[1], 32);
log_error("Error parsing VHDL character.\n");
}
static const RTLIL::Const extract_real_value(std::string &val)
{
RTLIL::Const c = mkconst_str(val);
c.flags |= RTLIL::CONST_FLAG_REAL;
return c;
}
static const RTLIL::Const extract_vhdl_string(std::string &val)
{
if (!(val.size()>1 && val[0]=='\"' && val.back()=='\"'))
log_error("Error parsing VHDL string.\n");
return RTLIL::Const(val.substr(1,val.size()-2));
}
static const RTLIL::Const extract_vhdl_const(const char *value, bool output_signed)
{
RTLIL::Const c;
char *end;
int decimal;
bool is_signed = false;
RTLIL::Const c;
std::string val = std::string(value);
if (val.size()>1 && val[0]=='\"' && val.back()=='\"') {
std::string data = val.substr(1,val.size()-2);
bool isBinary = std::all_of(data.begin(), data.end(), [](char c) {return c=='1' || c=='0'; });
if (isBinary)
c = RTLIL::Const::from_string(data);
else
c = RTLIL::Const(data);
} else if (val.size()==3 && val[0]=='\'' && val.back()=='\'') {
c = RTLIL::Const::from_string(val.substr(1,val.size()-2));
} else if ((value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) &&
((decimal = std::strtol(value, &end, 10)), !end[0])) {
is_signed = output_signed;
c = RTLIL::Const((int)decimal, 32);
} else if (val == "false") {
c = RTLIL::Const::from_string("0");
} else if (val == "true") {
c = RTLIL::Const::from_string("1");
} else {
c = mkconst_str(val);
log_warning("encoding value '%s' as string.\n", value);
}
if (is_signed)
c.flags |= RTLIL::CONST_FLAG_SIGNED;
return c;
}
static const RTLIL::Const extract_verilog_const(const char *value, bool allow_string, bool output_signed)
{
RTLIL::Const c;
char *end;
int decimal;
bool is_signed = false;
size_t found;
std::string val = std::string(value);
if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') {
c = RTLIL::Const(val.substr(1,val.size()-2));
} else if ((found = val.find("'sb")) != std::string::npos) {
@ -245,15 +342,56 @@ static const RTLIL::Const verific_const(const char *value, bool allow_string = t
} else if (allow_string) {
c = RTLIL::Const(val);
} else {
log_error("expected numeric constant but found '%s'", value);
c = mkconst_str(val);
log_warning("encoding value '%s' as string.\n", value);
}
if (is_signed)
c.flags |= RTLIL::CONST_FLAG_SIGNED;
return c;
}
// When used as attributes or parameter values Verific constants come already processed.
// - Real string values are already under quotes
// - Numeric values with specified width are always converted to binary
// - Rest of user defined values are handled as 32bit integers
// - There could be some internal values that are strings without quotes
// so we check if value is all digits or not
//
// Note: For signed values, verific uses <len>'sb<bits> and decimal values can
// also be negative.
static const RTLIL::Const verific_const(const char* type_name, const char *value, DesignObj *obj, bool allow_string = true, bool output_signed = false)
{
std::string val = std::string(value);
// VHDL
if (obj->IsFromVhdl()) {
if (type_name) {
std::string typ = std::string(type_name);
transform(typ.begin(), typ.end(), typ.begin(), ::tolower);
if (typ == "integer" || typ == "natural" || typ=="positive") return extract_vhdl_integer(val);
else if (typ =="boolean") return extract_vhdl_boolean(val);
else if (typ == "bit" || typ =="std_logic" || typ == "std_ulogic") return extract_vhdl_bit(val,typ);
else if (typ == "character") return extract_vhdl_char(val);
else if (typ == "bit_vector" || typ == "std_logic_vector" || typ == "std_ulogic_vector" ||
typ == "unsigned" || typ == "signed") return extract_vhdl_bit_vector(val,typ);
else if (typ == "real") return extract_real_value(val);
else if (typ == "string") return extract_vhdl_string(val);
else {
if (val.size()>1 && val[0]=='\"' && val.back()=='\"')
return RTLIL::Const(val.substr(1,val.size()-2));
else if (val.size()==3 && val[0]=='\'' && val.back()=='\'')
return RTLIL::Const(val.substr(1,val.size()-2));
else
return RTLIL::Const(val);
}
} else extract_vhdl_const(value, output_signed);
}
// SystemVerilog
if (type_name && strcmp(type_name, "real")==0) {
return extract_real_value(val);
} else
return extract_verilog_const(value, allow_string, output_signed);
}
static const std::string verific_unescape(const char *value)
{
std::string val = std::string(value);
@ -276,7 +414,7 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att
FOREACH_ATTRIBUTE(obj, mi, attr) {
if (attr->Key()[0] == ' ' || attr->Value() == nullptr)
continue;
attributes[RTLIL::escape_id(attr->Key())] = verific_const(attr->Value());
attributes[RTLIL::escape_id(attr->Key())] = verific_const(nullptr, attr->Value(), obj);
}
if (nl) {
@ -298,7 +436,7 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att
const char *k, *v;
FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mi, &k, &v) {
if (nl->IsFromVerilog()) {
auto const value = verific_const(v, false);
auto const value = verific_const(type_name, v, nl, false);
attributes.emplace(stringf("\\enum_value_%s", value.as_string().c_str()), RTLIL::escape_id(k));
}
@ -1292,6 +1430,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
}
import_attributes(module->attributes, nl, nl);
module->set_string_attribute(ID::hdlname, nl->CellBaseName());
module->set_string_attribute(ID(library), nl->Owner()->Owner()->Name());
#ifdef VERIFIC_VHDL_SUPPORT
if (nl->IsFromVhdl()) {
NameSpace name_space(0);
@ -1304,7 +1443,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
MapIter mi;
FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) {
module->avail_parameters(RTLIL::escape_id(param_name));
module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value);
const TypeRange *tr = nl->GetTypeRange(param_name) ;
module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(tr->GetTypeName(), param_value, nl);
}
SetIter si;
@ -2004,7 +2144,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
const char *param_value ;
if (is_blackbox(inst->View())) {
FOREACH_PARAMETER_OF_INST(inst, mi2, param_name, param_value) {
cell->setParam(RTLIL::escape_id(param_name), verific_const(param_value));
const TypeRange *tr = inst->View()->GetTypeRange(param_name) ;
cell->setParam(RTLIL::escape_id(param_name), verific_const(tr->GetTypeName(), param_value, inst->View()));
}
}
@ -2015,8 +2156,16 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
int port_offset = 0;
if (pr->GetPort()->Bus()) {
port_name = pr->GetPort()->Bus()->Name();
port_offset = pr->GetPort()->Bus()->IndexOf(pr->GetPort()) -
min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());
int msb_index = pr->GetPort()->Bus()->LeftIndex();
int lsb_index = pr->GetPort()->Bus()->RightIndex();
int index_of_port = pr->GetPort()->Bus()->IndexOf(pr->GetPort());
port_offset = index_of_port - min(msb_index, lsb_index);
// In cases where the msb order is flipped we need to make sure
// that the indicies match LSB = 0 order to match the std::vector
// to SigSpec LSB = 0 precondition.
if (lsb_index > msb_index) {
port_offset = abs(port_offset - (lsb_index - min(msb_index, lsb_index)));
}
}
IdString port_name_id = RTLIL::escape_id(port_name);
auto &sigvec = cell_port_conns[port_name_id];
@ -2699,7 +2848,7 @@ struct VerificPass : public Pass {
log("\n");
log("\n");
#ifdef VERIFIC_VHDL_SUPPORT
log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n");
log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl2019|-vhdl} <vhdl-file>..\n");
log("\n");
log("Load the specified VHDL files into Verific.\n");
log("\n");
@ -3436,6 +3585,29 @@ struct VerificPass : public Pass {
goto check_error;
}
if (GetSize(args) > argidx && (args[argidx] == "-vhdl2019")) {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2019").c_str());
bool flag_lib = false;
for (argidx++; argidx < GetSize(args); argidx++) {
if (args[argidx] == "-lib") {
flag_lib = true;
continue;
}
if (args[argidx].compare(0, 1, "-") == 0) {
cmd_error(args, argidx, "unknown option");
goto check_error;
}
Map map(POINTER_HASH);
add_units_to_map(map, work, flag_lib);
std::string filename = frontent_rewrite(args, argidx, tmp_files);
if (!vhdl_file::Analyze(filename.c_str(), work.c_str(), vhdl_file::VHDL_2019))
log_cmd_error("Reading `%s' in VHDL_2019 mode failed.\n", filename.c_str());
set_units_to_blackbox(map, work, flag_lib);
}
verific_import_pending = true;
goto check_error;
}
if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
bool flag_lib = false;
@ -3979,7 +4151,7 @@ struct ReadPass : public Pass {
log("\n");
log("\n");
#ifdef VERIFIC_VHDL_SUPPORT
log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n");
log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl2019|-vhdl} <vhdl-file>..\n");
log("\n");
log("Load the specified VHDL files. (Requires Verific.)\n");
log("\n");
@ -4083,7 +4255,7 @@ struct ReadPass : public Pass {
}
#ifdef VERIFIC_VHDL_SUPPORT
if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl") {
if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl2019" || args[1] == "-vhdl") {
if (use_verific) {
args[0] = "verific";
Pass::call(design, args);

View File

@ -270,8 +270,11 @@ struct VerilogFrontend : public Frontend {
frontend_verilog_yydebug = false;
sv_mode = false;
formal_mode = false;
noassert_mode = false;
noassume_mode = false;
norestrict_mode = false;
assume_asserts_mode = false;
assert_assumes_mode = false;
lib_mode = false;
specify_mode = false;
default_nettype_wire = true;

View File

@ -19,7 +19,7 @@ Formatting of code
blank lines.
- Otherwise stick to the Linux Kernel Coding Style:
https://www.kernel.org/doc/Documentation/CodingStyle
https://www.kernel.org/doc/Documentation/process/coding-style.rst
C++ Language

View File

@ -222,6 +222,8 @@ X(_TECHMAP_REPLACE_)
X(techmap_simplemap)
X(_techmap_special_)
X(techmap_wrap)
X(_TECHMAP_PLACEHOLDER_)
X(techmap_chtype)
X(T_FALL_MAX)
X(T_FALL_MIN)
X(T_FALL_TYP)

View File

@ -356,7 +356,7 @@ int main(int argc, char **argv)
printf(" -V\n");
printf(" print version information and exit\n");
printf("\n");
printf("The option -S is an shortcut for calling the \"synth\" command, a default\n");
printf("The option -S is a shortcut for calling the \"synth\" command, a default\n");
printf("script for transforming the Verilog input to a gate-level netlist. For example:\n");
printf("\n");
printf(" yosys -o output.blif -S input.v\n");

View File

@ -22,9 +22,9 @@
USING_YOSYS_NAMESPACE
void Fmt::append_string(const std::string &str) {
void Fmt::append_literal(const std::string &str) {
FmtPart part = {};
part.type = FmtPart::STRING;
part.type = FmtPart::LITERAL;
part.str = str;
parts.push_back(part);
}
@ -42,11 +42,11 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
} else if (fmt.substr(i, 2) == "{{") {
part.str += '{';
++i;
} else if (fmt[i] == '}')
} else if (fmt[i] == '}') {
log_assert(false && "Unexpected '}' in format string");
else if (fmt[i] == '{') {
} else if (fmt[i] == '{') {
if (!part.str.empty()) {
part.type = FmtPart::STRING;
part.type = FmtPart::LITERAL;
parts.push_back(part);
part = {};
}
@ -74,19 +74,24 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
part.sig = args.extract(0, arg_size);
args.remove(0, arg_size);
if (fmt[i] == 'U') {
part.type = FmtPart::UNICHAR;
++i;
goto success;
}
if (fmt[i] == '>')
part.justify = FmtPart::RIGHT;
else if (fmt[i] == '<')
part.justify = FmtPart::LEFT;
else if (fmt[i] == '=')
part.justify = FmtPart::NUMERIC;
else
log_assert(false && "Unexpected justification in format substitution");
if (++i == fmt.size())
log_assert(false && "Unexpected end in format substitution");
if (fmt[i] == '0' || fmt[i] == ' ')
part.padding = fmt[i];
else
log_assert(false && "Unexpected padding in format substitution");
part.padding = fmt[i];
if (++i == fmt.size())
log_assert(false && "Unexpected end in format substitution");
@ -107,8 +112,12 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
} else if (fmt[i] == 'h') {
part.type = FmtPart::INTEGER;
part.base = 16;
} else if (fmt[i] == 'H') {
part.type = FmtPart::INTEGER;
part.base = 16;
part.hex_upper = true;
} else if (fmt[i] == 'c') {
part.type = FmtPart::CHARACTER;
part.type = FmtPart::STRING;
} else if (fmt[i] == 't') {
part.type = FmtPart::VLOG_TIME;
} else if (fmt[i] == 'r') {
@ -124,10 +133,29 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
log_assert(false && "Unexpected end in format substitution");
if (part.type == FmtPart::INTEGER) {
if (fmt[i] == '+') {
part.plus = true;
if (fmt[i] == '-') {
part.sign = FmtPart::MINUS;
if (++i == fmt.size())
log_assert(false && "Unexpected end in format substitution");
} else if (fmt[i] == '+') {
part.sign = FmtPart::PLUS_MINUS;
if (++i == fmt.size())
log_assert(false && "Unexpected end in format substitution");
} else if (fmt[i] == ' ') {
part.sign = FmtPart::SPACE_MINUS;
if (++i == fmt.size())
log_assert(false && "Unexpected end in format substitution");
} else {
// also accept no sign character and treat like MINUS for compatibility
}
if (fmt[i] == '#') {
part.show_base = true;
++i;
}
if (fmt[i] == '_') {
part.group = true;
++i;
}
if (fmt[i] == 'u')
@ -140,6 +168,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
log_assert(false && "Unexpected end in format substitution");
}
success:
if (fmt[i] != '}')
log_assert(false && "Expected '}' after format substitution");
@ -150,7 +179,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
}
}
if (!part.str.empty()) {
part.type = FmtPart::STRING;
part.type = FmtPart::LITERAL;
parts.push_back(part);
}
}
@ -161,7 +190,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
for (auto &part : parts) {
switch (part.type) {
case FmtPart::STRING:
case FmtPart::LITERAL:
for (char c : part.str) {
if (c == '{')
fmt += "{{";
@ -172,10 +201,15 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
}
break;
case FmtPart::UNICHAR:
log_assert(part.sig.size() <= 32);
fmt += "{U}";
break;
case FmtPart::VLOG_TIME:
log_assert(part.sig.size() == 0);
YS_FALLTHROUGH
case FmtPart::CHARACTER:
case FmtPart::STRING:
log_assert(part.sig.size() % 8 == 0);
YS_FALLTHROUGH
case FmtPart::INTEGER:
@ -187,6 +221,8 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
fmt += '>';
else if (part.justify == FmtPart::LEFT)
fmt += '<';
else if (part.justify == FmtPart::NUMERIC)
fmt += '=';
else log_abort();
log_assert(part.width == 0 || part.padding != '\0');
fmt += part.padding != '\0' ? part.padding : ' ';
@ -197,13 +233,18 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
case 2: fmt += 'b'; break;
case 8: fmt += 'o'; break;
case 10: fmt += 'd'; break;
case 16: fmt += 'h'; break;
case 16: fmt += part.hex_upper ? 'H' : 'h'; break;
default: log_abort();
}
if (part.plus)
fmt += '+';
switch (part.sign) {
case FmtPart::MINUS: fmt += '-'; break;
case FmtPart::PLUS_MINUS: fmt += '+'; break;
case FmtPart::SPACE_MINUS: fmt += ' '; break;
}
fmt += part.show_base ? "#" : "";
fmt += part.group ? "_" : "";
fmt += part.signed_ ? 's' : 'u';
} else if (part.type == FmtPart::CHARACTER) {
} else if (part.type == FmtPart::STRING) {
fmt += 'c';
} else if (part.type == FmtPart::VLOG_TIME) {
if (part.realtime)
@ -299,12 +340,12 @@ void Fmt::apply_verilog_automatic_sizing_and_add(FmtPart &part)
part.width = places;
if (part.justify == FmtPart::RIGHT) {
append_string(gap);
append_literal(gap);
parts.push_back(part);
} else {
part.justify = FmtPart::RIGHT;
parts.push_back(part);
append_string(gap);
append_literal(gap);
}
}
}
@ -355,7 +396,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
part.str += module_name.str();
} else {
if (!part.str.empty()) {
part.type = FmtPart::STRING;
part.type = FmtPart::LITERAL;
parts.push_back(part);
part = {};
}
@ -375,7 +416,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
part.justify = FmtPart::LEFT;
} else if (fmt[i] == '+') {
// always show sign; not in IEEE 1800-2017 or verilator but iverilog has it
part.plus = true;
part.sign = FmtPart::PLUS_MINUS;
} else break;
}
if (i == fmt.size()) {
@ -408,11 +449,11 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
part.type = FmtPart::INTEGER;
part.base = 16;
} else if (fmt[i] == 'c' || fmt[i] == 'C') {
part.type = FmtPart::CHARACTER;
part.type = FmtPart::STRING;
part.sig.extend_u0(8);
// %10c and %010c not fully defined in IEEE 1800-2017 and do different things in iverilog
} else if (fmt[i] == 's' || fmt[i] == 'S') {
part.type = FmtPart::CHARACTER;
part.type = FmtPart::STRING;
if ((part.sig.size() % 8) != 0)
part.sig.extend_u0((part.sig.size() + 7) / 8 * 8);
// %10s and %010s not fully defined in IEEE 1800-2017 and do the same thing in iverilog
@ -435,12 +476,20 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
}
if (part.padding == '\0')
part.padding = (has_leading_zero && part.justify == FmtPart::RIGHT) ? '0' : ' ';
if (part.padding == '\0') {
if (has_leading_zero && part.justify == FmtPart::RIGHT) {
part.padding = '0';
part.justify = FmtPart::NUMERIC;
} else {
part.padding = ' ';
}
}
if (part.type == FmtPart::INTEGER && part.base != 10 && part.plus)
if (part.type == FmtPart::INTEGER && part.base != 10 && part.sign != FmtPart::MINUS)
log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1);
if (part.base != 10)
part.signed_ = false;
if (part.type == FmtPart::INTEGER && !has_leading_zero)
apply_verilog_automatic_sizing_and_add(part);
else
@ -449,12 +498,12 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
}
}
if (!part.str.empty()) {
part.type = FmtPart::STRING;
part.type = FmtPart::LITERAL;
parts.push_back(part);
}
} else {
FmtPart part = {};
part.type = FmtPart::STRING;
part.type = FmtPart::LITERAL;
part.str = arg->str;
parts.push_back(part);
}
@ -474,7 +523,7 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
for (auto &part : parts) {
switch (part.type) {
case FmtPart::STRING:
case FmtPart::LITERAL:
for (char c : part.str) {
if (c == '%')
fmt.str += "%%";
@ -491,14 +540,13 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
args.push_back(arg);
fmt.str += '%';
if (part.plus)
fmt.str += '+';
if (part.sign == FmtPart::PLUS_MINUS || part.sign == FmtPart::SPACE_MINUS)
fmt.str += '+'; // treat space/minus as plus/minus
if (part.justify == FmtPart::LEFT)
fmt.str += '-';
if (part.width == 0) {
fmt.str += '0';
} else if (part.width > 0) {
log_assert(part.padding == ' ' || part.padding == '0');
if (part.base != 10 || part.padding == '0')
fmt.str += '0';
fmt.str += std::to_string(part.width);
@ -507,13 +555,13 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
case 2: fmt.str += 'b'; break;
case 8: fmt.str += 'o'; break;
case 10: fmt.str += 'd'; break;
case 16: fmt.str += 'h'; break;
case 16: fmt.str += 'h'; break; // treat uppercase hex as lowercase
default: log_abort();
}
break;
}
case FmtPart::CHARACTER: {
case FmtPart::STRING: {
VerilogFmtArg arg;
arg.type = VerilogFmtArg::INTEGER;
arg.sig = part.sig;
@ -524,7 +572,6 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
fmt.str += '-';
if (part.sig.size() == 8) {
if (part.width > 0) {
log_assert(part.padding == '0' || part.padding == ' ');
if (part.padding == '0')
fmt.str += part.padding;
fmt.str += std::to_string(part.width);
@ -533,7 +580,6 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
} else {
log_assert(part.sig.size() % 8 == 0);
if (part.width > 0) {
log_assert(part.padding == ' '); // no zero padding
fmt.str += std::to_string(part.width);
}
fmt.str += 's';
@ -541,6 +587,16 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
break;
}
case FmtPart::UNICHAR: {
VerilogFmtArg arg;
arg.type = VerilogFmtArg::INTEGER;
arg.sig = part.sig.extract(0, 7); // only ASCII
args.push_back(arg);
fmt.str += "%c";
break;
}
case FmtPart::VLOG_TIME: {
VerilogFmtArg arg;
arg.type = VerilogFmtArg::TIME;
@ -549,11 +605,11 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
args.push_back(arg);
fmt.str += '%';
if (part.plus)
log_assert(part.sign == FmtPart::MINUS || part.sign == FmtPart::PLUS_MINUS);
if (part.sign == FmtPart::PLUS_MINUS)
fmt.str += '+';
if (part.justify == FmtPart::LEFT)
fmt.str += '-';
log_assert(part.padding == ' ' || part.padding == '0');
if (part.padding == '0' && part.width > 0)
fmt.str += '0';
fmt.str += std::to_string(part.width);
@ -599,24 +655,35 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(c
os << indent << "buf += fmt_part { ";
os << "fmt_part::";
switch (part.type) {
case FmtPart::STRING: os << "STRING"; break;
case FmtPart::LITERAL: os << "LITERAL"; break;
case FmtPart::INTEGER: os << "INTEGER"; break;
case FmtPart::CHARACTER: os << "CHARACTER"; break;
case FmtPart::STRING: os << "STRING"; break;
case FmtPart::UNICHAR: os << "UNICHAR"; break;
case FmtPart::VLOG_TIME: os << "VLOG_TIME"; break;
}
os << ", ";
os << escape_cxx_string(part.str) << ", ";
os << "fmt_part::";
switch (part.justify) {
case FmtPart::LEFT: os << "LEFT"; break;
case FmtPart::RIGHT: os << "RIGHT"; break;
case FmtPart::LEFT: os << "LEFT"; break;
case FmtPart::RIGHT: os << "RIGHT"; break;
case FmtPart::NUMERIC: os << "NUMERIC"; break;
}
os << ", ";
os << "(char)" << (int)part.padding << ", ";
os << part.width << ", ";
os << part.base << ", ";
os << part.signed_ << ", ";
os << part.plus << ", ";
os << "fmt_part::";
switch (part.sign) {
case FmtPart::MINUS: os << "MINUS"; break;
case FmtPart::PLUS_MINUS: os << "PLUS_MINUS"; break;
case FmtPart::SPACE_MINUS: os << "SPACE_MINUS"; break;
}
os << ", ";
os << part.hex_upper << ", ";
os << part.show_base << ", ";
os << part.group << ", ";
os << part.realtime;
os << " }.render(";
emit_sig(part.sig);
@ -631,19 +698,62 @@ std::string Fmt::render() const
for (auto &part : parts) {
switch (part.type) {
case FmtPart::STRING:
case FmtPart::LITERAL:
str += part.str;
break;
case FmtPart::UNICHAR: {
RTLIL::Const value = part.sig.as_const();
uint32_t codepoint = value.as_int();
if (codepoint >= 0x10000)
str += (char)(0xf0 | (codepoint >> 18));
else if (codepoint >= 0x800)
str += (char)(0xe0 | (codepoint >> 12));
else if (codepoint >= 0x80)
str += (char)(0xc0 | (codepoint >> 6));
else
str += (char)codepoint;
if (codepoint >= 0x10000)
str += (char)(0x80 | ((codepoint >> 12) & 0x3f));
if (codepoint >= 0x800)
str += (char)(0x80 | ((codepoint >> 6) & 0x3f));
if (codepoint >= 0x80)
str += (char)(0x80 | ((codepoint >> 0) & 0x3f));
break;
}
case FmtPart::INTEGER:
case FmtPart::CHARACTER:
case FmtPart::STRING:
case FmtPart::VLOG_TIME: {
std::string buf;
std::string prefix;
if (part.type == FmtPart::INTEGER) {
RTLIL::Const value = part.sig.as_const();
bool has_x = false, all_x = true, has_z = false, all_z = true;
for (State bit : value) {
if (bit == State::Sx)
has_x = true;
else
all_x = false;
if (bit == State::Sz)
has_z = true;
else
all_z = false;
}
if (!has_z && !has_x && part.signed_ && value[value.size() - 1]) {
prefix = "-";
value = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1);
} else {
switch (part.sign) {
case FmtPart::MINUS: break;
case FmtPart::PLUS_MINUS: prefix = "+"; break;
case FmtPart::SPACE_MINUS: prefix = " "; break;
}
}
if (part.base != 10) {
size_t minimum_size = 0;
size_t minimum_size = 1;
for (size_t index = 0; index < (size_t)value.size(); index++)
if (value[index] != State::S0)
minimum_size = index + 1;
@ -651,10 +761,28 @@ std::string Fmt::render() const
}
if (part.base == 2) {
buf = value.as_string();
if (part.show_base)
prefix += "0b";
for (size_t index = 0; index < (size_t)value.size(); index++) {
if (part.group && index > 0 && index % 4 == 0)
buf += '_';
RTLIL::State bit = value[index];
if (bit == State::Sx)
buf += 'x';
else if (bit == State::Sz)
buf += 'z';
else if (bit == State::S1)
buf += '1';
else /* if (bit == State::S0) */
buf += '0';
}
} else if (part.base == 8 || part.base == 16) {
if (part.show_base)
prefix += (part.base == 16) ? (part.hex_upper ? "0X" : "0x") : "0o";
size_t step = (part.base == 16) ? 4 : 3;
for (size_t index = 0; index < (size_t)value.size(); index += step) {
if (part.group && index > 0 && index % (4 * step) == 0)
buf += '_';
RTLIL::Const subvalue = value.extract(index, min(step, value.size() - index));
bool has_x = false, all_x = true, has_z = false, all_z = true;
for (State bit : subvalue) {
@ -676,21 +804,11 @@ std::string Fmt::render() const
else if (has_z)
buf += 'Z';
else
buf += "0123456789abcdef"[subvalue.as_int()];
buf += (part.hex_upper ? "0123456789ABCDEF" : "0123456789abcdef")[subvalue.as_int()];
}
std::reverse(buf.begin(), buf.end());
} else if (part.base == 10) {
bool has_x = false, all_x = true, has_z = false, all_z = true;
for (State bit : value) {
if (bit == State::Sx)
has_x = true;
else
all_x = false;
if (bit == State::Sz)
has_z = true;
else
all_z = false;
}
if (part.show_base)
prefix += "0d";
if (all_x)
buf += 'x';
else if (all_z)
@ -700,25 +818,29 @@ std::string Fmt::render() const
else if (has_z)
buf += 'Z';
else {
bool negative = part.signed_ && value[value.size() - 1];
RTLIL::Const absvalue;
if (negative)
absvalue = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1);
else
absvalue = value;
log_assert(absvalue.is_fully_def());
if (absvalue.is_fully_zero())
log_assert(value.is_fully_def());
if (value.is_fully_zero())
buf += '0';
while (!absvalue.is_fully_zero()) {
buf += '0' + RTLIL::const_mod(absvalue, 10, false, false, 4).as_int();
absvalue = RTLIL::const_div(absvalue, 10, false, false, absvalue.size());
size_t index = 0;
while (!value.is_fully_zero()) {
if (part.group && index > 0 && index % 3 == 0)
buf += '_';
buf += '0' + RTLIL::const_mod(value, 10, false, false, 4).as_int();
value = RTLIL::const_div(value, 10, false, false, value.size());
index++;
}
if (negative || part.plus)
buf += negative ? '-' : '+';
std::reverse(buf.begin(), buf.end());
}
} else log_abort();
} else if (part.type == FmtPart::CHARACTER) {
if (part.justify == FmtPart::NUMERIC && part.group && part.padding == '0') {
int group_size = part.base == 10 ? 3 : 4;
while (prefix.size() + buf.size() < part.width) {
if (buf.size() % (group_size + 1) == group_size)
buf += '_';
buf += '0';
}
}
std::reverse(buf.begin(), buf.end());
} else if (part.type == FmtPart::STRING) {
buf = part.sig.as_const().decode_string();
} else if (part.type == FmtPart::VLOG_TIME) {
// We only render() during initial, so time is always zero.
@ -726,17 +848,29 @@ std::string Fmt::render() const
}
log_assert(part.width == 0 || part.padding != '\0');
if (part.justify == FmtPart::RIGHT && buf.size() < part.width) {
size_t pad_width = part.width - buf.size();
if (part.padding == '0' && (!buf.empty() && (buf.front() == '+' || buf.front() == '-'))) {
str += buf.front();
buf.erase(0, 1);
if (prefix.size() + buf.size() < part.width) {
size_t pad_width = part.width - prefix.size() - buf.size();
switch (part.justify) {
case FmtPart::LEFT:
str += prefix;
str += buf;
str += std::string(pad_width, part.padding);
break;
case FmtPart::RIGHT:
str += std::string(pad_width, part.padding);
str += prefix;
str += buf;
break;
case FmtPart::NUMERIC:
str += prefix;
str += std::string(pad_width, part.padding);
str += buf;
break;
}
str += std::string(pad_width, part.padding);
} else {
str += prefix;
str += buf;
}
str += buf;
if (part.justify == FmtPart::LEFT && buf.size() < part.width)
str += std::string(part.width - buf.size(), part.padding);
break;
}
}

View File

@ -53,22 +53,24 @@ struct VerilogFmtArg {
// Must be kept in sync with `struct fmt_part` in backends/cxxrtl/runtime/cxxrtl/cxxrtl.h!
struct FmtPart {
enum {
STRING = 0,
LITERAL = 0,
INTEGER = 1,
CHARACTER = 2,
VLOG_TIME = 3,
STRING = 2,
UNICHAR = 3,
VLOG_TIME = 4,
} type;
// STRING type
// LITERAL type
std::string str;
// INTEGER/CHARACTER types
// INTEGER/STRING/UNICHAR types
RTLIL::SigSpec sig;
// INTEGER/CHARACTER/VLOG_TIME types
// INTEGER/STRING/VLOG_TIME types
enum {
RIGHT = 0,
LEFT = 1,
NUMERIC = 2,
} justify = RIGHT;
char padding = '\0';
size_t width = 0;
@ -76,7 +78,14 @@ struct FmtPart {
// INTEGER type
unsigned base = 10;
bool signed_ = false;
bool plus = false;
enum {
MINUS = 0,
PLUS_MINUS = 1,
SPACE_MINUS = 2,
} sign = MINUS;
bool hex_upper = false;
bool show_base = false;
bool group = false;
// VLOG_TIME type
bool realtime = false;
@ -86,7 +95,7 @@ struct Fmt {
public:
std::vector<FmtPart> parts;
void append_string(const std::string &str);
void append_literal(const std::string &str);
void parse_rtlil(const RTLIL::Cell *cell);
void emit_rtlil(RTLIL::Cell *cell) const;

View File

@ -17,11 +17,11 @@
*
*/
#include "kernel/yosys.h"
#ifndef LOG_H
#define LOG_H
#include "kernel/yosys_common.h"
#include <time.h>
#include <regex>
@ -449,4 +449,6 @@ void log_dump_args_worker(const char *p, T first, Args ... args)
YOSYS_NAMESPACE_END
#include "kernel/yosys.h"
#endif

View File

@ -17,11 +17,12 @@
*
*/
#include "kernel/yosys.h"
#ifndef REGISTER_H
#define REGISTER_H
#include "kernel/yosys_common.h"
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
struct Pass

View File

@ -4435,9 +4435,36 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
log_assert(offset >= 0);
log_assert(length >= 0);
log_assert(offset + length <= width_);
unpack();
cover("kernel.rtlil.sigspec.extract_pos");
return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
if (packed()) {
SigSpec extracted;
extracted.width_ = length;
auto it = chunks_.begin();
for (; offset; offset -= it->width, it++) {
if (offset < it->width) {
int chunk_length = min(it->width - offset, length);
extracted.chunks_.emplace_back(it->extract(offset, chunk_length));
length -= chunk_length;
it++;
break;
}
}
for (; length; length -= it->width, it++) {
if (length >= it->width) {
extracted.chunks_.emplace_back(*it);
} else {
extracted.chunks_.emplace_back(it->extract(0, length));
break;
}
}
return extracted;
} else {
return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
}
}
void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)

View File

@ -17,11 +17,12 @@
*
*/
#include "kernel/yosys.h"
#ifndef RTLIL_H
#define RTLIL_H
#include "kernel/yosys_common.h"
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
namespace RTLIL

View File

@ -39,323 +39,7 @@
#ifndef YOSYS_H
#define YOSYS_H
#include <map>
#include <set>
#include <tuple>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <initializer_list>
#include <stdexcept>
#include <memory>
#include <cmath>
#include <cstddef>
#include <sstream>
#include <fstream>
#include <istream>
#include <ostream>
#include <iostream>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <limits.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef WITH_PYTHON
#include <Python.h>
#endif
#ifndef _YOSYS_
# error It looks like you are trying to build Yosys without the config defines set. \
When building Yosys with a custom make system, make sure you set all the \
defines the Yosys Makefile would set for your build configuration.
#endif
#ifdef YOSYS_ENABLE_TCL
# include <tcl.h>
# ifdef YOSYS_MXE_HACKS
extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
extern Tcl_Interp *Tcl_CreateInterp(void);
extern void Tcl_Preserve(ClientData data);
extern void Tcl_Release(ClientData clientData);
extern int Tcl_InterpDeleted(Tcl_Interp *interp);
extern void Tcl_DeleteInterp(Tcl_Interp *interp);
extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
extern void Tcl_Finalize(void);
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
extern Tcl_Obj *Tcl_NewIntObj(int intValue);
extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
# endif
# undef CONST
# undef INLINE
#endif
#ifdef _WIN32
# undef NOMINMAX
# define NOMINMAX 1
# undef YY_NO_UNISTD_H
# define YY_NO_UNISTD_H 1
# include <windows.h>
# include <io.h>
# include <direct.h>
# define strtok_r strtok_s
# define strdup _strdup
# define snprintf _snprintf
# define getcwd _getcwd
# define mkdir _mkdir
# define popen _popen
# define pclose _pclose
# ifndef __MINGW32__
# define PATH_MAX MAX_PATH
# define isatty _isatty
# define fileno _fileno
# endif
// The following defines conflict with our identifiers:
# undef CONST
// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc
# undef TRANSPARENT
#endif
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
#define YOSYS_NAMESPACE Yosys
#define PRIVATE_NAMESPACE_BEGIN namespace {
#define PRIVATE_NAMESPACE_END }
#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
#define YOSYS_NAMESPACE_END }
#define YOSYS_NAMESPACE_PREFIX Yosys::
#define USING_YOSYS_NAMESPACE using namespace Yosys;
#if defined(__GNUC__) || defined(__clang__)
# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
#elif defined(_MSC_VER)
# define YS_ATTRIBUTE(...)
#else
# define YS_ATTRIBUTE(...)
#endif
#if defined(__GNUC__) || defined(__clang__)
# define YS_MAYBE_UNUSED __attribute__((__unused__))
#else
# define YS_MAYBE_UNUSED
#endif
#if __cplusplus >= 201703L
# define YS_FALLTHROUGH [[fallthrough]];
#elif defined(__clang__)
# define YS_FALLTHROUGH [[clang::fallthrough]];
#elif defined(__GNUC__)
# define YS_FALLTHROUGH [[gnu::fallthrough]];
#else
# define YS_FALLTHROUGH
#endif
YOSYS_NAMESPACE_BEGIN
// Note: All headers included in hashlib.h must be included
// outside of YOSYS_NAMESPACE before this or bad things will happen.
#ifdef HASHLIB_H
# undef HASHLIB_H
# include "kernel/hashlib.h"
#else
# include "kernel/hashlib.h"
# undef HASHLIB_H
#endif
using std::vector;
using std::string;
using std::tuple;
using std::pair;
using std::make_tuple;
using std::make_pair;
using std::get;
using std::min;
using std::max;
// A primitive shared string implementation that does not
// move its .c_str() when the object is copied or moved.
struct shared_str {
std::shared_ptr<string> content;
shared_str() { }
shared_str(string s) { content = std::shared_ptr<string>(new string(s)); }
shared_str(const char *s) { content = std::shared_ptr<string>(new string(s)); }
const char *c_str() const { return content->c_str(); }
const string &str() const { return *content; }
bool operator==(const shared_str &other) const { return *content == *other.content; }
unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
};
using hashlib::mkhash;
using hashlib::mkhash_init;
using hashlib::mkhash_add;
using hashlib::mkhash_xorshift;
using hashlib::hash_ops;
using hashlib::hash_cstr_ops;
using hashlib::hash_ptr_ops;
using hashlib::hash_obj_ops;
using hashlib::dict;
using hashlib::idict;
using hashlib::pool;
using hashlib::mfp;
namespace RTLIL {
struct IdString;
struct Const;
struct SigBit;
struct SigSpec;
struct Wire;
struct Cell;
struct Memory;
struct Process;
struct Module;
struct Design;
struct Monitor;
enum State : unsigned char;
}
namespace AST {
struct AstNode;
}
using RTLIL::IdString;
using RTLIL::Const;
using RTLIL::SigBit;
using RTLIL::SigSpec;
using RTLIL::Wire;
using RTLIL::Cell;
using RTLIL::Module;
using RTLIL::Design;
namespace hashlib {
template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Process*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Process*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
}
void memhasher_on();
void memhasher_off();
void memhasher_do();
extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner();
int ceil_log2(int x) YS_ATTRIBUTE(const);
inline std::string vstringf(const char *fmt, va_list ap)
{
// For the common case of strings shorter than 128, save a heap
// allocation by using a stack allocated buffer.
const int kBufSize = 128;
char buf[kBufSize];
buf[0] = '\0';
va_list apc;
va_copy(apc, ap);
int n = vsnprintf(buf, kBufSize, fmt, apc);
va_end(apc);
if (n < kBufSize)
return std::string(buf);
std::string string;
char *str = NULL;
#if defined(_WIN32 )|| defined(__CYGWIN__)
int sz = 2 * kBufSize, rc;
while (1) {
va_copy(apc, ap);
str = (char*)realloc(str, sz);
rc = vsnprintf(str, sz, fmt, apc);
va_end(apc);
if (rc >= 0 && rc < sz)
break;
sz *= 2;
}
if (str != NULL) {
string = str;
free(str);
}
return string;
#else
if (vasprintf(&str, fmt, ap) < 0)
str = NULL;
if (str != NULL) {
string = str;
free(str);
}
return string;
#endif
}
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
inline std::string stringf(const char *fmt, ...)
{
std::string string;
va_list ap;
va_start(ap, fmt);
string = vstringf(fmt, ap);
va_end(ap);
return string;
}
int readsome(std::istream &f, char *s, int n);
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
bool patmatch(const char *pattern, const char *string);
#if !defined(YOSYS_DISABLE_SPAWN)
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
#endif
std::string get_base_tmpdir();
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false);
bool check_directory_exists(const std::string& dirname);
bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname);
bool create_directory(const std::string& dirname);
std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); }
inline int GetSize(RTLIL::Wire *wire);
extern int autoidx;
extern int yosys_xtrace;
YOSYS_NAMESPACE_END
#include "kernel/yosys_common.h"
#include "kernel/log.h"
#include "kernel/rtlil.h"
@ -363,14 +47,6 @@ YOSYS_NAMESPACE_END
YOSYS_NAMESPACE_BEGIN
using RTLIL::State;
using RTLIL::SigChunk;
using RTLIL::SigSig;
namespace hashlib {
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
}
void yosys_setup();
#ifdef WITH_PYTHON
@ -385,26 +61,6 @@ Tcl_Interp *yosys_get_tcl_interp();
extern RTLIL::Design *yosys_design;
RTLIL::IdString new_id(std::string file, int line, std::string func);
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
#define NEW_ID \
YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
#define NEW_ID_SUFFIX(suffix) \
YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
// Create a statically allocated IdString object, using for example ID::A or ID($add).
//
// Recipe for Converting old code that is using conversion of strings like ID::A and
// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for
// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary.
//
// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename>
//
#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
namespace ID = RTLIL::ID;
RTLIL::Design *yosys_get_design();
std::string proc_self_dirname();
std::string proc_share_dirname();

379
kernel/yosys_common.h Normal file
View File

@ -0,0 +1,379 @@
/* -*- c++ -*-
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef YOSYS_COMMON_H
#define YOSYS_COMMON_H
#include <map>
#include <set>
#include <tuple>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <initializer_list>
#include <stdexcept>
#include <memory>
#include <cmath>
#include <cstddef>
#include <sstream>
#include <fstream>
#include <istream>
#include <ostream>
#include <iostream>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <limits.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef WITH_PYTHON
#include <Python.h>
#endif
#ifndef _YOSYS_
# error It looks like you are trying to build Yosys without the config defines set. \
When building Yosys with a custom make system, make sure you set all the \
defines the Yosys Makefile would set for your build configuration.
#endif
#ifdef YOSYS_ENABLE_TCL
# include <tcl.h>
# ifdef YOSYS_MXE_HACKS
extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
extern Tcl_Interp *Tcl_CreateInterp(void);
extern void Tcl_Preserve(ClientData data);
extern void Tcl_Release(ClientData clientData);
extern int Tcl_InterpDeleted(Tcl_Interp *interp);
extern void Tcl_DeleteInterp(Tcl_Interp *interp);
extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
extern void Tcl_Finalize(void);
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
extern Tcl_Obj *Tcl_NewIntObj(int intValue);
extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
# endif
# undef CONST
# undef INLINE
#endif
#ifdef _WIN32
# undef NOMINMAX
# define NOMINMAX 1
# undef YY_NO_UNISTD_H
# define YY_NO_UNISTD_H 1
# include <windows.h>
# include <io.h>
# include <direct.h>
# define strtok_r strtok_s
# define strdup _strdup
# define snprintf _snprintf
# define getcwd _getcwd
# define mkdir _mkdir
# define popen _popen
# define pclose _pclose
# ifndef __MINGW32__
# define PATH_MAX MAX_PATH
# define isatty _isatty
# define fileno _fileno
# endif
// The following defines conflict with our identifiers:
# undef CONST
// `wingdi.h` defines a TRANSPARENT macro that conflicts with X(TRANSPARENT) entry in kernel/constids.inc
# undef TRANSPARENT
#endif
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
#define YOSYS_NAMESPACE Yosys
#define PRIVATE_NAMESPACE_BEGIN namespace {
#define PRIVATE_NAMESPACE_END }
#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
#define YOSYS_NAMESPACE_END }
#define YOSYS_NAMESPACE_PREFIX Yosys::
#define USING_YOSYS_NAMESPACE using namespace Yosys;
#if defined(__GNUC__) || defined(__clang__)
# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
#elif defined(_MSC_VER)
# define YS_ATTRIBUTE(...)
#else
# define YS_ATTRIBUTE(...)
#endif
#if defined(__GNUC__) || defined(__clang__)
# define YS_MAYBE_UNUSED __attribute__((__unused__))
#else
# define YS_MAYBE_UNUSED
#endif
#if __cplusplus >= 201703L
# define YS_FALLTHROUGH [[fallthrough]];
#elif defined(__clang__)
# define YS_FALLTHROUGH [[clang::fallthrough]];
#elif defined(__GNUC__)
# define YS_FALLTHROUGH [[gnu::fallthrough]];
#else
# define YS_FALLTHROUGH
#endif
YOSYS_NAMESPACE_BEGIN
// Note: All headers included in hashlib.h must be included
// outside of YOSYS_NAMESPACE before this or bad things will happen.
#ifdef HASHLIB_H
# undef HASHLIB_H
# include "kernel/hashlib.h"
#else
# include "kernel/hashlib.h"
# undef HASHLIB_H
#endif
using std::vector;
using std::string;
using std::tuple;
using std::pair;
using std::make_tuple;
using std::make_pair;
using std::get;
using std::min;
using std::max;
// A primitive shared string implementation that does not
// move its .c_str() when the object is copied or moved.
struct shared_str {
std::shared_ptr<string> content;
shared_str() { }
shared_str(string s) { content = std::shared_ptr<string>(new string(s)); }
shared_str(const char *s) { content = std::shared_ptr<string>(new string(s)); }
const char *c_str() const { return content->c_str(); }
const string &str() const { return *content; }
bool operator==(const shared_str &other) const { return *content == *other.content; }
unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
};
using hashlib::mkhash;
using hashlib::mkhash_init;
using hashlib::mkhash_add;
using hashlib::mkhash_xorshift;
using hashlib::hash_ops;
using hashlib::hash_cstr_ops;
using hashlib::hash_ptr_ops;
using hashlib::hash_obj_ops;
using hashlib::dict;
using hashlib::idict;
using hashlib::pool;
using hashlib::mfp;
namespace RTLIL {
struct IdString;
struct Const;
struct SigBit;
struct SigSpec;
struct Wire;
struct Cell;
struct Memory;
struct Process;
struct Module;
struct Design;
struct Monitor;
struct Selection;
struct SigChunk;
enum State : unsigned char;
typedef std::pair<SigSpec, SigSpec> SigSig;
namespace ID {}
}
namespace AST {
struct AstNode;
}
using RTLIL::IdString;
using RTLIL::Const;
using RTLIL::SigBit;
using RTLIL::SigSpec;
using RTLIL::Wire;
using RTLIL::Cell;
using RTLIL::Module;
using RTLIL::Design;
using RTLIL::State;
using RTLIL::SigChunk;
using RTLIL::SigSig;
namespace hashlib {
template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Process*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Process*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
}
void memhasher_on();
void memhasher_off();
void memhasher_do();
extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner();
int ceil_log2(int x) YS_ATTRIBUTE(const);
inline std::string vstringf(const char *fmt, va_list ap)
{
// For the common case of strings shorter than 128, save a heap
// allocation by using a stack allocated buffer.
const int kBufSize = 128;
char buf[kBufSize];
buf[0] = '\0';
va_list apc;
va_copy(apc, ap);
int n = vsnprintf(buf, kBufSize, fmt, apc);
va_end(apc);
if (n < kBufSize)
return std::string(buf);
std::string string;
char *str = NULL;
#if defined(_WIN32 )|| defined(__CYGWIN__)
int sz = 2 * kBufSize, rc;
while (1) {
va_copy(apc, ap);
str = (char*)realloc(str, sz);
rc = vsnprintf(str, sz, fmt, apc);
va_end(apc);
if (rc >= 0 && rc < sz)
break;
sz *= 2;
}
if (str != NULL) {
string = str;
free(str);
}
return string;
#else
if (vasprintf(&str, fmt, ap) < 0)
str = NULL;
if (str != NULL) {
string = str;
free(str);
}
return string;
#endif
}
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
inline std::string stringf(const char *fmt, ...)
{
std::string string;
va_list ap;
va_start(ap, fmt);
string = vstringf(fmt, ap);
va_end(ap);
return string;
}
int readsome(std::istream &f, char *s, int n);
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
bool patmatch(const char *pattern, const char *string);
#if !defined(YOSYS_DISABLE_SPAWN)
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
#endif
std::string get_base_tmpdir();
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false);
bool check_directory_exists(const std::string& dirname);
bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname);
bool create_directory(const std::string& dirname);
std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); }
inline int GetSize(RTLIL::Wire *wire);
extern int autoidx;
extern int yosys_xtrace;
RTLIL::IdString new_id(std::string file, int line, std::string func);
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
#define NEW_ID \
YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
#define NEW_ID_SUFFIX(suffix) \
YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
// Create a statically allocated IdString object, using for example ID::A or ID($add).
//
// Recipe for Converting old code that is using conversion of strings like ID::A and
// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for
// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary.
//
// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename>
//
#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
namespace ID = RTLIL::ID;
namespace hashlib {
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
}
YOSYS_NAMESPACE_END
#endif

View File

@ -31,7 +31,8 @@ struct LogPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" log string\n");
log(" log [options] string\n");
log(" log [ -push | -pop ]\n");
log("\n");
log("Print the given string to the screen and/or the log file. This is useful for TCL\n");
log("scripts, because the TCL command \"puts\" only goes to stdout but not to\n");
@ -52,14 +53,26 @@ struct LogPass : public Pass {
log(" -n\n");
log(" do not append a newline\n");
log("\n");
log(" -header\n");
log(" log a pass header\n");
log("\n");
log(" -push\n");
log(" push a new level on the pass counter\n");
log("\n");
log(" -push\n");
log(" pop from the pass counter\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design*) override
void execute(std::vector<std::string> args, RTLIL::Design* design) override
{
size_t argidx;
bool to_stdout = false;
bool to_stderr = false;
bool to_log = true;
bool newline = true;
bool header = false;
bool push = false;
bool pop = false;
std::string text;
for (argidx = 1; argidx < args.size(); argidx++)
@ -68,15 +81,30 @@ struct LogPass : public Pass {
else if (args[argidx] == "-stderr") to_stderr = true;
else if (args[argidx] == "-nolog") to_log = false;
else if (args[argidx] == "-n") newline = false;
else if (args[argidx] == "-header") header = true;
else if (args[argidx] == "-push") push = true;
else if (args[argidx] == "-pop") pop = true;
else break;
}
if ((push || pop) && args.size() != 2)
log_cmd_error("Bad usage: 'log -push' or 'log -pop' must be used without other arguments.\n");
if (push) { log_push(); return; }
if (pop) { log_pop(); return; }
for (; argidx < args.size(); argidx++)
text += args[argidx] + ' ';
if (!text.empty()) text.resize(text.size()-1);
if (to_stdout) fprintf(stdout, (newline ? "%s\n" : "%s"), text.c_str());
if (to_stderr) fprintf(stderr, (newline ? "%s\n" : "%s"), text.c_str());
if (to_log) log ( (newline ? "%s\n" : "%s"), text.c_str());
const char *fmtline = newline ? "%s\n" : "%s";
if (to_stdout) fprintf(stdout, fmtline, text.c_str());
if (to_stderr) fprintf(stderr, fmtline, text.c_str());
if (to_log) {
if (!header) log(fmtline, text.c_str());
else log_header(design, fmtline, text.c_str());
}
}
} LogPass;

View File

@ -36,7 +36,8 @@ struct cell_area_t {
struct statdata_t
{
#define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \
X(num_processes)
#define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
@ -90,6 +91,11 @@ struct statdata_t
for (auto wire : mod->selected_wires())
{
if (wire->port_input || wire->port_output) {
num_ports++;
num_port_bits += wire->width;
}
if (wire->name.isPublic()) {
num_pub_wires++;
num_pub_wire_bits += wire->width;
@ -239,6 +245,8 @@ struct statdata_t
log(" Number of wire bits: %6u\n", num_wire_bits);
log(" Number of public wires: %6u\n", num_pub_wires);
log(" Number of public wire bits: %6u\n", num_pub_wire_bits);
log(" Number of ports: %6u\n", num_ports);
log(" Number of port bits: %6u\n", num_port_bits);
log(" Number of memories: %6u\n", num_memories);
log(" Number of memory bits: %6u\n", num_memory_bits);
log(" Number of processes: %6u\n", num_processes);
@ -284,6 +292,8 @@ struct statdata_t
log(" \"num_wire_bits\": %u,\n", num_wire_bits);
log(" \"num_pub_wires\": %u,\n", num_pub_wires);
log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits);
log(" \"num_ports\": %u,\n", num_ports);
log(" \"num_port_bits\": %u,\n", num_port_bits);
log(" \"num_memories\": %u,\n", num_memories);
log(" \"num_memory_bits\": %u,\n", num_memory_bits);
log(" \"num_processes\": %u,\n", num_processes);
@ -494,6 +504,8 @@ struct StatPass : public Pass {
design->scratchpad_set_int("stat.num_wire_bits", data.num_wire_bits);
design->scratchpad_set_int("stat.num_pub_wires", data.num_pub_wires);
design->scratchpad_set_int("stat.num_pub_wire_bits", data.num_pub_wire_bits);
design->scratchpad_set_int("stat.num_ports", data.num_ports);
design->scratchpad_set_int("stat.num_port_bits", data.num_port_bits);
design->scratchpad_set_int("stat.num_memories", data.num_memories);
design->scratchpad_set_int("stat.num_memory_bits", data.num_memory_bits);
design->scratchpad_set_int("stat.num_processes", data.num_processes);

View File

@ -47,7 +47,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
{
if (design->module(cell->type) != nullptr)
continue;
if (cell->type.begins_with("$__"))
if (cell->type.begins_with("$") && !cell->type.begins_with("$__"))
continue;
for (auto &pattern : celltypes)
if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))

View File

@ -415,7 +415,7 @@ struct MemoryMapPass : public Pass {
log(" to any of the values.\n");
log("\n");
log(" -iattr\n");
log(" for -attr, ignore case of <value>.\n");
log(" for -attr, suppress case sensitivity in matching of <value>.\n");
log("\n");
log(" -rom-only\n");
log(" only perform conversion for ROMs (memories with no write ports).\n");

View File

@ -443,13 +443,6 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (!raw_used_signals.check_any(s1)) {
// delete wires that aren't used by anything directly
goto delete_this_wire;
} else
if (!used_signals.check_any(s2)) {
// this path shouldn't be possible: this wire is used directly (otherwise it would get cleaned up above), and indirectly
// used wires are a superset of those used directly
log_assert(false);
// delete wires that aren't used by anything indirectly, even though other wires may alias it
goto delete_this_wire;
}
if (0)

View File

@ -183,7 +183,7 @@ struct OptDemorganPass : public Pass {
{
log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n");
int argidx = 0;
int argidx = 1;
extra_args(args, argidx, design);
unsigned int cells_changed = 0;

View File

@ -289,7 +289,7 @@ struct Ice40DspPass : public Pass {
log("\n");
log("Pack input registers (A, B, {C,D}; with optional hold), pipeline registers\n");
log("({F,J,K,G}, H), output registers (O -- full 32-bits or lower 16-bits only; with\n");
log("optional hold), and post-adder into into the SB_MAC16 resource.\n");
log("optional hold), and post-adder into the SB_MAC16 resource.\n");
log("\n");
log("Multiply-accumulate operations using the post-adder with feedback on the {C,D}\n");
log("input will be folded into the DSP. In this scenario only, resetting the\n");

View File

@ -237,7 +237,7 @@ struct InitValWorker
return true;
if (ff.has_ce && initconst(ff.sig_ce.as_bit()) == (ff.pol_ce ? State::S0 : State::S1))
continue;
if (ff.has_srst && initconst(ff.sig_ce.as_bit()) == (ff.pol_srst ? State::S1 : State::S0))
if (ff.has_srst && initconst(ff.sig_srst.as_bit()) == (ff.pol_srst ? State::S1 : State::S0))
continue;
return true;

View File

@ -48,6 +48,7 @@ OBJS += passes/techmap/dfflegalize.o
OBJS += passes/techmap/dffunmap.o
OBJS += passes/techmap/flowmap.o
OBJS += passes/techmap/extractinv.o
OBJS += passes/techmap/cellmatch.o
endif
ifeq ($(DISABLE_SPAWN),0)

View File

@ -804,8 +804,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (std::string dont_use_cell : dont_use_cells) {
dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str());
}
bool first_lib = true;
for (std::string liberty_file : liberty_files) {
abc_script += stringf("read_lib %s -w \"%s\" ; ", dont_use_args.c_str(), liberty_file.c_str());
abc_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args.c_str(), first_lib ? "" : "-m", liberty_file.c_str());
first_lib = false;
}
for (std::string liberty_file : genlib_files)
abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str());

312
passes/techmap/cellmatch.cc Normal file
View File

@ -0,0 +1,312 @@
#include "kernel/celltypes.h"
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/sigtools.h"
#include "kernel/consteval.h"
#include "kernel/utils.h"
#include <algorithm>
USING_YOSYS_NAMESPACE
YOSYS_NAMESPACE_BEGIN
// return module's inputs in canonical order
SigSpec module_inputs(Module *m)
{
SigSpec ret;
for (auto port : m->ports) {
Wire *w = m->wire(port);
if (!w->port_input)
continue;
if (w->width != 1)
log_error("Unsupported wide port (%s) of non-unit width found in module %s.\n",
log_id(w), log_id(m));
ret.append(w);
}
return ret;
}
// return module's outputs in canonical order
SigSpec module_outputs(Module *m)
{
SigSpec ret;
for (auto port : m->ports) {
Wire *w = m->wire(port);
if (!w->port_output)
continue;
if (w->width != 1)
log_error("Unsupported wide port (%s) of non-unit width found in module %s.\n",
log_id(w), log_id(m));
ret.append(w);
}
return ret;
}
// Permute the inputs of a single-output k-LUT according to varmap
uint64_t permute_lut(uint64_t lut, const std::vector<int> &varmap)
{
int k = varmap.size();
uint64_t ret = 0;
// Index j iterates over all bits in lut.
// When (j & 1 << n) is true,
// (lut & 1 << j) represents an output value where input var n is set.
// We use this fact to permute the LUT such that
// every variable n is remapped to varmap[n].
for (int j = 0; j < 1 << k; j++) {
int m = 0;
for (int l = 0; l < k; l++)
if (j & 1 << l)
m |= 1 << varmap[l];
if (lut & 1 << m)
ret |= 1 << j;
}
return ret;
}
// Find the LUT with the minimum integer representation
// such that it is a permutation of the given lut.
// The resulting LUT becomes the "fingerprint" of the "permutation class".
// This function checks all possible input permutations.
uint64_t p_class(int k, uint64_t lut)
{
std::vector<int> map;
for (int j = 0; j < k; j++)
map.push_back(j);
uint64_t repr = ~(uint64_t) 0;
std::vector<int> repr_vars;
while (true) {
uint64_t perm = permute_lut(lut, map);
if (perm <= repr) {
repr = perm;
repr_vars = map;
}
if (!std::next_permutation(map.begin(), map.end()))
break;
}
return repr;
}
// Represent module m as N single-output k-LUTs
// where k is the number of module inputs,
// and N is the number of module outputs.
bool derive_module_luts(Module *m, std::vector<uint64_t> &luts)
{
CellTypes ff_types;
ff_types.setup_stdcells_mem();
for (auto cell : m->cells()) {
if (ff_types.cell_known(cell->type)) {
log("Ignoring module '%s' which isn't purely combinational.\n", log_id(m));
return false;
}
}
SigSpec inputs = module_inputs(m);
SigSpec outputs = module_outputs(m);
int ninputs = inputs.size(), noutputs = outputs.size();
if (ninputs > 6) {
log_warning("Skipping module %s with more than 6 inputs bits.\n", log_id(m));
return false;
}
luts.clear();
luts.resize(noutputs);
ConstEval ceval(m);
for (int i = 0; i < 1 << ninputs; i++) {
ceval.clear();
for (int j = 0; j < ninputs; j++)
ceval.set(inputs[j], (i & (1 << j)) ? State::S1 : State::S0);
for (int j = 0; j < noutputs; j++) {
SigSpec bit = outputs[j];
if (!ceval.eval(bit)) {
log("Failed to evaluate output '%s' in module '%s'.\n",
log_signal(outputs[j]), log_id(m));
return false;
}
log_assert(ceval.eval(bit));
if (bit[0] == State::S1)
luts[j] |= 1 << i;
}
}
return true;
}
struct CellmatchPass : Pass {
CellmatchPass() : Pass("cellmatch", "match cells to their targets in cell library") {}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" cellmatch -lib <design> [module selection]\n");
log("\n");
log("This pass identifies functionally equivalent counterparts between each of the\n");
log("selected modules and a module from the secondary design <design>. For every such\n");
log("correspondence found, a techmap rule is generated for mapping instances of the\n");
log("former to instances of the latter. This techmap rule is saved in yet another\n");
log("design called '$cellmatch', which is created if non-existent.\n");
log("\n");
log("This pass restricts itself to combinational modules. Modules are functionally\n");
log("equivalent as long as their truth tables are identical upto a permutation of\n");
log("inputs and outputs. The supported number of inputs is limited to 6.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *d) override
{
log_header(d, "Executing CELLMATCH pass. (match cells)\n");
size_t argidx;
bool lut_attrs = false;
Design *lib = NULL;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-lut_attrs") {
// an undocumented debugging option
lut_attrs = true;
} else if (args[argidx] == "-lib" && argidx + 1 < args.size()) {
if (!saved_designs.count(args[++argidx]))
log_cmd_error("No design '%s' found!\n", args[argidx].c_str());
lib = saved_designs.at(args[argidx]);
} else {
break;
}
}
extra_args(args, argidx, d);
if (!lib && !lut_attrs)
log_cmd_error("Missing required -lib option.\n");
struct Target {
Module *module;
std::vector<uint64_t> luts;
};
dict<pool<uint64_t>, std::vector<Target>> targets;
if (lib)
for (auto m : lib->modules()) {
pool<uint64_t> p_classes;
// produce a fingerprint in p_classes
int ninputs = module_inputs(m).size();
std::vector<uint64_t> luts;
if (!derive_module_luts(m, luts))
continue;
for (auto lut : luts)
p_classes.insert(p_class(ninputs, lut));
log_debug("Registered %s\n", log_id(m));
// save as a viable target
targets[p_classes].push_back(Target{m, luts});
}
auto r = saved_designs.emplace("$cellmatch", nullptr);
if (r.second)
r.first->second = new Design;
Design *map_design = r.first->second;
for (auto m : d->selected_whole_modules_warn()) {
std::vector<uint64_t> luts;
if (!derive_module_luts(m, luts))
continue;
SigSpec inputs = module_inputs(m);
SigSpec outputs = module_outputs(m);
if (lut_attrs) {
int no = 0;
for (auto bit : outputs) {
log_assert(bit.is_wire());
bit.wire->attributes[ID(p_class)] = p_class(inputs.size(), luts[no]);
bit.wire->attributes[ID(lut)] = luts[no++];
}
}
// fingerprint
pool<uint64_t> p_classes;
for (auto lut : luts)
p_classes.insert(p_class(inputs.size(), lut));
for (auto target : targets[p_classes]) {
log_debug("Candidate %s for matching to %s\n", log_id(target.module), log_id(m));
SigSpec target_inputs = module_inputs(target.module);
SigSpec target_outputs = module_outputs(target.module);
if (target_inputs.size() != inputs.size())
continue;
if (target_outputs.size() != outputs.size())
continue;
std::vector<int> input_map;
for (int i = 0; i < inputs.size(); i++)
input_map.push_back(i);
bool found_match = false;
// For each input_map
while (!found_match) {
std::vector<int> output_map;
for (int i = 0; i < outputs.size(); i++)
output_map.push_back(i);
// For each output_map
while (!found_match) {
int out_no = 0;
bool match = true;
for (auto lut : luts) {
if (permute_lut(target.luts[output_map[out_no++]], input_map) != lut) {
match = false;
break;
}
}
if (match) {
log("Module %s matches %s\n", log_id(m), log_id(target.module));
// Add target.module to map_design ("$cellmatch")
// as a techmap rule to match m and replace it with target.module
Module *map = map_design->addModule(stringf("\\_60_%s_%s", log_id(m), log_id(target.module)));
Cell *cell = map->addCell(ID::_TECHMAP_REPLACE_, target.module->name);
map->attributes[ID(techmap_celltype)] = m->name.str();
for (int i = 0; i < outputs.size(); i++) {
log_assert(outputs[i].is_wire());
Wire *w = map->addWire(outputs[i].wire->name, 1);
w->port_id = outputs[i].wire->port_id;
w->port_output = true;
log_assert(target_outputs[output_map[i]].is_wire());
cell->setPort(target_outputs[output_map[i]].wire->name, w);
}
for (int i = 0; i < inputs.size(); i++) {
log_assert(inputs[i].is_wire());
Wire *w = map->addWire(inputs[i].wire->name, 1);
w->port_id = inputs[i].wire->port_id;
w->port_input = true;
log_assert(target_inputs[input_map[i]].is_wire());
cell->setPort(target_inputs[input_map[i]].wire->name, w);
}
map->fixup_ports();
found_match = true;
}
if (!std::next_permutation(output_map.begin(), output_map.end()))
break;
}
if (!std::next_permutation(input_map.begin(), input_map.end()))
break;
}
}
}
}
} CellmatchPass;
YOSYS_NAMESPACE_END

View File

@ -336,6 +336,11 @@ struct TechmapWorker
if (c->type.begins_with("\\$"))
c->type = c->type.substr(1);
if (c->type == ID::_TECHMAP_PLACEHOLDER_ && tpl_cell->has_attribute(ID::techmap_chtype)) {
c->type = RTLIL::escape_id(tpl_cell->get_string_attribute(ID::techmap_chtype));
c->attributes.erase(ID::techmap_chtype);
}
vector<IdString> autopurge_ports;
@ -1135,6 +1140,10 @@ struct TechmapPass : public Pass {
log("new wire alias to be created and named as above but with the `_TECHMAP_REPLACE_'\n");
log("prefix also substituted.\n");
log("\n");
log("A cell with the type _TECHMAP_PLACEHOLDER_ in the map file will have its type\n");
log("changed to the content of the techmap_chtype attribute. This allows for choosing\n");
log("the cell type dynamically.\n");
log("\n");
log("See 'help extract' for a pass that does the opposite thing.\n");
log("\n");
log("See 'help flatten' for a pass that does flatten the design (which is\n");

View File

@ -169,12 +169,14 @@ struct SynthAnlogicPass : public ScriptPass
if (check_label("map_ram"))
{
std::string args = "";
if (nobram)
args += " -no-auto-block";
if (nolutram)
args += " -no-auto-distributed";
if (help_mode)
args += " [-no-auto-block] [-no-auto-distributed]";
else {
if (nobram)
args += " -no-auto-block";
if (nolutram)
args += " -no-auto-distributed";
}
run("memory_libmap -lib +/anlogic/lutrams.txt -lib +/anlogic/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)");
run("techmap -map +/anlogic/lutrams_map.v -map +/anlogic/brams_map.v");
}

View File

@ -35,3 +35,4 @@ $(eval $(call add_share_file,share,techlibs/common/abc9_map.v))
$(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v))
$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v))
$(eval $(call add_share_file,share,techlibs/common/cmp2softlogic.v))
$(eval $(call add_share_file,share/choices,techlibs/common/choices/kogge-stone.v))

View File

@ -0,0 +1,54 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2024 Martin Povišer <povik@cutebit.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
(* techmap_celltype = "$lcu" *)
module _80_lcu_kogge_stone (P, G, CI, CO);
parameter WIDTH = 2;
(* force_downto *)
input [WIDTH-1:0] P, G;
input CI;
(* force_downto *)
output [WIDTH-1:0] CO;
integer i, j;
(* force_downto *)
reg [WIDTH-1:0] p, g;
wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
always @* begin
p = P;
g = G;
// in almost all cases CI will be constant zero
g[0] = g[0] | (p[0] & CI);
for (i = 0; i < $clog2(WIDTH); i = i + 1) begin
// iterate in reverse so we don't confuse a result from this stage and the previous
for (j = WIDTH - 1; j >= 2**i; j = j - 1) begin
g[j] = g[j] | p[j] & g[j - 2**i];
p[j] = p[j] & p[j - 2**i];
end
end
end
assign CO = g;
endmodule

View File

@ -902,18 +902,34 @@ endgenerate
endmodule
// --------------------------------------------------------
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//-
//- $macc (A, B, Y)
//-
//- Multiply and accumulate.
//- A building block for summing any number of negated and unnegated signals
//- and arithmetic products of pairs of signals. Cell port A concatenates pairs
//- of signals to be multiplied together. When the second signal in a pair is zero
//- length, a constant 1 is used instead as the second factor. Cell port B
//- concatenates 1-bit-wide signals to also be summed, such as "carry in" in adders.
//- Typically created by the `alumacc` pass, which transforms $add and $mul
//- into $macc cells.
module \$macc (A, B, Y);
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
// CONFIG determines the layout of A, as explained below
parameter CONFIG = 4'b0000;
parameter CONFIG_WIDTH = 4;
input [A_WIDTH-1:0] A;
input [B_WIDTH-1:0] B;
output reg [Y_WIDTH-1:0] Y;
// In the terms used for this cell, there's mixed meanings for the term "port". To disambiguate:
// A cell port is for example the A input (it is constructed in C++ as cell->setPort(ID::A, ...))
// Multiplier ports are pairs of multiplier inputs ("factors").
// If the second signal in such a pair is zero length, no multiplication is necessary, and the first signal is just added to the sum.
input [A_WIDTH-1:0] A; // Cell port A is the concatenation of all arithmetic ports
input [B_WIDTH-1:0] B; // Cell port B is the concatenation of single-bit unsigned signals to be also added to the sum
output reg [Y_WIDTH-1:0] Y; // Output sum
// Xilinx XSIM does not like $clog2() below..
function integer my_clog2;
@ -929,10 +945,42 @@ function integer my_clog2;
end
endfunction
// Bits that a factor's length field in CONFIG per factor in cell port A
localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1;
// Number of multiplier ports
localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits);
// Minium bit width of an induction variable to iterate over all bits of cell port A
localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1;
// In this pseudocode, u(foo) means an unsigned int that's foo bits long.
// The CONFIG parameter carries the following information:
// struct CONFIG {
// u4 num_bits;
// struct port_field {
// bool is_signed;
// bool is_subtract;
// u(num_bits) factor1_len;
// u(num_bits) factor2_len;
// }[num_ports];
// };
// The A cell port carries the following information:
// struct A {
// u(CONFIG.port_field[0].factor1_len) port0factor1;
// u(CONFIG.port_field[0].factor2_len) port0factor2;
// u(CONFIG.port_field[1].factor1_len) port1factor1;
// u(CONFIG.port_field[1].factor2_len) port1factor2;
// ...
// };
// and log(sizeof(A)) is num_abits.
// No factor1 may have a zero length.
// A factor2 having a zero length implies factor2 is replaced with a constant 1.
// Additionally, B is an array of 1-bit-wide unsigned integers to also be summed up.
// Finally, we have:
// Y = port0factor1 * port0factor2 + port1factor1 * port1factor2 + ...
// * B[0] + B[1] + ...
function [2*num_ports*num_abits-1:0] get_port_offsets;
input [CONFIG_WIDTH-1:0] cfg;
integer i, cursor;

View File

@ -207,7 +207,7 @@ module _90_fa (A, B, C, X, Y);
endmodule
(* techmap_celltype = "$lcu" *)
module _90_lcu (P, G, CI, CO);
module _90_lcu_brent_kung (P, G, CI, CO);
parameter WIDTH = 2;
(* force_downto *)

View File

@ -308,12 +308,14 @@ struct SynthEcp5Pass : public ScriptPass
if (check_label("map_ram"))
{
std::string args = "";
if (nobram)
args += " -no-auto-block";
if (nolutram)
args += " -no-auto-distributed";
if (help_mode)
args += " [-no-auto-block] [-no-auto-distributed]";
else {
if (nobram)
args += " -no-auto-block";
if (nolutram)
args += " -no-auto-distributed";
}
run("memory_libmap -lib +/ecp5/lutrams.txt -lib +/ecp5/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)");
run("techmap -map +/ecp5/lutrams_map.v -map +/ecp5/brams_map.v");
}

View File

@ -113,7 +113,31 @@ module EFX_GBUFCE(
endmodule
module EFX_RAM_5K(
module EFX_RAM_5K
# (
parameter READ_WIDTH = 20,
parameter WRITE_WIDTH = 20,
localparam READ_ADDR_WIDTH =
(READ_WIDTH == 16) ? 8 : // 256x16
(READ_WIDTH == 8) ? 9 : // 512x8
(READ_WIDTH == 4) ? 10 : // 1024x4
(READ_WIDTH == 2) ? 11 : // 2048x2
(READ_WIDTH == 1) ? 12 : // 4096x1
(READ_WIDTH == 20) ? 8 : // 256x20
(READ_WIDTH == 10) ? 9 : // 512x10
(READ_WIDTH == 5) ? 10 : -1, // 1024x5
localparam WRITE_ADDR_WIDTH =
(WRITE_WIDTH == 16) ? 8 : // 256x16
(WRITE_WIDTH == 8) ? 9 : // 512x8
(WRITE_WIDTH == 4) ? 10 : // 1024x4
(WRITE_WIDTH == 2) ? 11 : // 2048x2
(WRITE_WIDTH == 1) ? 12 : // 4096x1
(WRITE_WIDTH == 20) ? 8 : // 256x20
(WRITE_WIDTH == 10) ? 9 : // 512x10
(WRITE_WIDTH == 5) ? 10 : -1 // 1024x5
)
(
input [WRITE_WIDTH-1:0] WDATA,
input [WRITE_ADDR_WIDTH-1:0] WADDR,
input WE,
@ -126,8 +150,6 @@ module EFX_RAM_5K(
(* clkbuf_sink *)
input RCLK
);
parameter READ_WIDTH = 20;
parameter WRITE_WIDTH = 20;
parameter OUTPUT_REG = 1'b0;
parameter RCLK_POLARITY = 1'b1;
parameter RE_POLARITY = 1'b1;
@ -155,25 +177,4 @@ module EFX_RAM_5K(
parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
localparam READ_ADDR_WIDTH =
(READ_WIDTH == 16) ? 8 : // 256x16
(READ_WIDTH == 8) ? 9 : // 512x8
(READ_WIDTH == 4) ? 10 : // 1024x4
(READ_WIDTH == 2) ? 11 : // 2048x2
(READ_WIDTH == 1) ? 12 : // 4096x1
(READ_WIDTH == 20) ? 8 : // 256x20
(READ_WIDTH == 10) ? 9 : // 512x10
(READ_WIDTH == 5) ? 10 : -1; // 1024x5
localparam WRITE_ADDR_WIDTH =
(WRITE_WIDTH == 16) ? 8 : // 256x16
(WRITE_WIDTH == 8) ? 9 : // 512x8
(WRITE_WIDTH == 4) ? 10 : // 1024x4
(WRITE_WIDTH == 2) ? 11 : // 2048x2
(WRITE_WIDTH == 1) ? 12 : // 4096x1
(WRITE_WIDTH == 20) ? 8 : // 256x20
(WRITE_WIDTH == 10) ? 9 : // 512x10
(WRITE_WIDTH == 5) ? 10 : -1; // 1024x5
endmodule

View File

@ -161,9 +161,13 @@ struct SynthEfinixPass : public ScriptPass
if (check_label("map_ram"))
{
std::string args = "";
if (nobram)
args += " -no-auto-block";
run("memory_libmap -lib +/efinix/brams.txt" + args);
if (help_mode)
args += " [-no-auto-block]";
else {
if (nobram)
args += " -no-auto-block";
}
run("memory_libmap -lib +/efinix/brams.txt" + args, "(-no-auto-block if -nobram)");
run("techmap -map +/efinix/brams_map.v");
}

View File

@ -320,7 +320,7 @@ struct SynthPass : public ScriptPass
run("opt_clean");
}
if (check_label("map_ram")) {
if (check_label("map_ram", "(unless -noregfile)")) {
// RegFile extraction
if (!noregfile) {
run("memory_libmap -lib +/fabulous/ram_regfile.txt");
@ -342,7 +342,7 @@ struct SynthPass : public ScriptPass
}
if (check_label("map_iopad", "(if -iopad)")) {
if (iopad) {
if (iopad || help_mode) {
run("opt -full");
run("iopadmap -bits -outpad $__FABULOUS_OBUF I:PAD -inpad $__FABULOUS_IBUF O:PAD "
"-toutpad IO_1_bidirectional_frame_config_pass ~T:I:PAD "

View File

@ -230,12 +230,14 @@ struct SynthGowinPass : public ScriptPass
if (check_label("map_ram"))
{
std::string args = "";
if (nobram)
args += " -no-auto-block";
if (nolutram)
args += " -no-auto-distributed";
if (help_mode)
args += " [-no-auto-block] [-no-auto-distributed]";
else {
if (nobram)
args += " -no-auto-block";
if (nolutram)
args += " -no-auto-distributed";
}
run("memory_libmap -lib +/gowin/lutrams.txt -lib +/gowin/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)");
run("techmap -map +/gowin/lutrams_map.v -map +/gowin/brams_map.v");
}

View File

@ -353,12 +353,14 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_ram"))
{
std::string args = "";
if (!spram)
args += " -no-auto-huge";
if (nobram)
args += " -no-auto-block";
if (help_mode)
args += " [-no-auto-huge] [-no-auto-block]";
else {
if (!spram)
args += " -no-auto-huge";
if (nobram)
args += " -no-auto-block";
}
run("memory_libmap -lib +/ice40/brams.txt -lib +/ice40/spram.txt" + args, "(-no-auto-huge unless -spram, -no-auto-block if -nobram)");
run("techmap -map +/ice40/brams_map.v -map +/ice40/spram_map.v");
run("ice40_braminit");

View File

@ -20,10 +20,7 @@ $(eval $(call add_share_file,share/intel_alm/cyclonev,techlibs/intel_alm/cyclone
# RAM
$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m10k.txt))
$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m10k_map.v))
$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k.txt))
$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k_map.v))
$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt))
# Miscellaneous
$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/megafunction_bb.v))
$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/quartus_rename.v))

View File

@ -1,4 +1,4 @@
// The core logic primitive of the Cyclone V/10GX is the Adaptive Logic Module
// The core logic primitive of the Cyclone V is the Adaptive Logic Module
// (ALM). Each ALM is made up of an 8-input, 2-output look-up table, covered
// in this file, connected to combinational outputs, a carry chain, and four
// D flip-flops (which are covered as MISTRAL_FF in dff_sim.v).
@ -77,14 +77,6 @@
// SUMOUT 368 1342 1323 887 927 - 785 -
// CARRYOUT 71 1082 1062 866 813 - 1198 -
// Arria V LUT output timings (picoseconds):
//
// CARRY A B C D E F G
// COMBOUT - 387 375 316 317 - 76 319 (LUT6)
// COMBOUT - 387 375 316 317 218 76 319 (LUT7)
// SUMOUT 249 744 732 562 576 - 511 -
// CARRYOUT 19 629 623 530 514 - 696 -
(* abc9_lut=2, lib_whitebox *)
module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q);
@ -100,26 +92,6 @@ specify
(F => Q) = 97;
endspecify
`endif
`ifdef arriav
specify
(A => Q) = 387;
(B => Q) = 375;
(C => Q) = 316;
(D => Q) = 317;
(E => Q) = 319;
(F => Q) = 76;
endspecify
`endif
`ifdef cyclone10gx
specify
(A => Q) = 275;
(B => Q) = 272;
(C => Q) = 175;
(D => Q) = 165;
(E => Q) = 162;
(F => Q) = 53;
endspecify
`endif
assign Q = LUT >> {F, E, D, C, B, A};
@ -140,24 +112,6 @@ specify
(E => Q) = 97;
endspecify
`endif
`ifdef arriav
specify
(A => Q) = 375;
(B => Q) = 316;
(C => Q) = 317;
(D => Q) = 319;
(E => Q) = 76;
endspecify
`endif
`ifdef cyclone10gx
specify
(A => Q) = 272;
(B => Q) = 175;
(C => Q) = 165;
(D => Q) = 162;
(E => Q) = 53;
endspecify
`endif
assign Q = LUT >> {E, D, C, B, A};
@ -177,22 +131,6 @@ specify
(D => Q) = 97;
endspecify
`endif
`ifdef arriav
specify
(A => Q) = 316;
(B => Q) = 317;
(C => Q) = 319;
(D => Q) = 76;
endspecify
`endif
`ifdef cyclone10gx
specify
(A => Q) = 175;
(B => Q) = 165;
(C => Q) = 162;
(D => Q) = 53;
endspecify
`endif
assign Q = LUT >> {D, C, B, A};
@ -211,20 +149,6 @@ specify
(C => Q) = 97;
endspecify
`endif
`ifdef arriav
specify
(A => Q) = 316;
(B => Q) = 317;
(C => Q) = 76;
endspecify
`endif
`ifdef cyclone10gx
specify
(A => Q) = 165;
(B => Q) = 162;
(C => Q) = 53;
endspecify
`endif
assign Q = LUT >> {C, B, A};
@ -242,18 +166,6 @@ specify
(B => Q) = 97;
endspecify
`endif
`ifdef arriav
specify
(A => Q) = 316;
(B => Q) = 76;
endspecify
`endif
`ifdef cyclone10gx
specify
(A => Q) = 162;
(B => Q) = 53;
endspecify
`endif
assign Q = LUT >> {B, A};
@ -268,16 +180,6 @@ specify
(A => Q) = 97;
endspecify
`endif
`ifdef arriav
specify
(A => Q) = 76;
endspecify
`endif
`ifdef cyclone10gx
specify
(A => Q) = 53;
endspecify
`endif
assign Q = ~A;
@ -306,40 +208,6 @@ specify
(CI => CO) = 36; // Divided by 2 to account for there being two ALUT_ARITHs in an ALM)
endspecify
`endif
`ifdef arriav
specify
(A => SO) = 744;
(B => SO) = 732;
(C => SO) = 562;
(D0 => SO) = 576;
(D1 => SO) = 511;
(CI => SO) = 249;
(A => CO) = 629;
(B => CO) = 623;
(C => CO) = 530;
(D0 => CO) = 514;
(D1 => CO) = 696;
(CI => CO) = 10; // Divided by 2 to account for there being two ALUT_ARITHs in an ALM)
endspecify
`endif
`ifdef cyclone10gx
specify
(A => SO) = 644;
(B => SO) = 477;
(C => SO) = 416;
(D0 => SO) = 380;
(D1 => SO) = 431;
(CI => SO) = 276;
(A => CO) = 525;
(B => CO) = 433;
(C => CO) = 712;
(D0 => CO) = 653;
(D1 => CO) = 593;
(CI => CO) = 16;
endspecify
`endif
wire q0, q1;
@ -349,283 +217,3 @@ assign q1 = LUT1 >> {D1, C, B, A};
assign {CO, SO} = q0 + !q1 + CI;
endmodule
/*
// A, B, C0, C1, E0, E1, F0, F1: data inputs
// CARRYIN: carry input
// SHAREIN: shared-arithmetic input
// CLK0, CLK1, CLK2: clock inputs
//
// COMB0, COMB1: combinational outputs
// FF0, FF1, FF2, FF3: DFF outputs
// SUM0, SUM1: adder outputs
// CARRYOUT: carry output
// SHAREOUT: shared-arithmetic output
module MISTRAL_ALM(
input A, B, C0, C1, E0, E1, F0, F1, CARRYIN, SHAREIN, // LUT path
input CLK0, CLK1, CLK2, AC0, AC1, // FF path
output COMB0, COMB1, SUM0, SUM1, CARRYOUT, SHAREOUT,
output FF0, FF1, FF2, FF3
);
parameter LUT0 = 16'b0000;
parameter LUT1 = 16'b0000;
parameter LUT2 = 16'b0000;
parameter LUT3 = 16'b0000;
parameter INIT0 = 1'b0;
parameter INIT1 = 1'b0;
parameter INIT2 = 1'b0;
parameter INIT3 = 1'b0;
parameter C0_MUX = "C0";
parameter C1_MUX = "C1";
parameter F0_MUX = "VCC";
parameter F1_MUX = "GND";
parameter FEEDBACK0 = "FF0";
parameter FEEDBACK1 = "FF2";
parameter ADD_MUX = "LUT";
parameter DFF01_DATA_MUX = "COMB";
parameter DFF23_DATA_MUX = "COMB";
parameter DFF0_CLK = "CLK0";
parameter DFF1_CLK = "CLK0";
parameter DFF2_CLK = "CLK0";
parameter DFF3_CLK = "CLK0";
parameter DFF0_AC = "AC0";
parameter DFF1_AC = "AC0";
parameter DFF2_AC = "AC0";
parameter DFF3_AC = "AC0";
// Feedback muxes from the flip-flop outputs.
wire ff_feedback_mux0, ff_feedback_mux1;
// C-input muxes which can be set to also use the F-input.
wire c0_input_mux, c1_input_mux;
// F-input muxes which can be set to a constant to allow LUT5 use.
wire f0_input_mux, f1_input_mux;
// Adder input muxes to select between shared-arithmetic mode and arithmetic mode.
wire add0_input_mux, add1_input_mux;
// Combinational-output muxes for LUT #1 and LUT #3
wire lut1_comb_mux, lut3_comb_mux;
// Sum-output muxes for LUT #1 and LUT #3
wire lut1_sum_mux, lut3_sum_mux;
// DFF data-input muxes
wire dff01_data_mux, dff23_data_mux;
// DFF clock selectors
wire dff0_clk, dff1_clk, dff2_clk, dff3_clk;
// DFF asynchronous-clear selectors
wire dff0_ac, dff1_ac, dff2_ac, dff3_ac;
// LUT, DFF and adder output wires for routing.
wire lut0_out, lut1a_out, lut1b_out, lut2_out, lut3a_out, lut3b_out;
wire dff0_out, dff1_out, dff2_out, dff3_out;
wire add0_sum, add1_sum, add0_carry, add1_carry;
generate
if (FEEDBACK0 === "FF0")
assign ff_feedback_mux0 = dff0_out;
else if (FEEDBACK0 === "FF1")
assign ff_feedback_mux0 = dff1_out;
else
$error("Invalid FEEDBACK0 setting!");
if (FEEDBACK1 == "FF2")
assign ff_feedback_mux1 = dff2_out;
else if (FEEDBACK1 == "FF3")
assign ff_feedback_mux1 = dff3_out;
else
$error("Invalid FEEDBACK1 setting!");
if (C0_MUX === "C0")
assign c0_input_mux = C0;
else if (C0_MUX === "F1")
assign c0_input_mux = F1;
else if (C0_MUX === "FEEDBACK1")
assign c0_input_mux = ff_feedback_mux1;
else
$error("Invalid C0_MUX setting!");
if (C1_MUX === "C1")
assign c1_input_mux = C1;
else if (C1_MUX === "F0")
assign c1_input_mux = F0;
else if (C1_MUX === "FEEDBACK0")
assign c1_input_mux = ff_feedback_mux0;
else
$error("Invalid C1_MUX setting!");
// F0 == VCC is LUT5
// F0 == F0 is LUT6
// F0 == FEEDBACK is unknown
if (F0_MUX === "VCC")
assign f0_input_mux = 1'b1;
else if (F0_MUX === "F0")
assign f0_input_mux = F0;
else if (F0_MUX === "FEEDBACK0")
assign f0_input_mux = ff_feedback_mux0;
else
$error("Invalid F0_MUX setting!");
// F1 == GND is LUT5
// F1 == F1 is LUT6
// F1 == FEEDBACK is unknown
if (F1_MUX === "GND")
assign f1_input_mux = 1'b0;
else if (F1_MUX === "F1")
assign f1_input_mux = F1;
else if (F1_MUX === "FEEDBACK1")
assign f1_input_mux = ff_feedback_mux1;
else
$error("Invalid F1_MUX setting!");
if (ADD_MUX === "LUT") begin
assign add0_input_mux = ~lut1_sum_mux;
assign add1_input_mux = ~lut3_sum_mux;
end else if (ADD_MUX === "SHARE") begin
assign add0_input_mux = SHAREIN;
assign add1_input_mux = lut1_comb_mux;
end else
$error("Invalid ADD_MUX setting!");
if (DFF01_DATA_MUX === "COMB")
assign dff01_data_mux = COMB0;
else if (DFF01_DATA_MUX === "SUM")
assign dff01_data_mux = SUM0;
else
$error("Invalid DFF01_DATA_MUX setting!");
if (DFF23_DATA_MUX === "COMB")
assign dff23_data_mux = COMB0;
else if (DFF23_DATA_MUX === "SUM")
assign dff23_data_mux = SUM0;
else
$error("Invalid DFF23_DATA_MUX setting!");
if (DFF0_CLK === "CLK0")
assign dff0_clk = CLK0;
else if (DFF0_CLK === "CLK1")
assign dff0_clk = CLK1;
else if (DFF0_CLK === "CLK2")
assign dff0_clk = CLK2;
else
$error("Invalid DFF0_CLK setting!");
if (DFF1_CLK === "CLK0")
assign dff1_clk = CLK0;
else if (DFF1_CLK === "CLK1")
assign dff1_clk = CLK1;
else if (DFF1_CLK === "CLK2")
assign dff1_clk = CLK2;
else
$error("Invalid DFF1_CLK setting!");
if (DFF2_CLK === "CLK0")
assign dff2_clk = CLK0;
else if (DFF2_CLK === "CLK1")
assign dff2_clk = CLK1;
else if (DFF2_CLK === "CLK2")
assign dff2_clk = CLK2;
else
$error("Invalid DFF2_CLK setting!");
if (DFF3_CLK === "CLK0")
assign dff3_clk = CLK0;
else if (DFF3_CLK === "CLK1")
assign dff3_clk = CLK1;
else if (DFF3_CLK === "CLK2")
assign dff3_clk = CLK2;
else
$error("Invalid DFF3_CLK setting!");
if (DFF0_AC === "AC0")
assign dff0_ac = AC0;
else if (DFF0_AC === "AC1")
assign dff0_ac = AC1;
else
$error("Invalid DFF0_AC setting!");
if (DFF1_AC === "AC0")
assign dff1_ac = AC0;
else if (DFF1_AC === "AC1")
assign dff1_ac = AC1;
else
$error("Invalid DFF1_AC setting!");
if (DFF2_AC === "AC0")
assign dff2_ac = AC0;
else if (DFF2_AC === "AC1")
assign dff2_ac = AC1;
else
$error("Invalid DFF2_AC setting!");
if (DFF3_AC === "AC0")
assign dff3_ac = AC0;
else if (DFF3_AC === "AC1")
assign dff3_ac = AC1;
else
$error("Invalid DFF3_AC setting!");
endgenerate
// F0 on the Quartus diagram
MISTRAL_ALUT4 #(.LUT(LUT0)) lut0 (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut0_out));
// F2 on the Quartus diagram
MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_comb (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut1_comb_mux));
MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_sum (.A(A), .B(B), .C(C0), .D(E0), .Q(lut1_sum_mux));
// F1 on the Quartus diagram
MISTRAL_ALUT4 #(.LUT(LUT2)) lut2 (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut2_out));
// F3 on the Quartus diagram
MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_comb (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut3_comb_mux));
MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_sum (.A(A), .B(B), .C(C1), .D(E1), .Q(lut3_sum_mux));
MISTRAL_FF #(.INIT(INIT0)) dff0 (.D(dff01_data_mux), .CLK(dff0_clk), .ACn(dff0_ac), .Q(dff0_out));
MISTRAL_FF #(.INIT(INIT1)) dff1 (.D(dff01_data_mux), .CLK(dff1_clk), .ACn(dff1_ac), .Q(dff1_out));
MISTRAL_FF #(.INIT(INIT2)) dff2 (.D(dff23_data_mux), .CLK(dff2_clk), .ACn(dff2_ac), .Q(dff2_out));
MISTRAL_FF #(.INIT(INIT3)) dff3 (.D(dff23_data_mux), .CLK(dff3_clk), .ACn(dff3_ac), .Q(dff3_out));
// Adders
assign {add0_carry, add0_sum} = CARRYIN + lut0_out + lut1_sum_mux;
assign {add1_carry, add1_sum} = add0_carry + lut2_out + lut3_sum_mux;
// COMBOUT outputs on the Quartus diagram
assign COMB0 = E0 ? (f0_input_mux ? lut3_comb_mux : lut1_comb_mux)
: (f0_input_mux ? lut2_out : lut0_out);
assign COMB1 = E1 ? (f1_input_mux ? lut3_comb_mux : lut1_comb_mux)
: (f1_input_mux ? lut2_out : lut0_out);
// SUMOUT output on the Quartus diagram
assign SUM0 = add0_sum;
assign SUM1 = add1_sum;
// COUT output on the Quartus diagram
assign CARRYOUT = add1_carry;
// SHAREOUT output on the Quartus diagram
assign SHAREOUT = lut3_comb_mux;
// REGOUT outputs on the Quartus diagram
assign FF0 = dff0_out;
assign FF1 = dff1_out;
assign FF2 = dff2_out;
assign FF3 = dff3_out;
endmodule
*/

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