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
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
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
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
submodules: true
|
||||||
- name: Take last commit
|
- name: Take last commit
|
||||||
id: log
|
id: log
|
||||||
run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT
|
run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT
|
||||||
|
|
|
@ -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.info
|
||||||
/coverage_html
|
/coverage_html
|
||||||
/Makefile.conf
|
/Makefile.conf
|
||||||
/abc
|
|
||||||
/viz.js
|
/viz.js
|
||||||
/yosys
|
/yosys
|
||||||
/yosys.exe
|
/yosys.exe
|
||||||
|
@ -46,3 +45,4 @@ __pycache__
|
||||||
/tests/unit/bintest/
|
/tests/unit/bintest/
|
||||||
/tests/unit/objtest/
|
/tests/unit/objtest/
|
||||||
/tests/ystests
|
/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
|
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
|
Yosys 0.38 .. Yosys 0.39
|
||||||
--------------------------
|
--------------------------
|
||||||
* New commands and options
|
* New commands and options
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
# PATH (can use glob) USERNAME(S)
|
# PATH (can use glob) USERNAME(S)
|
||||||
|
|
||||||
|
CODEOWNERS @nakengelhardt
|
||||||
passes/cmds/scratchpad.cc @nakengelhardt
|
passes/cmds/scratchpad.cc @nakengelhardt
|
||||||
frontends/rpc/ @whitequark
|
frontends/rpc/ @whitequark
|
||||||
backends/cxxrtl/ @whitequark
|
backends/cxxrtl/ @whitequark
|
||||||
|
@ -19,7 +20,7 @@ passes/opt/opt_lut.cc @whitequark
|
||||||
passes/techmap/abc9*.cc @eddiehung @Ravenslofty
|
passes/techmap/abc9*.cc @eddiehung @Ravenslofty
|
||||||
backends/aiger/xaiger.cc @eddiehung
|
backends/aiger/xaiger.cc @eddiehung
|
||||||
docs/ @KrystalDelusion
|
docs/ @KrystalDelusion
|
||||||
|
.github/workflows/*.yml @mmicko
|
||||||
|
|
||||||
## External Contributors
|
## External Contributors
|
||||||
# Only users with write permission to the repository get review
|
# Only users with write permission to the repository get review
|
||||||
|
|
182
Makefile
182
Makefile
|
@ -3,7 +3,6 @@ CONFIG := none
|
||||||
# CONFIG := clang
|
# CONFIG := clang
|
||||||
# CONFIG := gcc
|
# CONFIG := gcc
|
||||||
# CONFIG := afl-gcc
|
# CONFIG := afl-gcc
|
||||||
# CONFIG := emcc
|
|
||||||
# CONFIG := wasi
|
# CONFIG := wasi
|
||||||
# CONFIG := mxe
|
# CONFIG := mxe
|
||||||
# CONFIG := msys2-32
|
# CONFIG := msys2-32
|
||||||
|
@ -142,7 +141,7 @@ LIBS += -lrt
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
YOSYS_VER := 0.39+147
|
YOSYS_VER := 0.41+108
|
||||||
|
|
||||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
||||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
||||||
|
@ -158,17 +157,8 @@ endif
|
||||||
OBJS = kernel/version_$(GIT_REV).o
|
OBJS = kernel/version_$(GIT_REV).o
|
||||||
|
|
||||||
bumpversion:
|
bumpversion:
|
||||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 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)
|
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
|
# set ABCEXTERNAL = <abc-command> to use an external ABC instance
|
||||||
|
@ -263,45 +253,6 @@ CXX = g++
|
||||||
CXXFLAGS += -std=gnu++11 -Os
|
CXXFLAGS += -std=gnu++11 -Os
|
||||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
|
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)
|
else ifeq ($(CONFIG),wasi)
|
||||||
ifeq ($(WASI_SDK),)
|
ifeq ($(WASI_SDK),)
|
||||||
CXX = clang++
|
CXX = clang++
|
||||||
|
@ -366,7 +317,7 @@ CXXFLAGS += -std=$(CXXSTD) -Os
|
||||||
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
|
ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)"
|
||||||
|
|
||||||
else
|
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
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_LIBYOSYS),1)
|
ifeq ($(ENABLE_LIBYOSYS),1)
|
||||||
|
@ -504,7 +455,7 @@ LIBS += -lpthread
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
ifeq ($(ABCEXTERNAL),)
|
ifeq ($(ABCEXTERNAL),)
|
||||||
TARGETS += $(PROGRAM_PREFIX)yosys-abc$(EXE)
|
TARGETS := $(PROGRAM_PREFIX)yosys-abc$(EXE) $(TARGETS)
|
||||||
endif
|
endif
|
||||||
endif
|
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/timinginfo.h))
|
||||||
$(eval $(call add_include_file,kernel/utils.h))
|
$(eval $(call add_include_file,kernel/utils.h))
|
||||||
$(eval $(call add_include_file,kernel/yosys.h))
|
$(eval $(call add_include_file,kernel/yosys.h))
|
||||||
|
$(eval $(call add_include_file,kernel/yosys_common.h))
|
||||||
$(eval $(call add_include_file,kernel/yw.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/ezsat.h))
|
||||||
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
|
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
|
||||||
|
@ -735,9 +687,11 @@ top-all: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
@echo " Build successful."
|
@echo " Build successful."
|
||||||
@echo ""
|
@echo ""
|
||||||
|
|
||||||
ifeq ($(CONFIG),emcc)
|
.PHONY: compile-only
|
||||||
yosys.js: $(filter-out yosysjs-$(YOSYS_VER).zip,$(EXTRA_TARGETS))
|
compile-only: $(OBJS) $(GENFILES) $(EXTRA_TARGETS)
|
||||||
endif
|
@echo ""
|
||||||
|
@echo " Compile successful."
|
||||||
|
@echo ""
|
||||||
|
|
||||||
$(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
|
$(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
|
||||||
$(P) $(CXX) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LINKFLAGS) $(LINKFLAGS) $(OBJS) $(LIBS) $(LIBS_VERIFIC)
|
$(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
|
-e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > $(PROGRAM_PREFIX)yosys-config
|
||||||
$(Q) chmod +x $(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)
|
$(P)
|
||||||
ifneq ($(ABCREV),default)
|
$(Q) mkdir -p abc && $(MAKE) -C $(PROGRAM_PREFIX)abc -f "$(realpath $(YOSYS_SRC)/abc/Makefile)" ABCSRC="$(realpath $(YOSYS_SRC)/abc/)" $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc",PROG="abc$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc.a)
|
||||||
$(Q) 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)
|
|
||||||
|
|
||||||
ifeq ($(ABCREV),default)
|
$(PROGRAM_PREFIX)yosys-abc$(EXE): abc/abc$(EXE)
|
||||||
.PHONY: abc/abc-$(ABCREV)$(EXE)
|
$(P) cp $< $(PROGRAM_PREFIX)yosys-abc$(EXE)
|
||||||
.PHONY: abc/libabc-$(ABCREV).a
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(PROGRAM_PREFIX)yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
|
$(PROGRAM_PREFIX)yosys-libabc.a: abc/libabc.a
|
||||||
$(P) cp abc/abc-$(ABCREV)$(EXE) $(PROGRAM_PREFIX)yosys-abc$(EXE)
|
$(P) cp $< $(PROGRAM_PREFIX)yosys-libabc.a
|
||||||
|
|
||||||
$(PROGRAM_PREFIX)yosys-libabc.a: abc/libabc-$(ABCREV).a
|
|
||||||
$(P) cp abc/libabc-$(ABCREV).a $(PROGRAM_PREFIX)yosys-libabc.a
|
|
||||||
|
|
||||||
ifneq ($(SEED),)
|
ifneq ($(SEED),)
|
||||||
SEEDOPT="-S $(SEED)"
|
SEEDOPT="-S $(SEED)"
|
||||||
|
@ -984,16 +937,33 @@ docs/gen_images:
|
||||||
$(Q) $(MAKE) -C docs images
|
$(Q) $(MAKE) -C docs images
|
||||||
|
|
||||||
DOCS_GUIDELINE_FILES := GettingStarted CodingStyle
|
DOCS_GUIDELINE_FILES := GettingStarted CodingStyle
|
||||||
docs/guidelines:
|
docs/guidelines docs/source/generated:
|
||||||
$(Q) mkdir -p docs/source/temp
|
$(Q) mkdir -p docs/source/generated
|
||||||
$(Q) cp -f $(addprefix guidelines/,$(DOCS_GUIDELINE_FILES)) docs/source/temp
|
$(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
|
# some commands return an error and print the usage text to stderr
|
||||||
# the command with a '-'
|
define DOC_USAGE_STDERR
|
||||||
DOCS_USAGE_PROGS := yosys yosys-config yosys-filterlib yosys-abc yosys-smtbmc yosys-witness
|
docs/source/generated/$(1): $(PROGRAM_PREFIX)$(1) docs/source/generated
|
||||||
docs/usage: $(addprefix docs/source/temp/,$(DOCS_USAGE_PROGS))
|
-$(Q) ./$$< --help 2> $$@
|
||||||
docs/source/temp/%: docs/guidelines
|
endef
|
||||||
-$(Q) ./$(PROGRAM_PREFIX)$* --help > $@ 2>&1
|
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:
|
docs/reqs:
|
||||||
$(Q) $(MAKE) -C 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 -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/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff
|
||||||
rm -f tests/tools/cmp_tbdata
|
rm -f tests/tools/cmp_tbdata
|
||||||
$(MAKE) -C docs clean
|
-$(MAKE) -C docs clean
|
||||||
|
-$(MAKE) -C docs/images clean
|
||||||
|
rm -rf docs/source/cmd docs/util/__pycache__
|
||||||
|
|
||||||
clean-abc:
|
clean-abc:
|
||||||
$(MAKE) -C abc DEP= clean
|
$(MAKE) -C abc DEP= clean
|
||||||
|
@ -1033,11 +1005,12 @@ coverage:
|
||||||
genhtml coverage.info --output-directory coverage_html
|
genhtml coverage.info --output-directory coverage_html
|
||||||
|
|
||||||
qtcreator:
|
qtcreator:
|
||||||
|
echo "$(CXXFLAGS)" | grep -o '\-D[^ ]*' | tr ' ' '\n' | sed 's/-D/#define /' | sed 's/=/ /'> qtcreator.config
|
||||||
{ for file in $(basename $(OBJS)); do \
|
{ for file in $(basename $(OBJS)); do \
|
||||||
for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \
|
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
|
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
|
{ 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)
|
vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
|
||||||
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
|
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
|
||||||
|
@ -1080,14 +1053,6 @@ config-gcc-static: clean
|
||||||
config-afl-gcc: clean
|
config-afl-gcc: clean
|
||||||
echo 'CONFIG := afl-gcc' > Makefile.conf
|
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
|
config-wasi: clean
|
||||||
echo 'CONFIG := wasi' > Makefile.conf
|
echo 'CONFIG := wasi' > Makefile.conf
|
||||||
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
echo 'ENABLE_TCL := 0' >> Makefile.conf
|
||||||
|
@ -1129,9 +1094,6 @@ echo-yosys-ver:
|
||||||
echo-git-rev:
|
echo-git-rev:
|
||||||
@echo "$(GIT_REV)"
|
@echo "$(GIT_REV)"
|
||||||
|
|
||||||
echo-abc-rev:
|
|
||||||
@echo "$(ABCREV)"
|
|
||||||
|
|
||||||
echo-cxx:
|
echo-cxx:
|
||||||
@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;
|
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) {
|
for (auto c : input) {
|
||||||
if (::isprint(c)) {
|
if (::isprint(c)) {
|
||||||
if (c == '\\')
|
if (c == '\\')
|
||||||
output.push_back('\\');
|
output.push_back('\\');
|
||||||
output.push_back(c);
|
output.push_back(c);
|
||||||
} else {
|
} else {
|
||||||
char l = c & 0xf, h = (c >> 4) & 0xf;
|
char l = c & 0x3, m = (c >> 3) & 0x3, h = (c >> 6) & 0x3;
|
||||||
output.append("\\x");
|
output.append("\\");
|
||||||
output.push_back((h < 10 ? '0' + h : 'a' + h - 10));
|
output.push_back('0' + h);
|
||||||
output.push_back((l < 10 ? '0' + l : 'a' + l - 10));
|
output.push_back('0' + m);
|
||||||
|
output.push_back('0' + l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output.push_back('"');
|
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) {
|
if (output.find('\0') != std::string::npos) {
|
||||||
output.insert(0, "std::string {");
|
output.insert(0, "std::string {");
|
||||||
output.append(stringf(", %zu}", input.size()));
|
output.append(stringf(", %zu}", input.size()));
|
||||||
|
@ -2275,12 +2283,53 @@ struct CxxrtlWorker {
|
||||||
dec_indent();
|
dec_indent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_metadata_map(const dict<RTLIL::IdString, RTLIL::Const> &metadata_map)
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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_metadata_map(const dict<RTLIL::IdString, RTLIL::Const> &metadata_map) {
|
||||||
if (metadata_map.empty()) {
|
if (metadata_map.empty()) {
|
||||||
f << "metadata_map()";
|
f << "metadata_map()";
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
f << "metadata_map({\n";
|
f << "metadata_map({\n";
|
||||||
inc_indent();
|
inc_indent();
|
||||||
for (auto metadata_item : metadata_map) {
|
for (auto metadata_item : metadata_map) {
|
||||||
|
@ -2306,16 +2355,21 @@ struct CxxrtlWorker {
|
||||||
dec_indent();
|
dec_indent();
|
||||||
f << indent << "})";
|
f << indent << "})";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dump_debug_attrs(const RTLIL::AttrObject *object)
|
void dump_debug_attrs(const RTLIL::AttrObject *object, bool serialize = true)
|
||||||
{
|
{
|
||||||
dict<RTLIL::IdString, RTLIL::Const> attributes = object->attributes;
|
dict<RTLIL::IdString, RTLIL::Const> attributes = object->attributes;
|
||||||
// Inherently necessary to get access to the object, so a waste of space to emit.
|
// Inherently necessary to get access to the object, so a waste of space to emit.
|
||||||
attributes.erase(ID::hdlname);
|
attributes.erase(ID::hdlname);
|
||||||
// Internal Yosys attribute that should be removed but isn't.
|
// Internal Yosys attribute that should be removed but isn't.
|
||||||
attributes.erase(ID::module_not_derived);
|
attributes.erase(ID::module_not_derived);
|
||||||
|
if (serialize) {
|
||||||
|
dump_serialized_metadata(attributes);
|
||||||
|
} else {
|
||||||
dump_metadata_map(attributes);
|
dump_metadata_map(attributes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dump_debug_info_method(RTLIL::Module *module)
|
void dump_debug_info_method(RTLIL::Module *module)
|
||||||
{
|
{
|
||||||
|
@ -2337,7 +2391,7 @@ struct CxxrtlWorker {
|
||||||
// The module is responsible for adding its own scope.
|
// The module is responsible for adding its own scope.
|
||||||
f << indent << "scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), ";
|
f << indent << "scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), ";
|
||||||
f << escape_cxx_string(get_hdl_name(module)) << ", ";
|
f << escape_cxx_string(get_hdl_name(module)) << ", ";
|
||||||
dump_debug_attrs(module);
|
dump_debug_attrs(module, /*serialize=*/false);
|
||||||
f << ", std::move(cell_attrs));\n";
|
f << ", std::move(cell_attrs));\n";
|
||||||
count_scopes++;
|
count_scopes++;
|
||||||
// If there were any submodules that were flattened, the module is also responsible for adding them.
|
// 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 module_attrs = scopeinfo_attributes(cell, ScopeinfoAttrs::Module);
|
||||||
auto cell_attrs = scopeinfo_attributes(cell, ScopeinfoAttrs::Cell);
|
auto cell_attrs = scopeinfo_attributes(cell, ScopeinfoAttrs::Cell);
|
||||||
cell_attrs.erase(ID::module_not_derived);
|
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))) << ", ";
|
f << escape_cxx_string(cell->get_string_attribute(ID(module))) << ", ";
|
||||||
dump_metadata_map(module_attrs);
|
dump_serialized_metadata(module_attrs);
|
||||||
f << ", ";
|
f << ", ";
|
||||||
dump_metadata_map(cell_attrs);
|
dump_serialized_metadata(cell_attrs);
|
||||||
f << ");\n";
|
f << ");\n";
|
||||||
} else log_assert(false && "Unknown $scopeinfo type");
|
} else log_assert(false && "Unknown $scopeinfo type");
|
||||||
count_scopes++;
|
count_scopes++;
|
||||||
|
@ -2419,8 +2473,11 @@ struct CxxrtlWorker {
|
||||||
if (has_driven_sync + has_driven_comb + has_undriven > 1)
|
if (has_driven_sync + has_driven_comb + has_undriven > 1)
|
||||||
count_mixed_driver++;
|
count_mixed_driver++;
|
||||||
|
|
||||||
f << indent << "items->add(path + " << escape_cxx_string(get_hdl_name(wire));
|
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
|
||||||
f << ", debug_item(" << mangle(wire) << ", " << wire->start_offset;
|
dump_debug_attrs(wire);
|
||||||
|
f << ", " << mangle(wire);
|
||||||
|
if (wire->start_offset != 0 || !flags.empty()) {
|
||||||
|
f << ", " << wire->start_offset;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto flag : flags) {
|
for (auto flag : flags) {
|
||||||
if (first) {
|
if (first) {
|
||||||
|
@ -2431,8 +2488,7 @@ struct CxxrtlWorker {
|
||||||
}
|
}
|
||||||
f << "debug_item::" << flag;
|
f << "debug_item::" << flag;
|
||||||
}
|
}
|
||||||
f << "), ";
|
}
|
||||||
dump_debug_attrs(wire);
|
|
||||||
f << ");\n";
|
f << ");\n";
|
||||||
count_member_wires++;
|
count_member_wires++;
|
||||||
break;
|
break;
|
||||||
|
@ -2440,16 +2496,18 @@ struct CxxrtlWorker {
|
||||||
case WireType::ALIAS: {
|
case WireType::ALIAS: {
|
||||||
// Alias of a member wire
|
// Alias of a member wire
|
||||||
const RTLIL::Wire *aliasee = debug_wire_type.sig_subst.as_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 << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
|
||||||
f << ", debug_item(";
|
dump_debug_attrs(aliasee);
|
||||||
|
f << ", ";
|
||||||
// If the aliasee is an outline, then the alias must be an outline, too; otherwise downstream
|
// 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.
|
// tooling has no way to find out about the outline.
|
||||||
if (debug_wire_types[aliasee].is_outline())
|
if (debug_wire_types[aliasee].is_outline())
|
||||||
f << "debug_eval_outline";
|
f << "debug_eval_outline";
|
||||||
else
|
else
|
||||||
f << "debug_alias()";
|
f << "debug_alias()";
|
||||||
f << ", " << mangle(aliasee) << ", " << wire->start_offset << "), ";
|
f << ", " << mangle(aliasee);
|
||||||
dump_debug_attrs(aliasee);
|
if (wire->start_offset != 0)
|
||||||
|
f << ", " << wire->start_offset;
|
||||||
f << ");\n";
|
f << ");\n";
|
||||||
count_alias_wires++;
|
count_alias_wires++;
|
||||||
break;
|
break;
|
||||||
|
@ -2459,18 +2517,22 @@ struct CxxrtlWorker {
|
||||||
f << indent << "static const value<" << wire->width << "> const_" << mangle(wire) << " = ";
|
f << indent << "static const value<" << wire->width << "> const_" << mangle(wire) << " = ";
|
||||||
dump_const(debug_wire_type.sig_subst.as_const());
|
dump_const(debug_wire_type.sig_subst.as_const());
|
||||||
f << ";\n";
|
f << ";\n";
|
||||||
f << indent << "items->add(path + " << escape_cxx_string(get_hdl_name(wire));
|
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
|
||||||
f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "), ";
|
|
||||||
dump_debug_attrs(wire);
|
dump_debug_attrs(wire);
|
||||||
|
f << ", const_" << mangle(wire);
|
||||||
|
if (wire->start_offset != 0)
|
||||||
|
f << ", " << wire->start_offset;
|
||||||
f << ");\n";
|
f << ");\n";
|
||||||
count_const_wires++;
|
count_const_wires++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WireType::OUTLINE: {
|
case WireType::OUTLINE: {
|
||||||
// Localized or inlined, but rematerializable wire
|
// Localized or inlined, but rematerializable wire
|
||||||
f << indent << "items->add(path + " << escape_cxx_string(get_hdl_name(wire));
|
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
|
||||||
f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "), ";
|
|
||||||
dump_debug_attrs(wire);
|
dump_debug_attrs(wire);
|
||||||
|
f << ", debug_eval_outline, " << mangle(wire);
|
||||||
|
if (wire->start_offset != 0)
|
||||||
|
f << ", " << wire->start_offset;
|
||||||
f << ");\n";
|
f << ");\n";
|
||||||
count_inline_wires++;
|
count_inline_wires++;
|
||||||
break;
|
break;
|
||||||
|
@ -2486,15 +2548,14 @@ struct CxxrtlWorker {
|
||||||
for (auto &mem : mod_memories[module]) {
|
for (auto &mem : mod_memories[module]) {
|
||||||
if (!mem.memid.isPublic())
|
if (!mem.memid.isPublic())
|
||||||
continue;
|
continue;
|
||||||
f << indent << "items->add(path + " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem));
|
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 << "), ";
|
|
||||||
if (mem.packed) {
|
if (mem.packed) {
|
||||||
dump_debug_attrs(mem.cell);
|
dump_debug_attrs(mem.cell);
|
||||||
} else {
|
} else {
|
||||||
dump_debug_attrs(mem.mem);
|
dump_debug_attrs(mem.mem);
|
||||||
}
|
}
|
||||||
f << ");\n";
|
f << ", " << mangle(&mem) << ", ";
|
||||||
|
f << mem.start_offset << ");\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dec_indent();
|
dec_indent();
|
||||||
|
@ -2506,7 +2567,7 @@ struct CxxrtlWorker {
|
||||||
const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : ".";
|
const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : ".";
|
||||||
f << indent << mangle(cell) << access;
|
f << indent << mangle(cell) << access;
|
||||||
f << "debug_info(items, scopes, path + " << escape_cxx_string(get_hdl_name(cell) + ' ') << ", ";
|
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";
|
f << ");\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3202,6 +3263,7 @@ struct CxxrtlWorker {
|
||||||
debug_wire_type = wire_type; // wire is a member
|
debug_wire_type = wire_type; // wire is a member
|
||||||
|
|
||||||
if (!debug_alias) continue;
|
if (!debug_alias) continue;
|
||||||
|
if (wire->port_input || wire->port_output) continue; // preserve input/output metadata in flags
|
||||||
const RTLIL::Wire *it = wire;
|
const RTLIL::Wire *it = wire;
|
||||||
while (flow.is_inlinable(it)) {
|
while (flow.is_inlinable(it)) {
|
||||||
log_assert(flow.wire_comb_defs[it].size() == 1);
|
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> remainder;
|
||||||
value<Bits + 1> dividend = sext<Bits + 1>();
|
value<Bits + 1> dividend = sext<Bits + 1>();
|
||||||
value<Bits + 1> divisor = other.template sext<Bits + 1>();
|
value<Bits + 1> divisor = other.template sext<Bits + 1>();
|
||||||
if (dividend.is_neg()) dividend = dividend.neg();
|
if (is_neg()) dividend = dividend.neg();
|
||||||
if (divisor.is_neg()) divisor = divisor.neg();
|
if (other.is_neg()) divisor = divisor.neg();
|
||||||
std::tie(quotient, remainder) = dividend.udivmod(divisor);
|
std::tie(quotient, remainder) = dividend.udivmod(divisor);
|
||||||
if (dividend.is_neg() != divisor.is_neg()) quotient = quotient.neg();
|
if (is_neg() != other.is_neg()) quotient = quotient.neg();
|
||||||
if (dividend.is_neg()) remainder = remainder.neg();
|
if (is_neg()) remainder = remainder.neg();
|
||||||
return {quotient.template trunc<Bits>(), remainder.template trunc<Bits>()};
|
return {quotient.template trunc<Bits>(), remainder.template trunc<Bits>()};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -941,6 +941,55 @@ struct metadata {
|
||||||
assert(value_type == DOUBLE);
|
assert(value_type == DOUBLE);
|
||||||
return double_value;
|
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;
|
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.
|
// Default member initializers would make this a non-aggregate-type in C++11, so they are commented out.
|
||||||
struct fmt_part {
|
struct fmt_part {
|
||||||
enum {
|
enum {
|
||||||
STRING = 0,
|
LITERAL = 0,
|
||||||
INTEGER = 1,
|
INTEGER = 1,
|
||||||
CHARACTER = 2,
|
STRING = 2,
|
||||||
VLOG_TIME = 3,
|
UNICHAR = 3,
|
||||||
|
VLOG_TIME = 4,
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
// STRING type
|
// LITERAL type
|
||||||
std::string str;
|
std::string str;
|
||||||
|
|
||||||
// INTEGER/CHARACTER types
|
// INTEGER/STRING/UNICHAR types
|
||||||
// + value<Bits> val;
|
// + value<Bits> val;
|
||||||
|
|
||||||
// INTEGER/CHARACTER/VLOG_TIME types
|
// INTEGER/STRING/VLOG_TIME types
|
||||||
enum {
|
enum {
|
||||||
RIGHT = 0,
|
RIGHT = 0,
|
||||||
LEFT = 1,
|
LEFT = 1,
|
||||||
|
NUMERIC = 2,
|
||||||
} justify; // = RIGHT;
|
} justify; // = RIGHT;
|
||||||
char padding; // = '\0';
|
char padding; // = '\0';
|
||||||
size_t width; // = 0;
|
size_t width; // = 0;
|
||||||
|
@ -1033,7 +1084,14 @@ struct fmt_part {
|
||||||
// INTEGER type
|
// INTEGER type
|
||||||
unsigned base; // = 10;
|
unsigned base; // = 10;
|
||||||
bool signed_; // = false;
|
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
|
// VLOG_TIME type
|
||||||
bool realtime; // = false;
|
bool realtime; // = false;
|
||||||
|
@ -1049,11 +1107,12 @@ struct fmt_part {
|
||||||
// We might want to replace some of these bit() calls with direct
|
// We might want to replace some of these bit() calls with direct
|
||||||
// chunk access if it turns out to be slow enough to matter.
|
// chunk access if it turns out to be slow enough to matter.
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
std::string prefix;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case STRING:
|
case LITERAL:
|
||||||
return str;
|
return str;
|
||||||
|
|
||||||
case CHARACTER: {
|
case STRING: {
|
||||||
buf.reserve(Bits/8);
|
buf.reserve(Bits/8);
|
||||||
for (int i = 0; i < Bits; i += 8) {
|
for (int i = 0; i < Bits; i += 8) {
|
||||||
char ch = 0;
|
char ch = 0;
|
||||||
|
@ -1067,35 +1126,76 @@ struct fmt_part {
|
||||||
break;
|
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: {
|
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) {
|
if (base != 10) {
|
||||||
width = 0;
|
val_width = 1;
|
||||||
for (size_t index = 0; index < Bits; index++)
|
for (size_t index = 0; index < Bits; index++)
|
||||||
if (val.bit(index))
|
if (val.bit(index))
|
||||||
width = index + 1;
|
val_width = index + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base == 2) {
|
if (base == 2) {
|
||||||
for (size_t i = width; i > 0; i--)
|
if (show_base)
|
||||||
buf += (val.bit(i - 1) ? '1' : '0');
|
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) {
|
} else if (base == 8 || base == 16) {
|
||||||
|
if (show_base)
|
||||||
|
prefix += (base == 16) ? (hex_upper ? "0X" : "0x") : "0o";
|
||||||
size_t step = (base == 16) ? 4 : 3;
|
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);
|
uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2);
|
||||||
if (step == 4)
|
if (step == 4)
|
||||||
value |= val.bit(index + 3) << 3;
|
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) {
|
} else if (base == 10) {
|
||||||
bool negative = signed_ && val.is_neg();
|
if (show_base)
|
||||||
if (negative)
|
prefix += "0d";
|
||||||
val = val.neg();
|
|
||||||
if (val.is_zero())
|
if (val.is_zero())
|
||||||
buf += '0';
|
buf += '0';
|
||||||
value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>();
|
value<(Bits > 4 ? Bits : 4)> xval = val.template zext<(Bits > 4 ? Bits : 4)>();
|
||||||
|
size_t index = 0;
|
||||||
while (!xval.is_zero()) {
|
while (!xval.is_zero()) {
|
||||||
|
if (group && index > 0 && index % 3 == 0)
|
||||||
|
buf += '_';
|
||||||
value<(Bits > 4 ? Bits : 4)> quotient, remainder;
|
value<(Bits > 4 ? Bits : 4)> quotient, remainder;
|
||||||
if (Bits >= 4)
|
if (Bits >= 4)
|
||||||
std::tie(quotient, remainder) = xval.udivmod(value<(Bits > 4 ? Bits : 4)>{10u});
|
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);
|
std::tie(quotient, remainder) = std::make_pair(value<(Bits > 4 ? Bits : 4)>{0u}, xval);
|
||||||
buf += '0' + remainder.template trunc<4>().template get<uint8_t>();
|
buf += '0' + remainder.template trunc<4>().template get<uint8_t>();
|
||||||
xval = quotient;
|
xval = quotient;
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
if (negative || plus)
|
|
||||||
buf += negative ? '-' : '+';
|
|
||||||
std::reverse(buf.begin(), buf.end());
|
|
||||||
} else assert(false && "Unsupported base for fmt_part");
|
} 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,17 +1230,29 @@ struct fmt_part {
|
||||||
|
|
||||||
std::string str;
|
std::string str;
|
||||||
assert(width == 0 || padding != '\0');
|
assert(width == 0 || padding != '\0');
|
||||||
if (justify == RIGHT && buf.size() < width) {
|
if (prefix.size() + buf.size() < width) {
|
||||||
size_t pad_width = width - buf.size();
|
size_t pad_width = width - prefix.size() - buf.size();
|
||||||
if (padding == '0' && (buf.front() == '+' || buf.front() == '-')) {
|
switch (justify) {
|
||||||
str += buf.front();
|
case LEFT:
|
||||||
buf.erase(0, 1);
|
str += prefix;
|
||||||
}
|
|
||||||
str += std::string(pad_width, padding);
|
|
||||||
}
|
|
||||||
str += buf;
|
str += buf;
|
||||||
if (justify == LEFT && buf.size() < width)
|
str += std::string(pad_width, padding);
|
||||||
str += std::string(width - buf.size(), 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;
|
||||||
|
}
|
||||||
return str;
|
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 {
|
size_t count(const std::string &path) const {
|
||||||
if (table.count(path) == 0)
|
if (table.count(path) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1393,6 +1518,11 @@ struct debug_scopes {
|
||||||
scope.cell_attrs = std::unique_ptr<debug_attrs>(new debug_attrs { cell_attrs });
|
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 {
|
size_t contains(const std::string &path) const {
|
||||||
return table.count(path);
|
return table.count(path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -512,9 +512,10 @@ public:
|
||||||
spool &operator=(const spool &) = delete;
|
spool &operator=(const spool &) = delete;
|
||||||
|
|
||||||
~spool() {
|
~spool() {
|
||||||
if (int fd = writefd.exchange(-1))
|
int fd;
|
||||||
|
if ((fd = writefd.exchange(-1)) != -1)
|
||||||
close(fd);
|
close(fd);
|
||||||
if (int fd = readfd.exchange(-1))
|
if ((fd = readfd.exchange(-1)) != -1)
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,6 @@ def help():
|
||||||
|
|
||||||
--minimize-assumes
|
--minimize-assumes
|
||||||
when using --track-assumes, solve for a minimal set of sufficient assumptions.
|
when using --track-assumes, solve for a minimal set of sufficient assumptions.
|
||||||
|
|
||||||
""" + so.helpmsg())
|
""" + so.helpmsg())
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
|
@ -670,18 +669,12 @@ if aimfile is not None:
|
||||||
|
|
||||||
ywfile_hierwitness_cache = None
|
ywfile_hierwitness_cache = None
|
||||||
|
|
||||||
def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False):
|
def ywfile_hierwitness():
|
||||||
global ywfile_hierwitness_cache
|
global ywfile_hierwitness_cache
|
||||||
if map_steps is None:
|
|
||||||
map_steps = {}
|
|
||||||
|
|
||||||
with open(inywfile, "r") as f:
|
|
||||||
inyw = ReadWitness(f)
|
|
||||||
|
|
||||||
if ywfile_hierwitness_cache is None:
|
if ywfile_hierwitness_cache is None:
|
||||||
ywfile_hierwitness_cache = smt.hierwitness(topmod, allregs=True, blackbox=True)
|
ywfile_hierwitness = 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_wires = defaultdict(list)
|
||||||
smt_mems = defaultdict(list)
|
smt_mems = defaultdict(list)
|
||||||
|
@ -692,21 +685,54 @@ def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False):
|
||||||
for mem in mems:
|
for mem in mems:
|
||||||
smt_mems[mem["path"]].append(mem)
|
smt_mems[mem["path"]].append(mem)
|
||||||
|
|
||||||
addr_re = re.compile(r'\\\[[0-9]+\]$')
|
ywfile_hierwitness_cache = inits, seqs, clocks, mems, smt_wires, smt_mems
|
||||||
bits_re = re.compile(r'[01?]*$')
|
|
||||||
|
|
||||||
max_t = -1
|
return ywfile_hierwitness_cache
|
||||||
|
|
||||||
for t, step in inyw.steps():
|
def_bits_re = re.compile(r'([01]+)')
|
||||||
present_signals, missing = step.present_signals(inyw.sigmap)
|
|
||||||
for sig in present_signals:
|
def smt_extract_mask(smt_expr, mask):
|
||||||
bits = step[sig]
|
chunks = []
|
||||||
if skip_x:
|
def_bits = ''
|
||||||
bits = bits.replace('x', '?')
|
|
||||||
if not bits_re.match(bits):
|
mask_index_order = mask[::-1]
|
||||||
raise ValueError("unsupported bit value in Yosys witness file")
|
|
||||||
|
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 = []
|
||||||
|
|
||||||
sig_end = sig.offset + len(bits)
|
|
||||||
if sig.path in smt_wires:
|
if sig.path in smt_wires:
|
||||||
for wire in smt_wires[sig.path]:
|
for wire in smt_wires[sig.path]:
|
||||||
width, offset = wire["width"], wire["offset"]
|
width, offset = wire["width"], wire["offset"]
|
||||||
|
@ -721,37 +747,23 @@ def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False):
|
||||||
if common_end <= common_offset:
|
if common_end <= common_offset:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
smt_expr = smt.witness_net_expr(topmod, f"s{map_steps.get(t, t)}", wire)
|
smt_expr = smt.witness_net_expr(topmod, f"s{step}", wire)
|
||||||
|
|
||||||
if not smt_bool:
|
if not smt_bool:
|
||||||
slice_high = common_end - offset - 1
|
slice_high = common_end - offset - 1
|
||||||
slice_low = common_offset - offset
|
slice_low = common_offset - offset
|
||||||
smt_expr = "((_ extract %d %d) %s)" % (slice_high, slice_low, smt_expr)
|
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:
|
else:
|
||||||
if "?" in bit_slice:
|
smt_expr = "(ite %s #b1 #b0)" % smt_expr
|
||||||
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)
|
output.append(((common_offset - sig.offset), (common_end - sig.offset), smt_expr))
|
||||||
|
|
||||||
constr_assumes[t].append((inywfile, smt_constr))
|
|
||||||
|
|
||||||
if sig.memory_path:
|
if sig.memory_path:
|
||||||
if sig.memory_path in smt_mems:
|
if sig.memory_path in smt_mems:
|
||||||
for mem in smt_mems[sig.memory_path]:
|
for mem in smt_mems[sig.memory_path]:
|
||||||
width, size, bv = mem["width"], mem["size"], mem["statebv"]
|
width, size, bv = mem["width"], mem["size"], mem["statebv"]
|
||||||
|
|
||||||
smt_expr = smt.net_expr(topmod, f"s{map_steps.get(t, t)}", mem["smtpath"])
|
smt_expr = smt.net_expr(topmod, f"s{step}", mem["smtpath"])
|
||||||
|
|
||||||
if bv:
|
if bv:
|
||||||
word_low = sig.memory_addr * width
|
word_low = sig.memory_addr * width
|
||||||
|
@ -762,21 +774,58 @@ def ywfile_constraints(inywfile, constr_assumes, map_steps=None, skip_x=False):
|
||||||
addr_bits = f"{sig.memory_addr:0{addr_width}b}"
|
addr_bits = f"{sig.memory_addr:0{addr_width}b}"
|
||||||
smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits)
|
smt_expr = "(select %s #b%s )" % (smt_expr, addr_bits)
|
||||||
|
|
||||||
if len(bits) < width:
|
if sig.width < width:
|
||||||
slice_high = sig.offset + len(bits) - 1
|
slice_high = sig.offset + sig.width - 1
|
||||||
smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr)
|
smt_expr = "((_ extract %d %d) %s)" % (slice_high, sig.offset, smt_expr)
|
||||||
|
|
||||||
bit_slice = bits
|
output.append((0, sig.width, smt_expr))
|
||||||
|
|
||||||
if "?" in bit_slice:
|
output.sort()
|
||||||
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)
|
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():
|
||||||
|
present_signals, missing = step.present_signals(inyw.sigmap)
|
||||||
|
for sig in present_signals:
|
||||||
|
bits = step[sig]
|
||||||
|
if skip_x:
|
||||||
|
bits = bits.replace('x', '?')
|
||||||
|
if not bits_re.match(bits):
|
||||||
|
raise ValueError("unsupported bit value in Yosys witness file")
|
||||||
|
|
||||||
|
smt_expr = ywfile_signal(sig, map_steps.get(t, t))
|
||||||
|
|
||||||
|
smt_expr, bits = smt_extract_mask(smt_expr, bits)
|
||||||
|
|
||||||
|
smt_constr = "(= %s #b%s)" % (smt_expr, bits)
|
||||||
constr_assumes[t].append((inywfile, smt_constr))
|
constr_assumes[t].append((inywfile, smt_constr))
|
||||||
max_t = t
|
|
||||||
|
|
||||||
|
max_t = t
|
||||||
return max_t
|
return max_t
|
||||||
|
|
||||||
if inywfile is not None:
|
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)
|
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))
|
bvs = iter(smt.get_list(exprs))
|
||||||
|
|
||||||
for sigs in all_sigs:
|
for (step_values, sigs) in all_sigs:
|
||||||
for sig in sigs:
|
for sig in sigs:
|
||||||
value = smt.bv2bin(next(bvs))
|
value = smt.bv2bin(next(bvs))
|
||||||
step_values[sig["sig"]] = value
|
step_values[sig["sig"]] = value
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import json
|
import json
|
||||||
import typing
|
import typing
|
||||||
from functools import partial
|
import ywio
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
import smtbmc
|
import smtbmc
|
||||||
|
@ -34,6 +34,7 @@ class Incremental:
|
||||||
self._witness_index = None
|
self._witness_index = None
|
||||||
|
|
||||||
self._yw_constraints = {}
|
self._yw_constraints = {}
|
||||||
|
self._define_sorts = {}
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
generic_assert_map = smtbmc.get_assert_map(
|
generic_assert_map = smtbmc.get_assert_map(
|
||||||
|
@ -175,11 +176,7 @@ class Incremental:
|
||||||
if len(expr) == 1:
|
if len(expr) == 1:
|
||||||
smt_out.push({"and": "true", "or": "false"}[expr[0]])
|
smt_out.push({"and": "true", "or": "false"}[expr[0]])
|
||||||
elif len(expr) == 2:
|
elif len(expr) == 2:
|
||||||
arg_sort = self.expr(expr[1], smt_out)
|
self.expr(expr[1], smt_out, required_sort="Bool")
|
||||||
if arg_sort != "Bool":
|
|
||||||
raise InteractiveError(
|
|
||||||
f"arguments of {json.dumps(expr[0])} must have sort Bool"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
sep = f"({expr[0]} "
|
sep = f"({expr[0]} "
|
||||||
for arg in expr[1:]:
|
for arg in expr[1:]:
|
||||||
|
@ -189,7 +186,51 @@ class Incremental:
|
||||||
smt_out.append(")")
|
smt_out.append(")")
|
||||||
return "Bool"
|
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):
|
def expr_yw(self, expr, smt_out):
|
||||||
|
self.expr_arg_len(expr, 1, 2)
|
||||||
if len(expr) == 2:
|
if len(expr) == 2:
|
||||||
name = None
|
name = None
|
||||||
step = expr[1]
|
step = expr[1]
|
||||||
|
@ -219,6 +260,40 @@ class Incremental:
|
||||||
|
|
||||||
return "Bool"
|
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):
|
def expr_smtlib(self, expr, smt_out):
|
||||||
self.expr_arg_len(expr, 2)
|
self.expr_arg_len(expr, 2)
|
||||||
|
|
||||||
|
@ -231,10 +306,15 @@ class Incremental:
|
||||||
f"got {json.dumps(smtlib_expr)}"
|
f"got {json.dumps(smtlib_expr)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not isinstance(sort, str):
|
if (
|
||||||
raise InteractiveError(
|
isinstance(sort, list)
|
||||||
f"raw SMT-LIB sort has to be a string, got {json.dumps(sort)}"
|
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)
|
smt_out.append(smtlib_expr)
|
||||||
return sort
|
return sort
|
||||||
|
@ -258,6 +338,14 @@ class Incremental:
|
||||||
|
|
||||||
return sort
|
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 = {
|
expr_handlers = {
|
||||||
"step": expr_step,
|
"step": expr_step,
|
||||||
"cell": expr_cell,
|
"cell": expr_cell,
|
||||||
|
@ -270,8 +358,15 @@ class Incremental:
|
||||||
"not": expr_not,
|
"not": expr_not,
|
||||||
"and": expr_andor,
|
"and": expr_andor,
|
||||||
"or": 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,
|
"=": expr_eq,
|
||||||
"yw": expr_yw,
|
"yw": expr_yw,
|
||||||
|
"yw_sig": expr_yw_sig,
|
||||||
"smtlib": expr_smtlib,
|
"smtlib": expr_smtlib,
|
||||||
"!": expr_label,
|
"!": expr_label,
|
||||||
}
|
}
|
||||||
|
@ -305,10 +400,13 @@ class Incremental:
|
||||||
raise InteractiveError(f"unknown expression {json.dumps(expr[0])}")
|
raise InteractiveError(f"unknown expression {json.dumps(expr[0])}")
|
||||||
|
|
||||||
def expr_smt(self, expr, required_sort):
|
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 = []
|
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)
|
out = "".join(smt_out)
|
||||||
return out
|
return out, output_sort
|
||||||
|
|
||||||
def cmd_new_step(self, cmd):
|
def cmd_new_step(self, cmd):
|
||||||
step = self.arg_step(cmd, declare=True)
|
step = self.arg_step(cmd, declare=True)
|
||||||
|
@ -338,7 +436,6 @@ class Incremental:
|
||||||
expr = cmd.get("expr")
|
expr = cmd.get("expr")
|
||||||
key = cmd.get("key")
|
key = cmd.get("key")
|
||||||
|
|
||||||
|
|
||||||
key = mkkey(key)
|
key = mkkey(key)
|
||||||
|
|
||||||
result = smtbmc.smt.smt2_assumptions.pop(key, None)
|
result = smtbmc.smt.smt2_assumptions.pop(key, None)
|
||||||
|
@ -348,7 +445,7 @@ class Incremental:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def cmd_get_unsat_assumptions(self, cmd):
|
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):
|
def cmd_push(self, cmd):
|
||||||
smtbmc.smt_push()
|
smtbmc.smt_push()
|
||||||
|
@ -370,6 +467,27 @@ class Incremental:
|
||||||
if response:
|
if response:
|
||||||
return smtbmc.smt.read()
|
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):
|
def cmd_design_hierwitness(self, cmd=None):
|
||||||
allregs = (cmd is None) or bool(cmd.get("allreges", False))
|
allregs = (cmd is None) or bool(cmd.get("allreges", False))
|
||||||
if self._cached_hierwitness[allregs] is not None:
|
if self._cached_hierwitness[allregs] is not None:
|
||||||
|
@ -451,6 +569,7 @@ class Incremental:
|
||||||
"pop": cmd_pop,
|
"pop": cmd_pop,
|
||||||
"check": cmd_check,
|
"check": cmd_check,
|
||||||
"smtlib": cmd_smtlib,
|
"smtlib": cmd_smtlib,
|
||||||
|
"define": cmd_define,
|
||||||
"design_hierwitness": cmd_design_hierwitness,
|
"design_hierwitness": cmd_design_hierwitness,
|
||||||
"write_yw_trace": cmd_write_yw_trace,
|
"write_yw_trace": cmd_write_yw_trace,
|
||||||
"read_yw_trace": cmd_read_yw_trace,
|
"read_yw_trace": cmd_read_yw_trace,
|
||||||
|
|
|
@ -160,6 +160,7 @@ class SmtIo:
|
||||||
self.noincr = opts.noincr
|
self.noincr = opts.noincr
|
||||||
self.info_stmts = opts.info_stmts
|
self.info_stmts = opts.info_stmts
|
||||||
self.nocomments = opts.nocomments
|
self.nocomments = opts.nocomments
|
||||||
|
self.smt2_options.update(opts.smt2_options)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.solver = "yices"
|
self.solver = "yices"
|
||||||
|
@ -959,6 +960,8 @@ class SmtIo:
|
||||||
return int(self.bv2bin(v), 2)
|
return int(self.bv2bin(v), 2)
|
||||||
|
|
||||||
def get_raw_unsat_assumptions(self):
|
def get_raw_unsat_assumptions(self):
|
||||||
|
if not self.smt2_assumptions:
|
||||||
|
return []
|
||||||
self.write("(get-unsat-assumptions)")
|
self.write("(get-unsat-assumptions)")
|
||||||
exprs = set(self.unparse(part) for part in self.parse(self.read()))
|
exprs = set(self.unparse(part) for part in self.parse(self.read()))
|
||||||
unsat_assumptions = []
|
unsat_assumptions = []
|
||||||
|
@ -973,6 +976,10 @@ class SmtIo:
|
||||||
def get_unsat_assumptions(self, minimize=False):
|
def get_unsat_assumptions(self, minimize=False):
|
||||||
if not minimize:
|
if not minimize:
|
||||||
return self.get_raw_unsat_assumptions()
|
return self.get_raw_unsat_assumptions()
|
||||||
|
orig_assumptions = self.smt2_assumptions
|
||||||
|
|
||||||
|
self.smt2_assumptions = dict(orig_assumptions)
|
||||||
|
|
||||||
required_assumptions = {}
|
required_assumptions = {}
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
@ -998,6 +1005,7 @@ class SmtIo:
|
||||||
required_assumptions[candidate_key] = candidate_assume
|
required_assumptions[candidate_key] = candidate_assume
|
||||||
|
|
||||||
if candidate_assumptions is not None:
|
if candidate_assumptions is not None:
|
||||||
|
self.smt2_assumptions = orig_assumptions
|
||||||
return list(required_assumptions)
|
return list(required_assumptions)
|
||||||
|
|
||||||
def get(self, expr):
|
def get(self, expr):
|
||||||
|
@ -1146,7 +1154,7 @@ class SmtIo:
|
||||||
class SmtOpts:
|
class SmtOpts:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.shortopts = "s:S:v"
|
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 = "yices"
|
||||||
self.solver_opts = list()
|
self.solver_opts = list()
|
||||||
self.debug_print = False
|
self.debug_print = False
|
||||||
|
@ -1159,6 +1167,7 @@ class SmtOpts:
|
||||||
self.logic = None
|
self.logic = None
|
||||||
self.info_stmts = list()
|
self.info_stmts = list()
|
||||||
self.nocomments = False
|
self.nocomments = False
|
||||||
|
self.smt2_options = {}
|
||||||
|
|
||||||
def handle(self, o, a):
|
def handle(self, o, a):
|
||||||
if o == "-s":
|
if o == "-s":
|
||||||
|
@ -1185,6 +1194,13 @@ class SmtOpts:
|
||||||
self.info_stmts.append(a)
|
self.info_stmts.append(a)
|
||||||
elif o == "--nocomments":
|
elif o == "--nocomments":
|
||||||
self.nocomments = True
|
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:
|
else:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
@ -1208,6 +1224,9 @@ class SmtOpts:
|
||||||
if solver is "dummy", read solver output from that file
|
if solver is "dummy", read solver output from that file
|
||||||
otherwise: write solver output to that file
|
otherwise: write solver output to that file
|
||||||
|
|
||||||
|
--smt2-option <option>=<value>
|
||||||
|
enable an SMT-LIBv2 option.
|
||||||
|
|
||||||
-v
|
-v
|
||||||
enable debug output
|
enable debug output
|
||||||
|
|
||||||
|
|
|
@ -2014,9 +2014,22 @@ 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)
|
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;
|
int offset = 0;
|
||||||
for (auto &chunk : left.chunks()) {
|
for (auto &chunk : left.chunks()) {
|
||||||
|
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());
|
f << stringf("%s" "assign ", indent.c_str());
|
||||||
dump_sigspec(f, chunk);
|
dump_sigspec(f, chunk);
|
||||||
f << stringf(" = ");
|
f << stringf(" = ");
|
||||||
|
@ -2024,12 +2037,6 @@ void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left,
|
||||||
f << stringf(";\n");
|
f << stringf(";\n");
|
||||||
offset += GetSize(chunk);
|
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];
|
active_initdata[sig[i]] = val[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!module->processes.empty())
|
bool has_sync_rules = false;
|
||||||
log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
|
for (auto process : module->processes)
|
||||||
"can't always be mapped directly to Verilog always blocks. Unintended\n"
|
if (!process.second->syncs.empty())
|
||||||
"changes in simulation behavior are possible! Use \"proc\" to convert\n"
|
has_sync_rules = true;
|
||||||
"processes to logic networks and registers.\n", log_id(module));
|
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");
|
f << stringf("\n");
|
||||||
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
|
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/build/
|
/build/
|
||||||
/source/cmd
|
/source/cmd
|
||||||
/source/temp
|
/source/generated
|
||||||
/source/_images/**/*.log
|
/source/_images/**/*.log
|
||||||
/source/_images/**/*.aux
|
/source/_images/**/*.aux
|
||||||
/source/_images/**/*.pdf
|
/source/_images/**/*.pdf
|
||||||
|
|
|
@ -48,6 +48,7 @@ help:
|
||||||
clean: clean-examples
|
clean: clean-examples
|
||||||
rm -rf $(BUILDDIR)/*
|
rm -rf $(BUILDDIR)/*
|
||||||
rm -rf source/cmd util/__pycache__
|
rm -rf source/cmd util/__pycache__
|
||||||
|
rm -rf source/generated
|
||||||
$(MAKE) -C source/_images clean
|
$(MAKE) -C source/_images clean
|
||||||
|
|
||||||
.PHONY: html
|
.PHONY: html
|
||||||
|
|
|
@ -24,3 +24,17 @@ a.external {
|
||||||
th {
|
th {
|
||||||
text-align: left;
|
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
|
compiler options and other information needed for building loadable modules for
|
||||||
Yosys. See :doc:`/yosys_internals/extending_yosys/extensions` for details.
|
Yosys. See :doc:`/yosys_internals/extending_yosys/extensions` for details.
|
||||||
|
|
||||||
.. literalinclude:: /temp/yosys-config
|
.. literalinclude:: /generated/yosys-config
|
||||||
:start-at: Usage
|
:start-at: Usage
|
||||||
|
|
||||||
.. _sec:filterlib:
|
.. _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
|
extract information from a Liberty file. This can be useful for removing
|
||||||
sensitive or proprietary information such as timing or other trade secrets.
|
sensitive or proprietary information such as timing or other trade secrets.
|
||||||
|
|
||||||
.. literalinclude:: /temp/yosys-filterlib
|
.. literalinclude:: /generated/yosys-filterlib
|
||||||
:start-at: Usage
|
:start-at: Usage
|
||||||
|
|
||||||
yosys-abc
|
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
|
So Yosys comes with its own yosys-abc to avoid compatibility issues between the
|
||||||
two.
|
two.
|
||||||
|
|
||||||
.. literalinclude:: /temp/yosys-abc
|
.. literalinclude:: /generated/yosys-abc
|
||||||
:start-at: usage
|
:start-at: usage
|
||||||
:end-before: UC Berkeley
|
|
||||||
|
|
||||||
yosys-smtbmc
|
yosys-smtbmc
|
||||||
------------
|
------------
|
||||||
|
@ -46,7 +45,7 @@ yosys-smtbmc
|
||||||
The ``yosys-smtbmc`` tool is a utility used by SBY for interacting with smt
|
The ``yosys-smtbmc`` tool is a utility used by SBY for interacting with smt
|
||||||
solvers.
|
solvers.
|
||||||
|
|
||||||
.. literalinclude:: /temp/yosys-smtbmc
|
.. literalinclude:: /generated/yosys-smtbmc
|
||||||
|
|
||||||
yosys-witness
|
yosys-witness
|
||||||
-------------
|
-------------
|
||||||
|
@ -55,7 +54,7 @@ yosys-witness
|
||||||
This is used in SBY and SCY for producing traces in a consistent format
|
This is used in SBY and SCY for producing traces in a consistent format
|
||||||
independent of the solver.
|
independent of the solver.
|
||||||
|
|
||||||
.. literalinclude:: /temp/yosys-witness
|
.. literalinclude:: /generated/yosys-witness
|
||||||
:start-at: Usage
|
:start-at: Usage
|
||||||
|
|
||||||
.. note:: ``yosys-witness`` requires `click`_ Python package for use.
|
.. 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.
|
abstraction and how they relate to different kinds of synthesis.
|
||||||
|
|
||||||
.. figure:: /_images/primer/basics_abstractions.*
|
.. figure:: /_images/primer/basics_abstractions.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Basics_abstractions
|
:name: fig:Basics_abstractions
|
||||||
|
|
||||||
Different levels of abstraction and synthesis.
|
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>`.
|
This process is illustrated in :numref:`Fig. %s <fig:Basics_flow>`.
|
||||||
|
|
||||||
.. figure:: /_images/primer/basics_flow.*
|
.. figure:: /_images/primer/basics_flow.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Basics_flow
|
:name: fig:Basics_flow
|
||||||
|
|
||||||
Typical design flow. Green boxes represent manually created models.
|
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;
|
expr: TOK_IDENTIFIER | TOK_NUMBER | expr TOK_PLUS expr;
|
||||||
|
|
||||||
.. figure:: /_images/primer/basics_parsetree.*
|
.. figure:: /_images/primer/basics_parsetree.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Basics_parsetree
|
:name: fig:Basics_parsetree
|
||||||
|
|
||||||
Example parse tree for the Verilog expression
|
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`
|
three-address-code intermediate representation. :cite:p:`Dragonbook`
|
||||||
|
|
||||||
.. figure:: /_images/primer/basics_ast.*
|
.. figure:: /_images/primer/basics_ast.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Basics_ast
|
:name: fig:Basics_ast
|
||||||
|
|
||||||
Example abstract syntax tree for the Verilog expression
|
Example abstract syntax tree for the Verilog expression
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
Command line reference
|
Command line reference
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
.. literalinclude:: /temp/yosys
|
.. literalinclude:: /generated/yosys
|
||||||
:start-at: Usage
|
:start-at: Usage
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
my_cmd.so
|
my_cmd.so
|
||||||
my_cmd.d
|
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
|
$(YOSYS)-config --exec --cxx $(subst $(DATDIR),../../../../share,$(CXXFLAGS)) --ldflags -o my_cmd.so -shared my_cmd.cc --ldlibs
|
||||||
|
|
||||||
test0.log: my_cmd.so
|
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
|
mv test0.log_new test0.log
|
||||||
|
|
||||||
test1.log: my_cmd.so
|
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
|
mv test1.log_new test1.log
|
||||||
|
|
||||||
test1.dot: my_cmd.so
|
test1.dot: my_cmd.so
|
||||||
$(YOSYS) -m ./my_cmd.so -p 'test1; show -format dot -prefix test1'
|
$(YOSYS) -m ./my_cmd.so -p 'test1; show -format dot -prefix test1'
|
||||||
|
|
||||||
test2.log: my_cmd.so
|
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
|
mv test2.log_new test2.log
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
|
@ -4,7 +4,8 @@ import os
|
||||||
|
|
||||||
project = 'YosysHQ Yosys'
|
project = 'YosysHQ Yosys'
|
||||||
author = 'YosysHQ GmbH'
|
author = 'YosysHQ GmbH'
|
||||||
copyright ='2022 YosysHQ GmbH'
|
copyright ='2024 YosysHQ GmbH'
|
||||||
|
yosys_ver = "0.41"
|
||||||
|
|
||||||
# select HTML theme
|
# select HTML theme
|
||||||
html_theme = 'furo'
|
html_theme = 'furo'
|
||||||
|
@ -46,12 +47,18 @@ extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex']
|
||||||
autosectionlabel_prefix_document = True
|
autosectionlabel_prefix_document = True
|
||||||
autosectionlabel_maxdepth = 1
|
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
|
# assign figure numbers
|
||||||
numfig = True
|
numfig = True
|
||||||
|
|
||||||
bibtex_bibfiles = ['literature.bib']
|
bibtex_bibfiles = ['literature.bib']
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
|
'releasename': 'Version',
|
||||||
'preamble': r'''
|
'preamble': r'''
|
||||||
\usepackage{lmodern}
|
\usepackage{lmodern}
|
||||||
\usepackage{comment}
|
\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:
|
Our ``addr_gen`` circuit now looks like this:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/addr_gen_hier.*
|
.. figure:: /_images/code_examples/fifo/addr_gen_hier.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: addr_gen_hier
|
:name: addr_gen_hier
|
||||||
|
|
||||||
``addr_gen`` module after :cmd:ref:`hierarchy`
|
``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.
|
automatic optimizations which would normally happen.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/addr_gen_proc.*
|
.. figure:: /_images/code_examples/fifo/addr_gen_proc.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: addr_gen_proc
|
:name: addr_gen_proc
|
||||||
|
|
||||||
``addr_gen`` module after :yoscrypt:`proc -noopt`
|
``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`.
|
clean`.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/addr_gen_clean.*
|
.. figure:: /_images/code_examples/fifo/addr_gen_clean.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: addr_gen_clean
|
:name: addr_gen_clean
|
||||||
|
|
||||||
``addr_gen`` module after :yoscrypt:`opt_expr; 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`.
|
:doc:`/getting_started/scripting_intro` has more on how to use :cmd:ref:`show`.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_proc.*
|
.. figure:: /_images/code_examples/fifo/rdata_proc.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_proc
|
:name: rdata_proc
|
||||||
|
|
||||||
``rdata`` output after :cmd:ref:`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;;`
|
:caption: output of :yoscrypt:`flatten;;`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_flat.*
|
.. figure:: /_images/code_examples/fifo/rdata_flat.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_flat
|
:name: rdata_flat
|
||||||
|
|
||||||
``rdata`` output after :yoscrypt:`flatten;;`
|
``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`
|
:caption: output of :cmd:ref:`opt_dff`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_adffe.*
|
.. figure:: /_images/code_examples/fifo/rdata_adffe.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_adffe
|
:name: rdata_adffe
|
||||||
|
|
||||||
``rdata`` output after :cmd:ref:`opt_dff`
|
``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`
|
.. todo:: pending bugfix in :cmd:ref:`wreduce` and/or :cmd:ref:`opt_clean`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_wreduce.*
|
.. figure:: /_images/code_examples/fifo/rdata_wreduce.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_wreduce
|
:name: rdata_wreduce
|
||||||
|
|
||||||
``rdata`` output after :cmd:ref:`wreduce`
|
``rdata`` output after :cmd:ref:`wreduce`
|
||||||
|
@ -446,7 +446,7 @@ Our next command to run is
|
||||||
:caption: output of :cmd:ref:`memory_dff`
|
:caption: output of :cmd:ref:`memory_dff`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_memrdv2.*
|
.. figure:: /_images/code_examples/fifo/rdata_memrdv2.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_memrdv2
|
:name: rdata_memrdv2
|
||||||
|
|
||||||
``rdata`` output after :cmd:ref:`memory_dff`
|
``rdata`` output after :cmd:ref:`memory_dff`
|
||||||
|
@ -535,7 +535,7 @@ example design:
|
||||||
:caption: output of :cmd:ref:`alumacc`
|
:caption: output of :cmd:ref:`alumacc`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_alumacc.*
|
.. figure:: /_images/code_examples/fifo/rdata_alumacc.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_alumacc
|
:name: rdata_alumacc
|
||||||
|
|
||||||
``rdata`` output after :cmd:ref:`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.
|
combines all of the reads and writes for a memory block into a single cell.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_coarse.*
|
.. figure:: /_images/code_examples/fifo/rdata_coarse.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_coarse
|
:name: rdata_coarse
|
||||||
|
|
||||||
``rdata`` output after :cmd:ref:`memory_collect`
|
``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
|
:caption: ``map_ram`` section
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_map_ram.*
|
.. figure:: /_images/code_examples/fifo/rdata_map_ram.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_map_ram
|
:name: rdata_map_ram
|
||||||
|
|
||||||
``rdata`` output after :ref:`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
|
:caption: ``map_ffram`` section
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_map_ffram.*
|
.. figure:: /_images/code_examples/fifo/rdata_map_ffram.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_map_ffram
|
:name: rdata_map_ffram
|
||||||
|
|
||||||
``rdata`` output after :ref:`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
|
:caption: ``map_gates`` section
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_map_gates.*
|
.. figure:: /_images/code_examples/fifo/rdata_map_gates.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_map_gates
|
:name: rdata_map_gates
|
||||||
|
|
||||||
``rdata`` output after :ref:`map_gates`
|
``rdata`` output after :ref:`map_gates`
|
||||||
|
@ -711,7 +711,7 @@ instead with an ``$_AND_`` cell.
|
||||||
:caption: ``map_ffs`` section
|
:caption: ``map_ffs`` section
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_map_ffs.*
|
.. figure:: /_images/code_examples/fifo/rdata_map_ffs.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_map_ffs
|
:name: rdata_map_ffs
|
||||||
|
|
||||||
``rdata`` output after :ref:`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
|
:caption: ``map_luts`` section
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_map_luts.*
|
.. figure:: /_images/code_examples/fifo/rdata_map_luts.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_map_luts
|
:name: rdata_map_luts
|
||||||
|
|
||||||
``rdata`` output after :ref:`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
|
:caption: ``map_cells`` section
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/rdata_map_cells.*
|
.. figure:: /_images/code_examples/fifo/rdata_map_cells.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: rdata_map_cells
|
:name: rdata_map_cells
|
||||||
|
|
||||||
``rdata`` output after :ref:`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.
|
:doc:`/using_yosys/more_scripting/interactive_investigation` page.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/addr_gen_show.*
|
.. figure:: /_images/code_examples/fifo/addr_gen_show.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: addr_gen_show
|
:name: addr_gen_show
|
||||||
|
|
||||||
Calling :yoscrypt:`show addr_gen` after :cmd:ref:`hierarchy`
|
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:
|
``$eq``. We can call :cmd:ref:`show` on that selection just as easily:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/new_cells_show.*
|
.. figure:: /_images/code_examples/fifo/new_cells_show.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: new_cells_show
|
:name: new_cells_show
|
||||||
|
|
||||||
Calling :yoscrypt:`show -notitle @new_cells`
|
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:
|
:yoscrypt:`-color` option:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/fifo/addr_gen_hier.*
|
.. 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`
|
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.
|
for specialised tasks.
|
||||||
|
|
||||||
.. figure:: /_images/primer/levels_of_abstraction.*
|
.. figure:: /_images/primer/levels_of_abstraction.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Levels_of_abstraction
|
:name: fig:Levels_of_abstraction
|
||||||
|
|
||||||
Where Yosys exists in the layers of abstraction
|
Where Yosys exists in the layers of abstraction
|
||||||
|
|
|
@ -56,7 +56,7 @@ is shown.
|
||||||
``xdot example_first.dot`` etc.
|
``xdot example_first.dot`` etc.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/show/example_first.*
|
.. 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`
|
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:
|
multiplexer and a d-type flip-flop, which brings us to the second diagram:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/show/example_second.*
|
.. 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`
|
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:
|
leads us to the third diagram:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/show/example_third.*
|
.. figure:: /_images/code_examples/show/example_third.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: example_out
|
:name: example_out
|
||||||
|
|
||||||
Output of the third :cmd:ref:`show` command in :ref:`example_ys`
|
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.
|
when the individual bits of of a signal vector are accessed.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/show/splice.*
|
.. figure:: /_images/code_examples/show/splice.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: splice_dia
|
:name: splice_dia
|
||||||
|
|
||||||
Output of ``yosys -p 'prep -top splice_demo; show' splice.v``
|
Output of ``yosys -p 'prep -top splice_demo; show' splice.v``
|
||||||
|
@ -165,7 +165,7 @@ Gate level netlists
|
||||||
mapped to a cell library:
|
mapped to a cell library:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/show/cmos_00.*
|
.. figure:: /_images/code_examples/show/cmos_00.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: first_pitfall
|
:name: first_pitfall
|
||||||
|
|
||||||
A half-adder built from simple CMOS gates, demonstrating common pitfalls when
|
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.
|
individual bits, resulting in an unnecessary complex diagram.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/show/cmos_01.*
|
.. figure:: /_images/code_examples/show/cmos_01.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: second_pitfall
|
:name: second_pitfall
|
||||||
|
|
||||||
Effects of :cmd:ref:`splitnets` command and of providing a cell library on
|
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 ..
|
:end-before: cd ..
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/scrambler/scrambler_p01.*
|
.. figure:: /_images/code_examples/scrambler/scrambler_p01.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/scrambler/scrambler_p02.*
|
.. figure:: /_images/code_examples/scrambler/scrambler_p02.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Analyzing the resulting circuit with :doc:`/cmd/eval`:
|
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`:
|
Recall the ``memdemo`` design from :ref:`advanced_logic_cones`:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/memdemo_00.*
|
.. figure:: /_images/code_examples/selections/memdemo_00.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
``memdemo``
|
``memdemo``
|
||||||
|
|
||||||
|
@ -463,18 +463,18 @@ name of the new cell in the current module. The resulting circuits are shown
|
||||||
below.
|
below.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/submod_02.*
|
.. figure:: /_images/code_examples/selections/submod_02.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
``outstage``
|
``outstage``
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/submod_03.*
|
.. figure:: /_images/code_examples/selections/submod_03.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: selstage
|
:name: selstage
|
||||||
|
|
||||||
``selstage``
|
``selstage``
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/submod_01.*
|
.. figure:: /_images/code_examples/selections/submod_01.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
``scramble``
|
``scramble``
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,7 @@ Selecting ``a:sumstuff`` in this module will yield the following circuit
|
||||||
diagram:
|
diagram:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/sumprod_00.*
|
.. figure:: /_images/code_examples/selections/sumprod_00.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: sumprod_00
|
:name: sumprod_00
|
||||||
|
|
||||||
Output of ``show a:sumstuff`` on :numref:`sumprod`
|
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`:
|
:yoscrypt:`show a:sumstuff %x` yields the diagram shown in :numref:`sumprod_01`:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/sumprod_01.*
|
.. figure:: /_images/code_examples/selections/sumprod_01.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: sumprod_01
|
:name: sumprod_01
|
||||||
|
|
||||||
Output of ``show a:sumstuff %x`` on :numref:`sumprod`
|
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:
|
The following sequence of diagrams demonstrates this step-wise expansion:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/sumprod_02.*
|
.. figure:: /_images/code_examples/selections/sumprod_02.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Output of :yoscrypt:`show prod` on :numref:`sumprod`
|
Output of :yoscrypt:`show prod` on :numref:`sumprod`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/sumprod_03.*
|
.. figure:: /_images/code_examples/selections/sumprod_03.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Output of :yoscrypt:`show prod %ci` on :numref:`sumprod`
|
Output of :yoscrypt:`show prod %ci` on :numref:`sumprod`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/sumprod_04.*
|
.. 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`
|
Output of :yoscrypt:`show prod %ci %ci` on :numref:`sumprod`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/sumprod_05.*
|
.. 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`
|
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`.
|
diagram in :numref:`memdemo_00`.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/memdemo_00.*
|
.. figure:: /_images/code_examples/selections/memdemo_00.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: memdemo_00
|
:name: memdemo_00
|
||||||
|
|
||||||
Complete circuit diagram for the design shown in :numref:`memdemo_src`
|
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`:
|
cones`_ from above, we can use :yoscrypt:`show y %ci2`:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/memdemo_01.*
|
.. figure:: /_images/code_examples/selections/memdemo_01.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: memdemo_01
|
:name: memdemo_01
|
||||||
|
|
||||||
Output of :yoscrypt:`show y %ci2`
|
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`:
|
start of the name). Let's go a bit further now and try :yoscrypt:`show y %ci5`:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/memdemo_02.*
|
.. figure:: /_images/code_examples/selections/memdemo_02.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: memdemo_02
|
:name: memdemo_02
|
||||||
|
|
||||||
Output of :yoscrypt:`show y %ci5`
|
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]`:
|
type with :yoscrypt:`show y %ci5:-$mux[S]`:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/memdemo_03.*
|
.. figure:: /_images/code_examples/selections/memdemo_03.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: memdemo_03
|
:name: memdemo_03
|
||||||
|
|
||||||
Output of :yoscrypt:`show y %ci5:-$mux[S]`
|
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:
|
multiplexer select inputs and flip-flop cells:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/memdemo_05.*
|
.. figure:: /_images/code_examples/selections/memdemo_05.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: memdemo_05
|
:name: memdemo_05
|
||||||
|
|
||||||
Output of ``show y %ci2:+$dff[Q,D] %ci*:-$mux[S]:-$dff``
|
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
|
.. TODO:: pending discussion on whether rule ordering is a bug or a feature
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/memdemo_04.*
|
.. figure:: /_images/code_examples/selections/memdemo_04.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: memdemo_04
|
:name: memdemo_04
|
||||||
|
|
||||||
Output of :yoscrypt:`show y %ci*:-[CLK,S]:+$dff,$mux`
|
Output of :yoscrypt:`show y %ci*:-[CLK,S]:+$dff,$mux`
|
||||||
|
@ -417,6 +417,6 @@ Example code from |code_examples/selections|_:
|
||||||
:name: select_ys
|
:name: select_ys
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/selections/select.*
|
.. figure:: /_images/code_examples/selections/select.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Circuit diagram produced by :numref:`select_ys`
|
Circuit diagram produced by :numref:`select_ys`
|
||||||
|
|
|
@ -51,7 +51,7 @@ Loading the design
|
||||||
Our circuit now looks like this:
|
Our circuit now looks like this:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/intro/counter_00.*
|
.. figure:: /_images/code_examples/intro/counter_00.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: counter-hierarchy
|
:name: counter-hierarchy
|
||||||
|
|
||||||
``counter`` after :cmd:ref:`hierarchy`
|
``counter`` after :cmd:ref:`hierarchy`
|
||||||
|
@ -66,7 +66,7 @@ Coarse-grain representation
|
||||||
:caption: :file:`counter.ys` - the high-level stuff
|
:caption: :file:`counter.ys` - the high-level stuff
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/intro/counter_01.*
|
.. figure:: /_images/code_examples/intro/counter_01.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Coarse-grain representation of the ``counter`` module
|
Coarse-grain representation of the ``counter`` module
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ Logic gate mapping
|
||||||
:caption: :file:`counter.ys` - mapping to internal cell library
|
:caption: :file:`counter.ys` - mapping to internal cell library
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/intro/counter_02.*
|
.. figure:: /_images/code_examples/intro/counter_02.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
``counter`` after :cmd:ref:`techmap`
|
``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:
|
The final version of our ``counter`` module looks like this:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/intro/counter_03.*
|
.. figure:: /_images/code_examples/intro/counter_03.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
``counter`` after hardware cell mapping
|
``counter`` after hardware cell mapping
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ Example code can be found in |code_examples/macc|_.
|
||||||
:lines: 1-2
|
:lines: 1-2
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_simple_test_00a.*
|
.. figure:: /_images/code_examples/macc/macc_simple_test_00a.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
before :cmd:ref:`extract`
|
before :cmd:ref:`extract`
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ Example code can be found in |code_examples/macc|_.
|
||||||
:lines: 6
|
:lines: 6
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_simple_test_00b.*
|
.. figure:: /_images/code_examples/macc/macc_simple_test_00b.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
after :cmd:ref:`extract`
|
after :cmd:ref:`extract`
|
||||||
|
|
||||||
|
@ -49,20 +49,20 @@ Example code can be found in |code_examples/macc|_.
|
||||||
:caption: :file:`macc_simple_test_01.v`
|
:caption: :file:`macc_simple_test_01.v`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_simple_test_01a.*
|
.. 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.*
|
.. 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
|
.. literalinclude:: /code_examples/macc/macc_simple_test_02.v
|
||||||
:language: verilog
|
:language: verilog
|
||||||
:caption: :file:`macc_simple_test_02.v`
|
:caption: :file:`macc_simple_test_02.v`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_simple_test_02a.*
|
.. 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.*
|
.. figure:: /_images/code_examples/macc/macc_simple_test_02b.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
The wrap-extract-unwrap method
|
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`
|
:caption: ``test1`` of :file:`macc_xilinx_test.v`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test1a.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test1a.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test1b.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test1b.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/macc/macc_xilinx_test.v
|
.. literalinclude:: /code_examples/macc/macc_xilinx_test.v
|
||||||
:language: verilog
|
:language: verilog
|
||||||
|
@ -160,15 +160,15 @@ Unwrapping adders: :file:`macc_xilinx_unwrap_map.v`
|
||||||
:caption: ``test2`` of :file:`macc_xilinx_test.v`
|
:caption: ``test2`` of :file:`macc_xilinx_test.v`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test2a.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test2a.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test2b.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test2b.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Wrapping in ``test1``:
|
Wrapping in ``test1``:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test1b.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test1b.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
||||||
:language: yoscrypt
|
:language: yoscrypt
|
||||||
|
@ -176,12 +176,12 @@ Wrapping in ``test1``:
|
||||||
:end-before: end part c
|
:end-before: end part c
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test1c.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test1c.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Wrapping in ``test2``:
|
Wrapping in ``test2``:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test2b.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test2b.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
||||||
:language: yoscrypt
|
:language: yoscrypt
|
||||||
|
@ -189,12 +189,12 @@ Wrapping in ``test2``:
|
||||||
:end-before: end part c
|
:end-before: end part c
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test2c.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test2c.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Extract in ``test1``:
|
Extract in ``test1``:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test1c.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test1c.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
||||||
:language: yoscrypt
|
:language: yoscrypt
|
||||||
|
@ -202,12 +202,12 @@ Extract in ``test1``:
|
||||||
:end-before: end part d
|
:end-before: end part d
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test1d.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test1d.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Extract in ``test2``:
|
Extract in ``test2``:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test2c.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test2c.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
||||||
:language: yoscrypt
|
:language: yoscrypt
|
||||||
|
@ -215,12 +215,12 @@ Extract in ``test2``:
|
||||||
:end-before: end part d
|
:end-before: end part d
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test2d.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test2d.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Unwrap in ``test2``:
|
Unwrap in ``test2``:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test2d.*
|
.. figure:: /_images/code_examples/macc/macc_xilinx_test2d.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
.. literalinclude:: /code_examples/macc/macc_xilinx_test.ys
|
||||||
:language: yoscrypt
|
:language: yoscrypt
|
||||||
|
@ -228,4 +228,4 @@ Unwrap in ``test2``:
|
||||||
:end-before: end part e
|
:end-before: end part e
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/macc/macc_xilinx_test2e.*
|
.. 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
|
.. _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.*
|
.. figure:: /_images/code_examples/synth_flow/memory_01.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/synth_flow/memory_01.ys
|
.. literalinclude:: /code_examples/synth_flow/memory_01.ys
|
||||||
:language: yoscrypt
|
:language: yoscrypt
|
||||||
|
@ -50,7 +50,7 @@ Example
|
||||||
:caption: :file:`memory_01.v`
|
:caption: :file:`memory_01.v`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/synth_flow/memory_02.*
|
.. figure:: /_images/code_examples/synth_flow/memory_02.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/synth_flow/memory_02.v
|
.. literalinclude:: /code_examples/synth_flow/memory_02.v
|
||||||
:language: verilog
|
:language: verilog
|
||||||
|
|
|
@ -88,7 +88,7 @@ trees can interfere with other optimizations.
|
||||||
:caption: example verilog for demonstrating :cmd:ref:`opt_expr`
|
:caption: example verilog for demonstrating :cmd:ref:`opt_expr`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/opt/opt_expr.*
|
.. figure:: /_images/code_examples/opt/opt_expr.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Before and after :cmd:ref:`opt_expr`
|
Before and after :cmd:ref:`opt_expr`
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ possible optimizations.
|
||||||
:caption: example verilog for demonstrating :cmd:ref:`opt_merge`
|
:caption: example verilog for demonstrating :cmd:ref:`opt_merge`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/opt/opt_merge.*
|
.. figure:: /_images/code_examples/opt/opt_merge.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Before and after :cmd:ref:`opt_merge`
|
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``.
|
yielding the logic for ``y = a ? b : d``.
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/opt/opt_muxtree.*
|
.. figure:: /_images/code_examples/opt/opt_muxtree.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Before and after :cmd:ref:`opt_muxtree`
|
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`
|
:caption: example verilog for demonstrating :cmd:ref:`opt_share`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/opt/opt_share.*
|
.. figure:: /_images/code_examples/opt/opt_share.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Before and after :cmd:ref:`opt_share`
|
Before and after :cmd:ref:`opt_share`
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,10 @@ Example
|
||||||
:caption: :file:`proc_01.ys`
|
:caption: :file:`proc_01.ys`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/synth_flow/proc_01.*
|
.. figure:: /_images/code_examples/synth_flow/proc_01.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/synth_flow/proc_02.*
|
.. figure:: /_images/code_examples/synth_flow/proc_02.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/synth_flow/proc_02.v
|
.. literalinclude:: /code_examples/synth_flow/proc_02.v
|
||||||
:language: verilog
|
:language: verilog
|
||||||
|
@ -56,7 +56,7 @@ Example
|
||||||
:caption: :file:`proc_02.ys`
|
:caption: :file:`proc_02.ys`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/synth_flow/proc_03.*
|
.. figure:: /_images/code_examples/synth_flow/proc_03.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/synth_flow/proc_03.ys
|
.. literalinclude:: /code_examples/synth_flow/proc_03.ys
|
||||||
:language: yoscrypt
|
: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`):
|
commands :cmd:ref:`proc` and :cmd:ref:`memory` (or :yoscrypt:`memory -nomap`):
|
||||||
|
|
||||||
.. figure:: /_images/internals/simplified_rtlil.*
|
.. figure:: /_images/internals/simplified_rtlil.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Simplified_RTLIL
|
:name: fig:Simplified_RTLIL
|
||||||
|
|
||||||
Simplified RTLIL entity-relationship diagram without memories and processes
|
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:
|
And if we look at the schematic for this new module we see the following:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/extensions/test1.*
|
.. figure:: /_images/code_examples/extensions/test1.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
Output of ``yosys -m ./my_cmd.so -p 'test1; show'``
|
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>`).
|
<fig:approach_flow>`).
|
||||||
|
|
||||||
.. figure:: /_images/internals/approach_flow.*
|
.. figure:: /_images/internals/approach_flow.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:approach_flow
|
:name: fig:approach_flow
|
||||||
|
|
||||||
General data- and control-flow of a synthesis tool
|
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.
|
design in different stages of the synthesis.
|
||||||
|
|
||||||
.. figure:: /_images/internals/overview_flow.*
|
.. figure:: /_images/internals/overview_flow.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Overview_flow
|
:name: fig:Overview_flow
|
||||||
|
|
||||||
Yosys simplified data flow (ellipses: data structures, rectangles:
|
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>`.
|
illustrated in :numref:`Fig. %s <fig:Verilog_flow>`.
|
||||||
|
|
||||||
.. figure:: /_images/internals/verilog_flow.*
|
.. figure:: /_images/internals/verilog_flow.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Verilog_flow
|
:name: fig:Verilog_flow
|
||||||
|
|
||||||
Simplified Verilog to RTLIL data flow
|
Simplified Verilog to RTLIL data flow
|
||||||
|
|
|
@ -619,6 +619,92 @@ Finite state machines
|
||||||
|
|
||||||
Add a brief description of the ``$fsm`` cell type.
|
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
|
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 ``$slice`` and ``$concat`` cells.
|
||||||
|
|
||||||
.. todo:: Add information about ``$lut`` and ``$sop`` cells.
|
.. todo:: Add information about ``$alu``, ``$fa``, and ``$lcu`` cells.
|
||||||
|
|
||||||
.. todo:: Add information about ``$alu``, ``$macc``, ``$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.
|
this other object to parse the cell library.
|
||||||
|
|
||||||
.. figure:: /_images/internals/overview_rtlil.*
|
.. figure:: /_images/internals/overview_rtlil.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
:name: fig:Overview_RTLIL
|
:name: fig:Overview_RTLIL
|
||||||
|
|
||||||
Simplified RTLIL Entity-Relationship Diagram
|
Simplified RTLIL Entity-Relationship Diagram
|
||||||
|
|
|
@ -34,7 +34,7 @@ Mapping OR3X1
|
||||||
:caption: :file:`red_or3x1_map.v`
|
:caption: :file:`red_or3x1_map.v`
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/techmap/red_or3x1.*
|
.. figure:: /_images/code_examples/techmap/red_or3x1.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/techmap/red_or3x1_test.ys
|
.. literalinclude:: /code_examples/techmap/red_or3x1_test.ys
|
||||||
:language: yoscrypt
|
:language: yoscrypt
|
||||||
|
@ -61,7 +61,7 @@ Conditional techmap
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/techmap/sym_mul.*
|
.. figure:: /_images/code_examples/techmap/sym_mul.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/techmap/sym_mul_map.v
|
.. literalinclude:: /code_examples/techmap/sym_mul_map.v
|
||||||
:language: verilog
|
:language: verilog
|
||||||
|
@ -100,7 +100,7 @@ Scripting in map modules
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/techmap/mymul.*
|
.. figure:: /_images/code_examples/techmap/mymul.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/techmap/mymul_map.v
|
.. literalinclude:: /code_examples/techmap/mymul_map.v
|
||||||
:language: verilog
|
:language: verilog
|
||||||
|
@ -130,7 +130,7 @@ Handling constant inputs
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/techmap/mulshift.*
|
.. figure:: /_images/code_examples/techmap/mulshift.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/techmap/mulshift_map.v
|
.. literalinclude:: /code_examples/techmap/mulshift_map.v
|
||||||
:language: verilog
|
:language: verilog
|
||||||
|
@ -162,7 +162,7 @@ Handling shorted inputs
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. figure:: /_images/code_examples/techmap/addshift.*
|
.. figure:: /_images/code_examples/techmap/addshift.*
|
||||||
:class: width-helper
|
:class: width-helper invert-helper
|
||||||
|
|
||||||
.. literalinclude:: /code_examples/techmap/addshift_map.v
|
.. literalinclude:: /code_examples/techmap/addshift_map.v
|
||||||
:language: verilog
|
:language: verilog
|
||||||
|
|
|
@ -10,13 +10,14 @@ import sys
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
# expects __file__ = yosys/docs/tests/macro_commands.py
|
# 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
|
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)
|
THIS_FILE = (TESTS_DIR / "macro_commands.py").relative_to(ROOT_DIR)
|
||||||
MACRO_SOURCE = TESTS_DIR.parent / "source" / "code_examples" / "macro_commands"
|
MACRO_SOURCE = TESTS_DIR.parent / "source" / "code_examples" / "macro_commands"
|
||||||
assert MACRO_SOURCE.exists(), f"can't find macro_commands in {MACRO_SOURCE}"
|
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}"
|
assert YOSYS.exists(), f"can't find yosys executable in {YOSYS}"
|
||||||
|
|
||||||
raise_error = False
|
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) {
|
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
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);
|
log_debug2("%d is an output\n", l1);
|
||||||
RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i));
|
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));
|
module->connect(wire, createWireIfNotExists(module, l1));
|
||||||
outputs.push_back(wire);
|
outputs.push_back(wire);
|
||||||
}
|
}
|
||||||
//std::getline(f, line); // Ignore up to start of next line
|
|
||||||
|
|
||||||
// Parse bad properties
|
// Parse bad properties
|
||||||
for (unsigned i = 0; i < B; ++i, ++line_count) {
|
for (unsigned i = 0; i < B; ++i, ++line_count) {
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
|
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);
|
log_debug2("%d is a bad state property\n", l1);
|
||||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||||
wire->port_output = true;
|
wire->port_output = true;
|
||||||
bad_properties.push_back(wire);
|
bad_properties.push_back(wire);
|
||||||
}
|
}
|
||||||
//if (B > 0)
|
|
||||||
// std::getline(f, line); // Ignore up to start of next line
|
|
||||||
|
|
||||||
// TODO: Parse invariant constraints
|
// TODO: Parse invariant constraints
|
||||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
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) {
|
for (unsigned i = 0; i < A; ++i) {
|
||||||
if (!(f >> l1 >> l2 >> l3))
|
if (!(f >> l1 >> l2 >> l3))
|
||||||
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
|
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_debug2("%d %d %d is an AND\n", l1, l2, l3);
|
||||||
log_assert(!(l1 & 1));
|
log_assert(!(l1 & 1));
|
||||||
|
@ -636,7 +636,6 @@ void AigerReader::parse_aiger_ascii()
|
||||||
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||||
module->addAndGate("$and" + o_wire->name.str(), i1_wire, i2_wire, o_wire);
|
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)
|
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) {
|
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
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);
|
log_debug2("%d is an output\n", l1);
|
||||||
RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i));
|
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));
|
module->connect(wire, createWireIfNotExists(module, l1));
|
||||||
outputs.push_back(wire);
|
outputs.push_back(wire);
|
||||||
}
|
}
|
||||||
std::getline(f, line); // Ignore up to start of next line
|
|
||||||
|
|
||||||
// Parse bad properties
|
// Parse bad properties
|
||||||
for (unsigned i = 0; i < B; ++i, ++line_count) {
|
for (unsigned i = 0; i < B; ++i, ++line_count) {
|
||||||
if (!(f >> l1))
|
if (!(f >> l1))
|
||||||
log_error("Line %u cannot be interpreted as a bad state property!\n", line_count);
|
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);
|
log_debug2("%d is a bad state property\n", l1);
|
||||||
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||||
wire->port_output = true;
|
wire->port_output = true;
|
||||||
bad_properties.push_back(wire);
|
bad_properties.push_back(wire);
|
||||||
}
|
}
|
||||||
if (B > 0)
|
|
||||||
std::getline(f, line); // Ignore up to start of next line
|
|
||||||
|
|
||||||
// TODO: Parse invariant constraints
|
// TODO: Parse invariant constraints
|
||||||
for (unsigned i = 0; i < C; ++i, ++line_count)
|
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||||
|
|
|
@ -790,7 +790,7 @@ struct AST_INTERNAL::ProcessGenerator
|
||||||
Fmt fmt;
|
Fmt fmt;
|
||||||
fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name);
|
fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name);
|
||||||
if (ast->str.substr(0, 8) == "$display")
|
if (ast->str.substr(0, 8) == "$display")
|
||||||
fmt.append_string("\n");
|
fmt.append_literal("\n");
|
||||||
fmt.emit_rtlil(cell);
|
fmt.emit_rtlil(cell);
|
||||||
} else if (!ast->str.empty()) {
|
} 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());
|
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
|
else
|
||||||
input_error("FATAL.\n");
|
input_error("FATAL.\n");
|
||||||
} else {
|
} else {
|
||||||
input_error("Unknown elabortoon system task '%s'.\n", str.c_str());
|
input_error("Unknown elaboration system task '%s'.\n", str.c_str());
|
||||||
}
|
}
|
||||||
} break;
|
} 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
|
// 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);
|
Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base, /*first_arg_at=*/0, /*may_fail=*/true);
|
||||||
if (str.substr(0, 8) == "$display")
|
if (str.substr(0, 8) == "$display")
|
||||||
fmt.append_string("\n");
|
fmt.append_literal("\n");
|
||||||
log("%s", fmt.render().c_str());
|
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_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_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_2008/. share/verific.new/vhdl_vdbs_2008
|
||||||
|
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2019/. share/verific.new/vhdl_vdbs_2019
|
||||||
endif
|
endif
|
||||||
$(Q) chmod -R a+rX share/verific.new
|
$(Q) chmod -R a+rX share/verific.new
|
||||||
$(Q) mv share/verific.new share/verific
|
$(Q) mv share/verific.new share/verific
|
||||||
|
|
|
@ -214,23 +214,120 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When used as attributes or parameter values Verific constants come already processed.
|
RTLIL::Const mkconst_str(const std::string &str)
|
||||||
// - 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)
|
|
||||||
{
|
{
|
||||||
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;
|
char *end;
|
||||||
int decimal;
|
int decimal;
|
||||||
bool is_signed = false;
|
bool is_signed = false;
|
||||||
RTLIL::Const c;
|
|
||||||
std::string val = std::string(value);
|
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()=='\"') {
|
if (allow_string && val.size()>1 && val[0]=='\"' && val.back()=='\"') {
|
||||||
c = RTLIL::Const(val.substr(1,val.size()-2));
|
c = RTLIL::Const(val.substr(1,val.size()-2));
|
||||||
} else if ((found = val.find("'sb")) != std::string::npos) {
|
} 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) {
|
} else if (allow_string) {
|
||||||
c = RTLIL::Const(val);
|
c = RTLIL::Const(val);
|
||||||
} else {
|
} 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)
|
if (is_signed)
|
||||||
c.flags |= RTLIL::CONST_FLAG_SIGNED;
|
c.flags |= RTLIL::CONST_FLAG_SIGNED;
|
||||||
|
|
||||||
return c;
|
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)
|
static const std::string verific_unescape(const char *value)
|
||||||
{
|
{
|
||||||
std::string val = std::string(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) {
|
FOREACH_ATTRIBUTE(obj, mi, attr) {
|
||||||
if (attr->Key()[0] == ' ' || attr->Value() == nullptr)
|
if (attr->Key()[0] == ' ' || attr->Value() == nullptr)
|
||||||
continue;
|
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) {
|
if (nl) {
|
||||||
|
@ -298,7 +436,7 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att
|
||||||
const char *k, *v;
|
const char *k, *v;
|
||||||
FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mi, &k, &v) {
|
FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mi, &k, &v) {
|
||||||
if (nl->IsFromVerilog()) {
|
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));
|
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);
|
import_attributes(module->attributes, nl, nl);
|
||||||
module->set_string_attribute(ID::hdlname, nl->CellBaseName());
|
module->set_string_attribute(ID::hdlname, nl->CellBaseName());
|
||||||
|
module->set_string_attribute(ID(library), nl->Owner()->Owner()->Name());
|
||||||
#ifdef VERIFIC_VHDL_SUPPORT
|
#ifdef VERIFIC_VHDL_SUPPORT
|
||||||
if (nl->IsFromVhdl()) {
|
if (nl->IsFromVhdl()) {
|
||||||
NameSpace name_space(0);
|
NameSpace name_space(0);
|
||||||
|
@ -1304,7 +1443,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
MapIter mi;
|
MapIter mi;
|
||||||
FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) {
|
FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) {
|
||||||
module->avail_parameters(RTLIL::escape_id(param_name));
|
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;
|
SetIter si;
|
||||||
|
@ -2004,7 +2144,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
const char *param_value ;
|
const char *param_value ;
|
||||||
if (is_blackbox(inst->View())) {
|
if (is_blackbox(inst->View())) {
|
||||||
FOREACH_PARAMETER_OF_INST(inst, mi2, param_name, param_value) {
|
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;
|
int port_offset = 0;
|
||||||
if (pr->GetPort()->Bus()) {
|
if (pr->GetPort()->Bus()) {
|
||||||
port_name = pr->GetPort()->Bus()->Name();
|
port_name = pr->GetPort()->Bus()->Name();
|
||||||
port_offset = pr->GetPort()->Bus()->IndexOf(pr->GetPort()) -
|
int msb_index = pr->GetPort()->Bus()->LeftIndex();
|
||||||
min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());
|
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);
|
IdString port_name_id = RTLIL::escape_id(port_name);
|
||||||
auto &sigvec = cell_port_conns[port_name_id];
|
auto &sigvec = cell_port_conns[port_name_id];
|
||||||
|
@ -2699,7 +2848,7 @@ struct VerificPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
#ifdef VERIFIC_VHDL_SUPPORT
|
#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("\n");
|
||||||
log("Load the specified VHDL files into Verific.\n");
|
log("Load the specified VHDL files into Verific.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -3436,6 +3585,29 @@ struct VerificPass : public Pass {
|
||||||
goto check_error;
|
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")) {
|
if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) {
|
||||||
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
|
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
|
||||||
bool flag_lib = false;
|
bool flag_lib = false;
|
||||||
|
@ -3979,7 +4151,7 @@ struct ReadPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
#ifdef VERIFIC_VHDL_SUPPORT
|
#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("\n");
|
||||||
log("Load the specified VHDL files. (Requires Verific.)\n");
|
log("Load the specified VHDL files. (Requires Verific.)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -4083,7 +4255,7 @@ struct ReadPass : public Pass {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VERIFIC_VHDL_SUPPORT
|
#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) {
|
if (use_verific) {
|
||||||
args[0] = "verific";
|
args[0] = "verific";
|
||||||
Pass::call(design, args);
|
Pass::call(design, args);
|
||||||
|
|
|
@ -270,8 +270,11 @@ struct VerilogFrontend : public Frontend {
|
||||||
frontend_verilog_yydebug = false;
|
frontend_verilog_yydebug = false;
|
||||||
sv_mode = false;
|
sv_mode = false;
|
||||||
formal_mode = false;
|
formal_mode = false;
|
||||||
|
noassert_mode = false;
|
||||||
|
noassume_mode = false;
|
||||||
norestrict_mode = false;
|
norestrict_mode = false;
|
||||||
assume_asserts_mode = false;
|
assume_asserts_mode = false;
|
||||||
|
assert_assumes_mode = false;
|
||||||
lib_mode = false;
|
lib_mode = false;
|
||||||
specify_mode = false;
|
specify_mode = false;
|
||||||
default_nettype_wire = true;
|
default_nettype_wire = true;
|
||||||
|
|
|
@ -19,7 +19,7 @@ Formatting of code
|
||||||
blank lines.
|
blank lines.
|
||||||
|
|
||||||
- Otherwise stick to the Linux Kernel Coding Style:
|
- 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
|
C++ Language
|
||||||
|
|
|
@ -222,6 +222,8 @@ X(_TECHMAP_REPLACE_)
|
||||||
X(techmap_simplemap)
|
X(techmap_simplemap)
|
||||||
X(_techmap_special_)
|
X(_techmap_special_)
|
||||||
X(techmap_wrap)
|
X(techmap_wrap)
|
||||||
|
X(_TECHMAP_PLACEHOLDER_)
|
||||||
|
X(techmap_chtype)
|
||||||
X(T_FALL_MAX)
|
X(T_FALL_MAX)
|
||||||
X(T_FALL_MIN)
|
X(T_FALL_MIN)
|
||||||
X(T_FALL_TYP)
|
X(T_FALL_TYP)
|
||||||
|
|
|
@ -356,7 +356,7 @@ int main(int argc, char **argv)
|
||||||
printf(" -V\n");
|
printf(" -V\n");
|
||||||
printf(" print version information and exit\n");
|
printf(" print version information and exit\n");
|
||||||
printf("\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("script for transforming the Verilog input to a gate-level netlist. For example:\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" yosys -o output.blif -S input.v\n");
|
printf(" yosys -o output.blif -S input.v\n");
|
||||||
|
|
302
kernel/fmt.cc
302
kernel/fmt.cc
|
@ -22,9 +22,9 @@
|
||||||
|
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
|
|
||||||
void Fmt::append_string(const std::string &str) {
|
void Fmt::append_literal(const std::string &str) {
|
||||||
FmtPart part = {};
|
FmtPart part = {};
|
||||||
part.type = FmtPart::STRING;
|
part.type = FmtPart::LITERAL;
|
||||||
part.str = str;
|
part.str = str;
|
||||||
parts.push_back(part);
|
parts.push_back(part);
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,11 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
||||||
} else if (fmt.substr(i, 2) == "{{") {
|
} else if (fmt.substr(i, 2) == "{{") {
|
||||||
part.str += '{';
|
part.str += '{';
|
||||||
++i;
|
++i;
|
||||||
} else if (fmt[i] == '}')
|
} else if (fmt[i] == '}') {
|
||||||
log_assert(false && "Unexpected '}' in format string");
|
log_assert(false && "Unexpected '}' in format string");
|
||||||
else if (fmt[i] == '{') {
|
} else if (fmt[i] == '{') {
|
||||||
if (!part.str.empty()) {
|
if (!part.str.empty()) {
|
||||||
part.type = FmtPart::STRING;
|
part.type = FmtPart::LITERAL;
|
||||||
parts.push_back(part);
|
parts.push_back(part);
|
||||||
part = {};
|
part = {};
|
||||||
}
|
}
|
||||||
|
@ -74,19 +74,24 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
||||||
part.sig = args.extract(0, arg_size);
|
part.sig = args.extract(0, arg_size);
|
||||||
args.remove(0, arg_size);
|
args.remove(0, arg_size);
|
||||||
|
|
||||||
|
if (fmt[i] == 'U') {
|
||||||
|
part.type = FmtPart::UNICHAR;
|
||||||
|
++i;
|
||||||
|
goto success;
|
||||||
|
}
|
||||||
|
|
||||||
if (fmt[i] == '>')
|
if (fmt[i] == '>')
|
||||||
part.justify = FmtPart::RIGHT;
|
part.justify = FmtPart::RIGHT;
|
||||||
else if (fmt[i] == '<')
|
else if (fmt[i] == '<')
|
||||||
part.justify = FmtPart::LEFT;
|
part.justify = FmtPart::LEFT;
|
||||||
|
else if (fmt[i] == '=')
|
||||||
|
part.justify = FmtPart::NUMERIC;
|
||||||
else
|
else
|
||||||
log_assert(false && "Unexpected justification in format substitution");
|
log_assert(false && "Unexpected justification in format substitution");
|
||||||
if (++i == fmt.size())
|
if (++i == fmt.size())
|
||||||
log_assert(false && "Unexpected end in format substitution");
|
log_assert(false && "Unexpected end in format substitution");
|
||||||
|
|
||||||
if (fmt[i] == '0' || fmt[i] == ' ')
|
|
||||||
part.padding = fmt[i];
|
part.padding = fmt[i];
|
||||||
else
|
|
||||||
log_assert(false && "Unexpected padding in format substitution");
|
|
||||||
if (++i == fmt.size())
|
if (++i == fmt.size())
|
||||||
log_assert(false && "Unexpected end in format substitution");
|
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') {
|
} else if (fmt[i] == 'h') {
|
||||||
part.type = FmtPart::INTEGER;
|
part.type = FmtPart::INTEGER;
|
||||||
part.base = 16;
|
part.base = 16;
|
||||||
|
} else if (fmt[i] == 'H') {
|
||||||
|
part.type = FmtPart::INTEGER;
|
||||||
|
part.base = 16;
|
||||||
|
part.hex_upper = true;
|
||||||
} else if (fmt[i] == 'c') {
|
} else if (fmt[i] == 'c') {
|
||||||
part.type = FmtPart::CHARACTER;
|
part.type = FmtPart::STRING;
|
||||||
} else if (fmt[i] == 't') {
|
} else if (fmt[i] == 't') {
|
||||||
part.type = FmtPart::VLOG_TIME;
|
part.type = FmtPart::VLOG_TIME;
|
||||||
} else if (fmt[i] == 'r') {
|
} 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");
|
log_assert(false && "Unexpected end in format substitution");
|
||||||
|
|
||||||
if (part.type == FmtPart::INTEGER) {
|
if (part.type == FmtPart::INTEGER) {
|
||||||
if (fmt[i] == '+') {
|
if (fmt[i] == '-') {
|
||||||
part.plus = true;
|
part.sign = FmtPart::MINUS;
|
||||||
if (++i == fmt.size())
|
if (++i == fmt.size())
|
||||||
log_assert(false && "Unexpected end in format substitution");
|
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')
|
if (fmt[i] == 'u')
|
||||||
|
@ -140,6 +168,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
||||||
log_assert(false && "Unexpected end in format substitution");
|
log_assert(false && "Unexpected end in format substitution");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
success:
|
||||||
if (fmt[i] != '}')
|
if (fmt[i] != '}')
|
||||||
log_assert(false && "Expected '}' after format substitution");
|
log_assert(false && "Expected '}' after format substitution");
|
||||||
|
|
||||||
|
@ -150,7 +179,7 @@ void Fmt::parse_rtlil(const RTLIL::Cell *cell) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!part.str.empty()) {
|
if (!part.str.empty()) {
|
||||||
part.type = FmtPart::STRING;
|
part.type = FmtPart::LITERAL;
|
||||||
parts.push_back(part);
|
parts.push_back(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +190,7 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
||||||
|
|
||||||
for (auto &part : parts) {
|
for (auto &part : parts) {
|
||||||
switch (part.type) {
|
switch (part.type) {
|
||||||
case FmtPart::STRING:
|
case FmtPart::LITERAL:
|
||||||
for (char c : part.str) {
|
for (char c : part.str) {
|
||||||
if (c == '{')
|
if (c == '{')
|
||||||
fmt += "{{";
|
fmt += "{{";
|
||||||
|
@ -172,10 +201,15 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FmtPart::UNICHAR:
|
||||||
|
log_assert(part.sig.size() <= 32);
|
||||||
|
fmt += "{U}";
|
||||||
|
break;
|
||||||
|
|
||||||
case FmtPart::VLOG_TIME:
|
case FmtPart::VLOG_TIME:
|
||||||
log_assert(part.sig.size() == 0);
|
log_assert(part.sig.size() == 0);
|
||||||
YS_FALLTHROUGH
|
YS_FALLTHROUGH
|
||||||
case FmtPart::CHARACTER:
|
case FmtPart::STRING:
|
||||||
log_assert(part.sig.size() % 8 == 0);
|
log_assert(part.sig.size() % 8 == 0);
|
||||||
YS_FALLTHROUGH
|
YS_FALLTHROUGH
|
||||||
case FmtPart::INTEGER:
|
case FmtPart::INTEGER:
|
||||||
|
@ -187,6 +221,8 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
||||||
fmt += '>';
|
fmt += '>';
|
||||||
else if (part.justify == FmtPart::LEFT)
|
else if (part.justify == FmtPart::LEFT)
|
||||||
fmt += '<';
|
fmt += '<';
|
||||||
|
else if (part.justify == FmtPart::NUMERIC)
|
||||||
|
fmt += '=';
|
||||||
else log_abort();
|
else log_abort();
|
||||||
log_assert(part.width == 0 || part.padding != '\0');
|
log_assert(part.width == 0 || part.padding != '\0');
|
||||||
fmt += part.padding != '\0' ? part.padding : ' ';
|
fmt += part.padding != '\0' ? part.padding : ' ';
|
||||||
|
@ -197,13 +233,18 @@ void Fmt::emit_rtlil(RTLIL::Cell *cell) const {
|
||||||
case 2: fmt += 'b'; break;
|
case 2: fmt += 'b'; break;
|
||||||
case 8: fmt += 'o'; break;
|
case 8: fmt += 'o'; break;
|
||||||
case 10: fmt += 'd'; break;
|
case 10: fmt += 'd'; break;
|
||||||
case 16: fmt += 'h'; break;
|
case 16: fmt += part.hex_upper ? 'H' : 'h'; break;
|
||||||
default: log_abort();
|
default: log_abort();
|
||||||
}
|
}
|
||||||
if (part.plus)
|
switch (part.sign) {
|
||||||
fmt += '+';
|
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';
|
fmt += part.signed_ ? 's' : 'u';
|
||||||
} else if (part.type == FmtPart::CHARACTER) {
|
} else if (part.type == FmtPart::STRING) {
|
||||||
fmt += 'c';
|
fmt += 'c';
|
||||||
} else if (part.type == FmtPart::VLOG_TIME) {
|
} else if (part.type == FmtPart::VLOG_TIME) {
|
||||||
if (part.realtime)
|
if (part.realtime)
|
||||||
|
@ -299,12 +340,12 @@ void Fmt::apply_verilog_automatic_sizing_and_add(FmtPart &part)
|
||||||
part.width = places;
|
part.width = places;
|
||||||
|
|
||||||
if (part.justify == FmtPart::RIGHT) {
|
if (part.justify == FmtPart::RIGHT) {
|
||||||
append_string(gap);
|
append_literal(gap);
|
||||||
parts.push_back(part);
|
parts.push_back(part);
|
||||||
} else {
|
} else {
|
||||||
part.justify = FmtPart::RIGHT;
|
part.justify = FmtPart::RIGHT;
|
||||||
parts.push_back(part);
|
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();
|
part.str += module_name.str();
|
||||||
} else {
|
} else {
|
||||||
if (!part.str.empty()) {
|
if (!part.str.empty()) {
|
||||||
part.type = FmtPart::STRING;
|
part.type = FmtPart::LITERAL;
|
||||||
parts.push_back(part);
|
parts.push_back(part);
|
||||||
part = {};
|
part = {};
|
||||||
}
|
}
|
||||||
|
@ -375,7 +416,7 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
||||||
part.justify = FmtPart::LEFT;
|
part.justify = FmtPart::LEFT;
|
||||||
} else if (fmt[i] == '+') {
|
} else if (fmt[i] == '+') {
|
||||||
// always show sign; not in IEEE 1800-2017 or verilator but iverilog has it
|
// always show sign; not in IEEE 1800-2017 or verilator but iverilog has it
|
||||||
part.plus = true;
|
part.sign = FmtPart::PLUS_MINUS;
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
if (i == fmt.size()) {
|
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.type = FmtPart::INTEGER;
|
||||||
part.base = 16;
|
part.base = 16;
|
||||||
} else if (fmt[i] == 'c' || fmt[i] == 'C') {
|
} else if (fmt[i] == 'c' || fmt[i] == 'C') {
|
||||||
part.type = FmtPart::CHARACTER;
|
part.type = FmtPart::STRING;
|
||||||
part.sig.extend_u0(8);
|
part.sig.extend_u0(8);
|
||||||
// %10c and %010c not fully defined in IEEE 1800-2017 and do different things in iverilog
|
// %10c and %010c not fully defined in IEEE 1800-2017 and do different things in iverilog
|
||||||
} else if (fmt[i] == 's' || fmt[i] == 'S') {
|
} else if (fmt[i] == 's' || fmt[i] == 'S') {
|
||||||
part.type = FmtPart::CHARACTER;
|
part.type = FmtPart::STRING;
|
||||||
if ((part.sig.size() % 8) != 0)
|
if ((part.sig.size() % 8) != 0)
|
||||||
part.sig.extend_u0((part.sig.size() + 7) / 8 * 8);
|
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
|
// %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);
|
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')
|
if (part.padding == '\0') {
|
||||||
part.padding = (has_leading_zero && part.justify == FmtPart::RIGHT) ? '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);
|
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)
|
if (part.type == FmtPart::INTEGER && !has_leading_zero)
|
||||||
apply_verilog_automatic_sizing_and_add(part);
|
apply_verilog_automatic_sizing_and_add(part);
|
||||||
else
|
else
|
||||||
|
@ -449,12 +498,12 @@ void Fmt::parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_lik
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!part.str.empty()) {
|
if (!part.str.empty()) {
|
||||||
part.type = FmtPart::STRING;
|
part.type = FmtPart::LITERAL;
|
||||||
parts.push_back(part);
|
parts.push_back(part);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FmtPart part = {};
|
FmtPart part = {};
|
||||||
part.type = FmtPart::STRING;
|
part.type = FmtPart::LITERAL;
|
||||||
part.str = arg->str;
|
part.str = arg->str;
|
||||||
parts.push_back(part);
|
parts.push_back(part);
|
||||||
}
|
}
|
||||||
|
@ -474,7 +523,7 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
||||||
|
|
||||||
for (auto &part : parts) {
|
for (auto &part : parts) {
|
||||||
switch (part.type) {
|
switch (part.type) {
|
||||||
case FmtPart::STRING:
|
case FmtPart::LITERAL:
|
||||||
for (char c : part.str) {
|
for (char c : part.str) {
|
||||||
if (c == '%')
|
if (c == '%')
|
||||||
fmt.str += "%%";
|
fmt.str += "%%";
|
||||||
|
@ -491,14 +540,13 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
||||||
args.push_back(arg);
|
args.push_back(arg);
|
||||||
|
|
||||||
fmt.str += '%';
|
fmt.str += '%';
|
||||||
if (part.plus)
|
if (part.sign == FmtPart::PLUS_MINUS || part.sign == FmtPart::SPACE_MINUS)
|
||||||
fmt.str += '+';
|
fmt.str += '+'; // treat space/minus as plus/minus
|
||||||
if (part.justify == FmtPart::LEFT)
|
if (part.justify == FmtPart::LEFT)
|
||||||
fmt.str += '-';
|
fmt.str += '-';
|
||||||
if (part.width == 0) {
|
if (part.width == 0) {
|
||||||
fmt.str += '0';
|
fmt.str += '0';
|
||||||
} else if (part.width > 0) {
|
} else if (part.width > 0) {
|
||||||
log_assert(part.padding == ' ' || part.padding == '0');
|
|
||||||
if (part.base != 10 || part.padding == '0')
|
if (part.base != 10 || part.padding == '0')
|
||||||
fmt.str += '0';
|
fmt.str += '0';
|
||||||
fmt.str += std::to_string(part.width);
|
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 2: fmt.str += 'b'; break;
|
||||||
case 8: fmt.str += 'o'; break;
|
case 8: fmt.str += 'o'; break;
|
||||||
case 10: fmt.str += 'd'; 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();
|
default: log_abort();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FmtPart::CHARACTER: {
|
case FmtPart::STRING: {
|
||||||
VerilogFmtArg arg;
|
VerilogFmtArg arg;
|
||||||
arg.type = VerilogFmtArg::INTEGER;
|
arg.type = VerilogFmtArg::INTEGER;
|
||||||
arg.sig = part.sig;
|
arg.sig = part.sig;
|
||||||
|
@ -524,7 +572,6 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
||||||
fmt.str += '-';
|
fmt.str += '-';
|
||||||
if (part.sig.size() == 8) {
|
if (part.sig.size() == 8) {
|
||||||
if (part.width > 0) {
|
if (part.width > 0) {
|
||||||
log_assert(part.padding == '0' || part.padding == ' ');
|
|
||||||
if (part.padding == '0')
|
if (part.padding == '0')
|
||||||
fmt.str += part.padding;
|
fmt.str += part.padding;
|
||||||
fmt.str += std::to_string(part.width);
|
fmt.str += std::to_string(part.width);
|
||||||
|
@ -533,7 +580,6 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
||||||
} else {
|
} else {
|
||||||
log_assert(part.sig.size() % 8 == 0);
|
log_assert(part.sig.size() % 8 == 0);
|
||||||
if (part.width > 0) {
|
if (part.width > 0) {
|
||||||
log_assert(part.padding == ' '); // no zero padding
|
|
||||||
fmt.str += std::to_string(part.width);
|
fmt.str += std::to_string(part.width);
|
||||||
}
|
}
|
||||||
fmt.str += 's';
|
fmt.str += 's';
|
||||||
|
@ -541,6 +587,16 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
||||||
break;
|
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: {
|
case FmtPart::VLOG_TIME: {
|
||||||
VerilogFmtArg arg;
|
VerilogFmtArg arg;
|
||||||
arg.type = VerilogFmtArg::TIME;
|
arg.type = VerilogFmtArg::TIME;
|
||||||
|
@ -549,11 +605,11 @@ std::vector<VerilogFmtArg> Fmt::emit_verilog() const
|
||||||
args.push_back(arg);
|
args.push_back(arg);
|
||||||
|
|
||||||
fmt.str += '%';
|
fmt.str += '%';
|
||||||
if (part.plus)
|
log_assert(part.sign == FmtPart::MINUS || part.sign == FmtPart::PLUS_MINUS);
|
||||||
|
if (part.sign == FmtPart::PLUS_MINUS)
|
||||||
fmt.str += '+';
|
fmt.str += '+';
|
||||||
if (part.justify == FmtPart::LEFT)
|
if (part.justify == FmtPart::LEFT)
|
||||||
fmt.str += '-';
|
fmt.str += '-';
|
||||||
log_assert(part.padding == ' ' || part.padding == '0');
|
|
||||||
if (part.padding == '0' && part.width > 0)
|
if (part.padding == '0' && part.width > 0)
|
||||||
fmt.str += '0';
|
fmt.str += '0';
|
||||||
fmt.str += std::to_string(part.width);
|
fmt.str += std::to_string(part.width);
|
||||||
|
@ -599,9 +655,10 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(c
|
||||||
os << indent << "buf += fmt_part { ";
|
os << indent << "buf += fmt_part { ";
|
||||||
os << "fmt_part::";
|
os << "fmt_part::";
|
||||||
switch (part.type) {
|
switch (part.type) {
|
||||||
case FmtPart::STRING: os << "STRING"; break;
|
case FmtPart::LITERAL: os << "LITERAL"; break;
|
||||||
case FmtPart::INTEGER: os << "INTEGER"; 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;
|
case FmtPart::VLOG_TIME: os << "VLOG_TIME"; break;
|
||||||
}
|
}
|
||||||
os << ", ";
|
os << ", ";
|
||||||
|
@ -610,13 +667,23 @@ void Fmt::emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(c
|
||||||
switch (part.justify) {
|
switch (part.justify) {
|
||||||
case FmtPart::LEFT: os << "LEFT"; break;
|
case FmtPart::LEFT: os << "LEFT"; break;
|
||||||
case FmtPart::RIGHT: os << "RIGHT"; break;
|
case FmtPart::RIGHT: os << "RIGHT"; break;
|
||||||
|
case FmtPart::NUMERIC: os << "NUMERIC"; break;
|
||||||
}
|
}
|
||||||
os << ", ";
|
os << ", ";
|
||||||
os << "(char)" << (int)part.padding << ", ";
|
os << "(char)" << (int)part.padding << ", ";
|
||||||
os << part.width << ", ";
|
os << part.width << ", ";
|
||||||
os << part.base << ", ";
|
os << part.base << ", ";
|
||||||
os << part.signed_ << ", ";
|
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 << part.realtime;
|
||||||
os << " }.render(";
|
os << " }.render(";
|
||||||
emit_sig(part.sig);
|
emit_sig(part.sig);
|
||||||
|
@ -631,19 +698,62 @@ std::string Fmt::render() const
|
||||||
|
|
||||||
for (auto &part : parts) {
|
for (auto &part : parts) {
|
||||||
switch (part.type) {
|
switch (part.type) {
|
||||||
case FmtPart::STRING:
|
case FmtPart::LITERAL:
|
||||||
str += part.str;
|
str += part.str;
|
||||||
break;
|
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::INTEGER:
|
||||||
case FmtPart::CHARACTER:
|
case FmtPart::STRING:
|
||||||
case FmtPart::VLOG_TIME: {
|
case FmtPart::VLOG_TIME: {
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
std::string prefix;
|
||||||
if (part.type == FmtPart::INTEGER) {
|
if (part.type == FmtPart::INTEGER) {
|
||||||
RTLIL::Const value = part.sig.as_const();
|
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) {
|
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++)
|
for (size_t index = 0; index < (size_t)value.size(); index++)
|
||||||
if (value[index] != State::S0)
|
if (value[index] != State::S0)
|
||||||
minimum_size = index + 1;
|
minimum_size = index + 1;
|
||||||
|
@ -651,10 +761,28 @@ std::string Fmt::render() const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part.base == 2) {
|
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) {
|
} 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;
|
size_t step = (part.base == 16) ? 4 : 3;
|
||||||
for (size_t index = 0; index < (size_t)value.size(); index += step) {
|
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));
|
RTLIL::Const subvalue = value.extract(index, min(step, value.size() - index));
|
||||||
bool has_x = false, all_x = true, has_z = false, all_z = true;
|
bool has_x = false, all_x = true, has_z = false, all_z = true;
|
||||||
for (State bit : subvalue) {
|
for (State bit : subvalue) {
|
||||||
|
@ -676,21 +804,11 @@ std::string Fmt::render() const
|
||||||
else if (has_z)
|
else if (has_z)
|
||||||
buf += 'Z';
|
buf += 'Z';
|
||||||
else
|
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) {
|
} else if (part.base == 10) {
|
||||||
bool has_x = false, all_x = true, has_z = false, all_z = true;
|
if (part.show_base)
|
||||||
for (State bit : value) {
|
prefix += "0d";
|
||||||
if (bit == State::Sx)
|
|
||||||
has_x = true;
|
|
||||||
else
|
|
||||||
all_x = false;
|
|
||||||
if (bit == State::Sz)
|
|
||||||
has_z = true;
|
|
||||||
else
|
|
||||||
all_z = false;
|
|
||||||
}
|
|
||||||
if (all_x)
|
if (all_x)
|
||||||
buf += 'x';
|
buf += 'x';
|
||||||
else if (all_z)
|
else if (all_z)
|
||||||
|
@ -700,25 +818,29 @@ std::string Fmt::render() const
|
||||||
else if (has_z)
|
else if (has_z)
|
||||||
buf += 'Z';
|
buf += 'Z';
|
||||||
else {
|
else {
|
||||||
bool negative = part.signed_ && value[value.size() - 1];
|
log_assert(value.is_fully_def());
|
||||||
RTLIL::Const absvalue;
|
if (value.is_fully_zero())
|
||||||
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())
|
|
||||||
buf += '0';
|
buf += '0';
|
||||||
while (!absvalue.is_fully_zero()) {
|
size_t index = 0;
|
||||||
buf += '0' + RTLIL::const_mod(absvalue, 10, false, false, 4).as_int();
|
while (!value.is_fully_zero()) {
|
||||||
absvalue = RTLIL::const_div(absvalue, 10, false, false, absvalue.size());
|
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 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();
|
buf = part.sig.as_const().decode_string();
|
||||||
} else if (part.type == FmtPart::VLOG_TIME) {
|
} else if (part.type == FmtPart::VLOG_TIME) {
|
||||||
// We only render() during initial, so time is always zero.
|
// 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');
|
log_assert(part.width == 0 || part.padding != '\0');
|
||||||
if (part.justify == FmtPart::RIGHT && buf.size() < part.width) {
|
if (prefix.size() + buf.size() < part.width) {
|
||||||
size_t pad_width = part.width - buf.size();
|
size_t pad_width = part.width - prefix.size() - buf.size();
|
||||||
if (part.padding == '0' && (!buf.empty() && (buf.front() == '+' || buf.front() == '-'))) {
|
switch (part.justify) {
|
||||||
str += buf.front();
|
case FmtPart::LEFT:
|
||||||
buf.erase(0, 1);
|
str += prefix;
|
||||||
}
|
|
||||||
str += std::string(pad_width, part.padding);
|
|
||||||
}
|
|
||||||
str += buf;
|
str += buf;
|
||||||
if (part.justify == FmtPart::LEFT && buf.size() < part.width)
|
str += std::string(pad_width, part.padding);
|
||||||
str += std::string(part.width - buf.size(), 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;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
str += prefix;
|
||||||
|
str += buf;
|
||||||
|
}
|
||||||
break;
|
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!
|
// Must be kept in sync with `struct fmt_part` in backends/cxxrtl/runtime/cxxrtl/cxxrtl.h!
|
||||||
struct FmtPart {
|
struct FmtPart {
|
||||||
enum {
|
enum {
|
||||||
STRING = 0,
|
LITERAL = 0,
|
||||||
INTEGER = 1,
|
INTEGER = 1,
|
||||||
CHARACTER = 2,
|
STRING = 2,
|
||||||
VLOG_TIME = 3,
|
UNICHAR = 3,
|
||||||
|
VLOG_TIME = 4,
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
// STRING type
|
// LITERAL type
|
||||||
std::string str;
|
std::string str;
|
||||||
|
|
||||||
// INTEGER/CHARACTER types
|
// INTEGER/STRING/UNICHAR types
|
||||||
RTLIL::SigSpec sig;
|
RTLIL::SigSpec sig;
|
||||||
|
|
||||||
// INTEGER/CHARACTER/VLOG_TIME types
|
// INTEGER/STRING/VLOG_TIME types
|
||||||
enum {
|
enum {
|
||||||
RIGHT = 0,
|
RIGHT = 0,
|
||||||
LEFT = 1,
|
LEFT = 1,
|
||||||
|
NUMERIC = 2,
|
||||||
} justify = RIGHT;
|
} justify = RIGHT;
|
||||||
char padding = '\0';
|
char padding = '\0';
|
||||||
size_t width = 0;
|
size_t width = 0;
|
||||||
|
@ -76,7 +78,14 @@ struct FmtPart {
|
||||||
// INTEGER type
|
// INTEGER type
|
||||||
unsigned base = 10;
|
unsigned base = 10;
|
||||||
bool signed_ = false;
|
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
|
// VLOG_TIME type
|
||||||
bool realtime = false;
|
bool realtime = false;
|
||||||
|
@ -86,7 +95,7 @@ struct Fmt {
|
||||||
public:
|
public:
|
||||||
std::vector<FmtPart> parts;
|
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 parse_rtlil(const RTLIL::Cell *cell);
|
||||||
void emit_rtlil(RTLIL::Cell *cell) const;
|
void emit_rtlil(RTLIL::Cell *cell) const;
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kernel/yosys.h"
|
|
||||||
|
|
||||||
#ifndef LOG_H
|
#ifndef LOG_H
|
||||||
#define LOG_H
|
#define LOG_H
|
||||||
|
|
||||||
|
#include "kernel/yosys_common.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
@ -449,4 +449,6 @@ void log_dump_args_worker(const char *p, T first, Args ... args)
|
||||||
|
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,11 +17,12 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kernel/yosys.h"
|
|
||||||
|
|
||||||
#ifndef REGISTER_H
|
#ifndef REGISTER_H
|
||||||
#define REGISTER_H
|
#define REGISTER_H
|
||||||
|
|
||||||
|
#include "kernel/yosys_common.h"
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
|
||||||
YOSYS_NAMESPACE_BEGIN
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct Pass
|
struct Pass
|
||||||
|
|
|
@ -4435,9 +4435,36 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
|
||||||
log_assert(offset >= 0);
|
log_assert(offset >= 0);
|
||||||
log_assert(length >= 0);
|
log_assert(length >= 0);
|
||||||
log_assert(offset + length <= width_);
|
log_assert(offset + length <= width_);
|
||||||
unpack();
|
|
||||||
cover("kernel.rtlil.sigspec.extract_pos");
|
cover("kernel.rtlil.sigspec.extract_pos");
|
||||||
|
|
||||||
|
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);
|
return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
|
void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
|
||||||
|
|
|
@ -17,11 +17,12 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kernel/yosys.h"
|
|
||||||
|
|
||||||
#ifndef RTLIL_H
|
#ifndef RTLIL_H
|
||||||
#define RTLIL_H
|
#define RTLIL_H
|
||||||
|
|
||||||
|
#include "kernel/yosys_common.h"
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
|
||||||
YOSYS_NAMESPACE_BEGIN
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
namespace RTLIL
|
namespace RTLIL
|
||||||
|
|
346
kernel/yosys.h
346
kernel/yosys.h
|
@ -39,323 +39,7 @@
|
||||||
#ifndef YOSYS_H
|
#ifndef YOSYS_H
|
||||||
#define YOSYS_H
|
#define YOSYS_H
|
||||||
|
|
||||||
#include <map>
|
#include "kernel/yosys_common.h"
|
||||||
#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/log.h"
|
#include "kernel/log.h"
|
||||||
#include "kernel/rtlil.h"
|
#include "kernel/rtlil.h"
|
||||||
|
@ -363,14 +47,6 @@ YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
YOSYS_NAMESPACE_BEGIN
|
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();
|
void yosys_setup();
|
||||||
|
|
||||||
#ifdef WITH_PYTHON
|
#ifdef WITH_PYTHON
|
||||||
|
@ -385,26 +61,6 @@ Tcl_Interp *yosys_get_tcl_interp();
|
||||||
|
|
||||||
extern RTLIL::Design *yosys_design;
|
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();
|
RTLIL::Design *yosys_get_design();
|
||||||
std::string proc_self_dirname();
|
std::string proc_self_dirname();
|
||||||
std::string proc_share_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---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" log string\n");
|
log(" log [options] string\n");
|
||||||
|
log(" log [ -push | -pop ]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Print the given string to the screen and/or the log file. This is useful for TCL\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");
|
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(" -n\n");
|
||||||
log(" do not append a newline\n");
|
log(" do not append a newline\n");
|
||||||
log("\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;
|
size_t argidx;
|
||||||
bool to_stdout = false;
|
bool to_stdout = false;
|
||||||
bool to_stderr = false;
|
bool to_stderr = false;
|
||||||
bool to_log = true;
|
bool to_log = true;
|
||||||
bool newline = true;
|
bool newline = true;
|
||||||
|
bool header = false;
|
||||||
|
bool push = false;
|
||||||
|
bool pop = false;
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
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] == "-stderr") to_stderr = true;
|
||||||
else if (args[argidx] == "-nolog") to_log = false;
|
else if (args[argidx] == "-nolog") to_log = false;
|
||||||
else if (args[argidx] == "-n") newline = 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;
|
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++)
|
for (; argidx < args.size(); argidx++)
|
||||||
text += args[argidx] + ' ';
|
text += args[argidx] + ' ';
|
||||||
if (!text.empty()) text.resize(text.size()-1);
|
if (!text.empty()) text.resize(text.size()-1);
|
||||||
|
|
||||||
if (to_stdout) fprintf(stdout, (newline ? "%s\n" : "%s"), text.c_str());
|
const char *fmtline = newline ? "%s\n" : "%s";
|
||||||
if (to_stderr) fprintf(stderr, (newline ? "%s\n" : "%s"), text.c_str());
|
|
||||||
if (to_log) log ( (newline ? "%s\n" : "%s"), text.c_str());
|
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;
|
} LogPass;
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,8 @@ struct cell_area_t {
|
||||||
struct statdata_t
|
struct statdata_t
|
||||||
{
|
{
|
||||||
#define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
|
#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)
|
#define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
|
||||||
|
|
||||||
|
@ -90,6 +91,11 @@ struct statdata_t
|
||||||
|
|
||||||
for (auto wire : mod->selected_wires())
|
for (auto wire : mod->selected_wires())
|
||||||
{
|
{
|
||||||
|
if (wire->port_input || wire->port_output) {
|
||||||
|
num_ports++;
|
||||||
|
num_port_bits += wire->width;
|
||||||
|
}
|
||||||
|
|
||||||
if (wire->name.isPublic()) {
|
if (wire->name.isPublic()) {
|
||||||
num_pub_wires++;
|
num_pub_wires++;
|
||||||
num_pub_wire_bits += wire->width;
|
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 wire bits: %6u\n", num_wire_bits);
|
||||||
log(" Number of public wires: %6u\n", num_pub_wires);
|
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 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 memories: %6u\n", num_memories);
|
||||||
log(" Number of memory bits: %6u\n", num_memory_bits);
|
log(" Number of memory bits: %6u\n", num_memory_bits);
|
||||||
log(" Number of processes: %6u\n", num_processes);
|
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_wire_bits\": %u,\n", num_wire_bits);
|
||||||
log(" \"num_pub_wires\": %u,\n", num_pub_wires);
|
log(" \"num_pub_wires\": %u,\n", num_pub_wires);
|
||||||
log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits);
|
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_memories\": %u,\n", num_memories);
|
||||||
log(" \"num_memory_bits\": %u,\n", num_memory_bits);
|
log(" \"num_memory_bits\": %u,\n", num_memory_bits);
|
||||||
log(" \"num_processes\": %u,\n", num_processes);
|
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_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_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_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_memories", data.num_memories);
|
||||||
design->scratchpad_set_int("stat.num_memory_bits", data.num_memory_bits);
|
design->scratchpad_set_int("stat.num_memory_bits", data.num_memory_bits);
|
||||||
design->scratchpad_set_int("stat.num_processes", data.num_processes);
|
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)
|
if (design->module(cell->type) != nullptr)
|
||||||
continue;
|
continue;
|
||||||
if (cell->type.begins_with("$__"))
|
if (cell->type.begins_with("$") && !cell->type.begins_with("$__"))
|
||||||
continue;
|
continue;
|
||||||
for (auto &pattern : celltypes)
|
for (auto &pattern : celltypes)
|
||||||
if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))
|
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(" to any of the values.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -iattr\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("\n");
|
||||||
log(" -rom-only\n");
|
log(" -rom-only\n");
|
||||||
log(" only perform conversion for ROMs (memories with no write ports).\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)) {
|
if (!raw_used_signals.check_any(s1)) {
|
||||||
// delete wires that aren't used by anything directly
|
// delete wires that aren't used by anything directly
|
||||||
goto delete_this_wire;
|
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)
|
if (0)
|
||||||
|
|
|
@ -183,7 +183,7 @@ struct OptDemorganPass : public Pass {
|
||||||
{
|
{
|
||||||
log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n");
|
log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n");
|
||||||
|
|
||||||
int argidx = 0;
|
int argidx = 1;
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
unsigned int cells_changed = 0;
|
unsigned int cells_changed = 0;
|
||||||
|
|
|
@ -289,7 +289,7 @@ struct Ice40DspPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Pack input registers (A, B, {C,D}; with optional hold), pipeline registers\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("({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("\n");
|
||||||
log("Multiply-accumulate operations using the post-adder with feedback on the {C,D}\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");
|
log("input will be folded into the DSP. In this scenario only, resetting the\n");
|
||||||
|
|
|
@ -237,7 +237,7 @@ struct InitValWorker
|
||||||
return true;
|
return true;
|
||||||
if (ff.has_ce && initconst(ff.sig_ce.as_bit()) == (ff.pol_ce ? State::S0 : State::S1))
|
if (ff.has_ce && initconst(ff.sig_ce.as_bit()) == (ff.pol_ce ? State::S0 : State::S1))
|
||||||
continue;
|
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;
|
continue;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -48,6 +48,7 @@ OBJS += passes/techmap/dfflegalize.o
|
||||||
OBJS += passes/techmap/dffunmap.o
|
OBJS += passes/techmap/dffunmap.o
|
||||||
OBJS += passes/techmap/flowmap.o
|
OBJS += passes/techmap/flowmap.o
|
||||||
OBJS += passes/techmap/extractinv.o
|
OBJS += passes/techmap/extractinv.o
|
||||||
|
OBJS += passes/techmap/cellmatch.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(DISABLE_SPAWN),0)
|
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) {
|
for (std::string dont_use_cell : dont_use_cells) {
|
||||||
dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str());
|
dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str());
|
||||||
}
|
}
|
||||||
|
bool first_lib = true;
|
||||||
for (std::string liberty_file : liberty_files) {
|
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)
|
for (std::string liberty_file : genlib_files)
|
||||||
abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str());
|
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
|
|
@ -337,6 +337,11 @@ struct TechmapWorker
|
||||||
if (c->type.begins_with("\\$"))
|
if (c->type.begins_with("\\$"))
|
||||||
c->type = c->type.substr(1);
|
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;
|
vector<IdString> autopurge_ports;
|
||||||
|
|
||||||
for (auto &conn : c->connections())
|
for (auto &conn : c->connections())
|
||||||
|
@ -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("new wire alias to be created and named as above but with the `_TECHMAP_REPLACE_'\n");
|
||||||
log("prefix also substituted.\n");
|
log("prefix also substituted.\n");
|
||||||
log("\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("See 'help extract' for a pass that does the opposite thing.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("See 'help flatten' for a pass that does flatten the design (which is\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"))
|
if (check_label("map_ram"))
|
||||||
{
|
{
|
||||||
std::string args = "";
|
std::string args = "";
|
||||||
|
if (help_mode)
|
||||||
|
args += " [-no-auto-block] [-no-auto-distributed]";
|
||||||
|
else {
|
||||||
if (nobram)
|
if (nobram)
|
||||||
args += " -no-auto-block";
|
args += " -no-auto-block";
|
||||||
if (nolutram)
|
if (nolutram)
|
||||||
args += " -no-auto-distributed";
|
args += " -no-auto-distributed";
|
||||||
if (help_mode)
|
}
|
||||||
args += " [-no-auto-block] [-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("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");
|
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/abc9_unmap.v))
|
||||||
$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.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,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
|
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);
|
module \$macc (A, B, Y);
|
||||||
|
|
||||||
parameter A_WIDTH = 0;
|
parameter A_WIDTH = 0;
|
||||||
parameter B_WIDTH = 0;
|
parameter B_WIDTH = 0;
|
||||||
parameter Y_WIDTH = 0;
|
parameter Y_WIDTH = 0;
|
||||||
|
// CONFIG determines the layout of A, as explained below
|
||||||
parameter CONFIG = 4'b0000;
|
parameter CONFIG = 4'b0000;
|
||||||
parameter CONFIG_WIDTH = 4;
|
parameter CONFIG_WIDTH = 4;
|
||||||
|
|
||||||
input [A_WIDTH-1:0] A;
|
// In the terms used for this cell, there's mixed meanings for the term "port". To disambiguate:
|
||||||
input [B_WIDTH-1:0] B;
|
// A cell port is for example the A input (it is constructed in C++ as cell->setPort(ID::A, ...))
|
||||||
output reg [Y_WIDTH-1:0] Y;
|
// 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..
|
// Xilinx XSIM does not like $clog2() below..
|
||||||
function integer my_clog2;
|
function integer my_clog2;
|
||||||
|
@ -929,10 +945,42 @@ function integer my_clog2;
|
||||||
end
|
end
|
||||||
endfunction
|
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;
|
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);
|
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;
|
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;
|
function [2*num_ports*num_abits-1:0] get_port_offsets;
|
||||||
input [CONFIG_WIDTH-1:0] cfg;
|
input [CONFIG_WIDTH-1:0] cfg;
|
||||||
integer i, cursor;
|
integer i, cursor;
|
||||||
|
|
|
@ -207,7 +207,7 @@ module _90_fa (A, B, C, X, Y);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
(* techmap_celltype = "$lcu" *)
|
(* techmap_celltype = "$lcu" *)
|
||||||
module _90_lcu (P, G, CI, CO);
|
module _90_lcu_brent_kung (P, G, CI, CO);
|
||||||
parameter WIDTH = 2;
|
parameter WIDTH = 2;
|
||||||
|
|
||||||
(* force_downto *)
|
(* force_downto *)
|
||||||
|
|
|
@ -308,12 +308,14 @@ struct SynthEcp5Pass : public ScriptPass
|
||||||
if (check_label("map_ram"))
|
if (check_label("map_ram"))
|
||||||
{
|
{
|
||||||
std::string args = "";
|
std::string args = "";
|
||||||
|
if (help_mode)
|
||||||
|
args += " [-no-auto-block] [-no-auto-distributed]";
|
||||||
|
else {
|
||||||
if (nobram)
|
if (nobram)
|
||||||
args += " -no-auto-block";
|
args += " -no-auto-block";
|
||||||
if (nolutram)
|
if (nolutram)
|
||||||
args += " -no-auto-distributed";
|
args += " -no-auto-distributed";
|
||||||
if (help_mode)
|
}
|
||||||
args += " [-no-auto-block] [-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("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");
|
run("techmap -map +/ecp5/lutrams_map.v -map +/ecp5/brams_map.v");
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,31 @@ module EFX_GBUFCE(
|
||||||
|
|
||||||
endmodule
|
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_WIDTH-1:0] WDATA,
|
||||||
input [WRITE_ADDR_WIDTH-1:0] WADDR,
|
input [WRITE_ADDR_WIDTH-1:0] WADDR,
|
||||||
input WE,
|
input WE,
|
||||||
|
@ -126,8 +150,6 @@ module EFX_RAM_5K(
|
||||||
(* clkbuf_sink *)
|
(* clkbuf_sink *)
|
||||||
input RCLK
|
input RCLK
|
||||||
);
|
);
|
||||||
parameter READ_WIDTH = 20;
|
|
||||||
parameter WRITE_WIDTH = 20;
|
|
||||||
parameter OUTPUT_REG = 1'b0;
|
parameter OUTPUT_REG = 1'b0;
|
||||||
parameter RCLK_POLARITY = 1'b1;
|
parameter RCLK_POLARITY = 1'b1;
|
||||||
parameter RE_POLARITY = 1'b1;
|
parameter RE_POLARITY = 1'b1;
|
||||||
|
@ -155,25 +177,4 @@ module EFX_RAM_5K(
|
||||||
parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
parameter INIT_13 = 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
|
endmodule
|
||||||
|
|
|
@ -161,9 +161,13 @@ struct SynthEfinixPass : public ScriptPass
|
||||||
if (check_label("map_ram"))
|
if (check_label("map_ram"))
|
||||||
{
|
{
|
||||||
std::string args = "";
|
std::string args = "";
|
||||||
|
if (help_mode)
|
||||||
|
args += " [-no-auto-block]";
|
||||||
|
else {
|
||||||
if (nobram)
|
if (nobram)
|
||||||
args += " -no-auto-block";
|
args += " -no-auto-block";
|
||||||
run("memory_libmap -lib +/efinix/brams.txt" + args);
|
}
|
||||||
|
run("memory_libmap -lib +/efinix/brams.txt" + args, "(-no-auto-block if -nobram)");
|
||||||
run("techmap -map +/efinix/brams_map.v");
|
run("techmap -map +/efinix/brams_map.v");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -320,7 +320,7 @@ struct SynthPass : public ScriptPass
|
||||||
run("opt_clean");
|
run("opt_clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_ram")) {
|
if (check_label("map_ram", "(unless -noregfile)")) {
|
||||||
// RegFile extraction
|
// RegFile extraction
|
||||||
if (!noregfile) {
|
if (!noregfile) {
|
||||||
run("memory_libmap -lib +/fabulous/ram_regfile.txt");
|
run("memory_libmap -lib +/fabulous/ram_regfile.txt");
|
||||||
|
@ -342,7 +342,7 @@ struct SynthPass : public ScriptPass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map_iopad", "(if -iopad)")) {
|
if (check_label("map_iopad", "(if -iopad)")) {
|
||||||
if (iopad) {
|
if (iopad || help_mode) {
|
||||||
run("opt -full");
|
run("opt -full");
|
||||||
run("iopadmap -bits -outpad $__FABULOUS_OBUF I:PAD -inpad $__FABULOUS_IBUF O:PAD "
|
run("iopadmap -bits -outpad $__FABULOUS_OBUF I:PAD -inpad $__FABULOUS_IBUF O:PAD "
|
||||||
"-toutpad IO_1_bidirectional_frame_config_pass ~T:I:PAD "
|
"-toutpad IO_1_bidirectional_frame_config_pass ~T:I:PAD "
|
||||||
|
|
|
@ -230,12 +230,14 @@ struct SynthGowinPass : public ScriptPass
|
||||||
if (check_label("map_ram"))
|
if (check_label("map_ram"))
|
||||||
{
|
{
|
||||||
std::string args = "";
|
std::string args = "";
|
||||||
|
if (help_mode)
|
||||||
|
args += " [-no-auto-block] [-no-auto-distributed]";
|
||||||
|
else {
|
||||||
if (nobram)
|
if (nobram)
|
||||||
args += " -no-auto-block";
|
args += " -no-auto-block";
|
||||||
if (nolutram)
|
if (nolutram)
|
||||||
args += " -no-auto-distributed";
|
args += " -no-auto-distributed";
|
||||||
if (help_mode)
|
}
|
||||||
args += " [-no-auto-block] [-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("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");
|
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"))
|
if (check_label("map_ram"))
|
||||||
{
|
{
|
||||||
std::string args = "";
|
std::string args = "";
|
||||||
|
if (help_mode)
|
||||||
|
args += " [-no-auto-huge] [-no-auto-block]";
|
||||||
|
else {
|
||||||
if (!spram)
|
if (!spram)
|
||||||
args += " -no-auto-huge";
|
args += " -no-auto-huge";
|
||||||
if (nobram)
|
if (nobram)
|
||||||
args += " -no-auto-block";
|
args += " -no-auto-block";
|
||||||
if (help_mode)
|
}
|
||||||
args += " [-no-auto-huge] [-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("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("techmap -map +/ice40/brams_map.v -map +/ice40/spram_map.v");
|
||||||
run("ice40_braminit");
|
run("ice40_braminit");
|
||||||
|
|
|
@ -20,10 +20,7 @@ $(eval $(call add_share_file,share/intel_alm/cyclonev,techlibs/intel_alm/cyclone
|
||||||
# RAM
|
# 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.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_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))
|
$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt))
|
||||||
|
|
||||||
# Miscellaneous
|
# 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/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
|
// (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
|
// 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).
|
// D flip-flops (which are covered as MISTRAL_FF in dff_sim.v).
|
||||||
|
@ -77,14 +77,6 @@
|
||||||
// SUMOUT 368 1342 1323 887 927 - 785 -
|
// SUMOUT 368 1342 1323 887 927 - 785 -
|
||||||
// CARRYOUT 71 1082 1062 866 813 - 1198 -
|
// 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 *)
|
(* abc9_lut=2, lib_whitebox *)
|
||||||
module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q);
|
module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q);
|
||||||
|
|
||||||
|
@ -100,26 +92,6 @@ specify
|
||||||
(F => Q) = 97;
|
(F => Q) = 97;
|
||||||
endspecify
|
endspecify
|
||||||
`endif
|
`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};
|
assign Q = LUT >> {F, E, D, C, B, A};
|
||||||
|
|
||||||
|
@ -140,24 +112,6 @@ specify
|
||||||
(E => Q) = 97;
|
(E => Q) = 97;
|
||||||
endspecify
|
endspecify
|
||||||
`endif
|
`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};
|
assign Q = LUT >> {E, D, C, B, A};
|
||||||
|
|
||||||
|
@ -177,22 +131,6 @@ specify
|
||||||
(D => Q) = 97;
|
(D => Q) = 97;
|
||||||
endspecify
|
endspecify
|
||||||
`endif
|
`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};
|
assign Q = LUT >> {D, C, B, A};
|
||||||
|
|
||||||
|
@ -211,20 +149,6 @@ specify
|
||||||
(C => Q) = 97;
|
(C => Q) = 97;
|
||||||
endspecify
|
endspecify
|
||||||
`endif
|
`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};
|
assign Q = LUT >> {C, B, A};
|
||||||
|
|
||||||
|
@ -242,18 +166,6 @@ specify
|
||||||
(B => Q) = 97;
|
(B => Q) = 97;
|
||||||
endspecify
|
endspecify
|
||||||
`endif
|
`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};
|
assign Q = LUT >> {B, A};
|
||||||
|
|
||||||
|
@ -268,16 +180,6 @@ specify
|
||||||
(A => Q) = 97;
|
(A => Q) = 97;
|
||||||
endspecify
|
endspecify
|
||||||
`endif
|
`endif
|
||||||
`ifdef arriav
|
|
||||||
specify
|
|
||||||
(A => Q) = 76;
|
|
||||||
endspecify
|
|
||||||
`endif
|
|
||||||
`ifdef cyclone10gx
|
|
||||||
specify
|
|
||||||
(A => Q) = 53;
|
|
||||||
endspecify
|
|
||||||
`endif
|
|
||||||
|
|
||||||
assign Q = ~A;
|
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)
|
(CI => CO) = 36; // Divided by 2 to account for there being two ALUT_ARITHs in an ALM)
|
||||||
endspecify
|
endspecify
|
||||||
`endif
|
`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;
|
wire q0, q1;
|
||||||
|
|
||||||
|
@ -349,283 +217,3 @@ assign q1 = LUT1 >> {D1, C, B, A};
|
||||||
assign {CO, SO} = q0 + !q1 + CI;
|
assign {CO, SO} = q0 + !q1 + CI;
|
||||||
|
|
||||||
endmodule
|
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