mirror of https://github.com/YosysHQ/yosys.git
Merge branch 'YosysHQ:main' into master
This commit is contained in:
commit
542660246f
|
@ -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
|
|
@ -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._
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 }}
|
|
@ -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
|
|
@ -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 }}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "abc"]
|
||||
path = abc
|
||||
url = https://github.com/YosysHQ/abc
|
30
CHANGELOG
30
CHANGELOG
|
@ -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
|
||||
|
|
|
@ -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
182
Makefile
|
@ -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)"
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 237d81397fcc85dd3894bf1a449d2955cd3df02d
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/build/
|
||||
/source/cmd
|
||||
/source/temp
|
||||
/source/generated
|
||||
/source/_images/**/*.log
|
||||
/source/_images/**/*.aux
|
||||
/source/_images/**/*.pdf
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Command line reference
|
||||
================================================================================
|
||||
|
||||
.. literalinclude:: /temp/yosys
|
||||
.. literalinclude:: /generated/yosys
|
||||
:start-at: Usage
|
||||
|
||||
.. toctree::
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
my_cmd.so
|
||||
my_cmd.d
|
||||
*.log
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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``
|
||||
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'``
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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 ];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
306
kernel/fmt.cc
306
kernel/fmt.cc
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
25
kernel/fmt.h
25
kernel/fmt.h
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
346
kernel/yosys.h
346
kernel/yosys.h
|
@ -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();
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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 *)
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue